android應(yīng)用程序管理主要由PackageManager這個類來管理,,實現(xiàn)PackageManager這個抽象類的是ContextImpl.java,。在ContextImpl.java中,有一個內(nèi)部靜態(tài)類叫ApplicationPackageManager,,實現(xiàn)了所有PackageManager的接口,。
1 | static final class ApplicationPackageManager extends PackageManager { |
ApplicationPackageManager又是通過對IPackageManager封裝調(diào)用,來實現(xiàn)的,。
01 | public PackageInfo getPackageInfo(String packageName, int flags) |
02 | throws NameNotFoundException { |
04 | PackageInfo pi = mPM.getPackageInfo(packageName, flags); |
08 | } catch (RemoteException e) { |
09 | throw new RuntimeException( "Package manager has died" , e); |
12 | throw new NameNotFoundException(packageName); |
這里的mPM就是IPackageManager,,PackageManagerService就是對IPackageManager的實現(xiàn)。所以我們平時對PackageManager的調(diào)用,,最終是的在PackageManagerService.java中實現(xiàn)的,。在PackageManagerService.java每個方法的實現(xiàn)。
PackageManagerService啟動流程:
PackageManagerService(context, factoryTest)是包管理服務(wù)的主進(jìn)程,。它完成了對/system/app,/data/app,/system/framework,/data/app-private下的apk文件的解析,。詳細(xì)流程如下:
1.建立java層的installer與c層的installd的socket聯(lián)接,使得在上層的install,remove,dexopt等功能最終由installd在底層實現(xiàn)
2.建立PackageHandler消息循環(huán),,用于處理外部的apk安裝請求消息,,如adb install,packageinstaller安裝apk時會發(fā)送消息
3.解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系統(tǒng)支持的各種硬件模塊的feature.主要工作:
(1)建立底層user ids和group ids 同上層permissions之間的映射,;可以指定一個權(quán)限與幾個組ID對應(yīng),。當(dāng)一個APK被授予這個權(quán)限時,它也同時屬于這幾個組,。
(2)給一些底層用戶分配權(quán)限,,如給shell授予各種permission權(quán)限;把一個權(quán)限賦予一個UID,,當(dāng)進(jìn)程使用這個UID運(yùn)行時,,就具備了這個權(quán)限。
(3) library,系統(tǒng)增加的一些應(yīng)用需要link的擴(kuò)展jar庫,;
(4) feature,系統(tǒng)每增加一個硬件,,都要添加相應(yīng)的feature.將解析結(jié)果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等幾個集合中供系統(tǒng)查詢和權(quán)限配置使用。
4.檢查/data/system/packages.xml是否存在,,這個文件是在解析apk時由
writeLP()創(chuàng)建的,,里面記錄了系統(tǒng)的permissions,,以及每個apk的name,codePath,flags,version,uesrid等信息,這些信息主要通過apk的
AndroidManifest.xml解析獲取,,解析完apk后將更新信息寫入這個文件并保
存到flash,,下次開機(jī)直接從里面讀取相關(guān)信息添加到內(nèi)存相關(guān)列表中。當(dāng)有apk
升級,,安裝或刪除時會更新這個文件,。
5.檢查BootClassPath,mSharedLibraries及/system/framework下的jar
是否需要dexopt,,需要的則通過dexopt進(jìn)行優(yōu)化
6.啟動AppDirObserver線程監(jiān)測/system/framework,/system/app,/data/app,/data/
app-private目錄的事件,主要監(jiān)聽add和remove事件,。對于目錄監(jiān)聽底層通過
inotify機(jī)制實現(xiàn),inotify 是一種文件系統(tǒng)的變化通知機(jī)制,,如文件增加,、刪除
等事件可以立刻讓用戶態(tài)得知,它為用戶態(tài)監(jiān)視文件系統(tǒng)的變化提供了強(qiáng)大的支持。
當(dāng)有add event時調(diào)用scanPackageLI(File , int , int)處理,;
當(dāng)有remove event時調(diào)用removePackageLI()處理;
7.對于以上幾個目錄下的apk逐個解析,,主要是解析每個apk的AndroidMa-
nifest.xml文件,處理asset/res等資源文件,,建立起每個apk的配置結(jié)構(gòu)信息,,
并將每個apk的配置信息添加到全局列表進(jìn)行管理。f
8.將解析的每個apk的信息保存到packages.xml和packages.list文件里,,
packages.list記錄了如下數(shù)據(jù):pkgName,,userId,debugFlag,,dataPath(包的數(shù)據(jù)路徑)
dexopt:
如果我們想要求運(yùn)行時的性能有進(jìn)一步提高,,就仍然需要對DEX文件進(jìn)行進(jìn)一步優(yōu)化。優(yōu)化DEX會產(chǎn)生一個可以快速載入執(zhí)行的classes.dex文件,,會進(jìn)行包括byte-swapping,structure realigning與basic structure checks,更新ODEX header ,為了確保產(chǎn)生ODEX流程的正確性,Android提供了一個dexopt工具,用來做為虛擬機(jī)的輔助工具,可以在系統(tǒng)啟動時,透過Dalvik虛擬機(jī)對載入的DEX文件執(zhí)行佳化操作,。
優(yōu)化發(fā)生的時機(jī)有兩個:
對于預(yù)置應(yīng)用,可以在系統(tǒng)編譯后,,生成優(yōu)化文件,,以O(shè)DEX 結(jié)尾。這樣在發(fā)布時除
APK 文件(不包含 DEX)以外,,還有一個相應(yīng)的 ODEX 文件,;
對于非預(yù)置應(yīng)用,,包含在 APK 文件里的 DEX 文件會在運(yùn)行時通過dexopt進(jìn)行優(yōu)化,,優(yōu)化后的文件將被保存在緩存中(data/dalvik-cache)。
android安全機(jī)制概述:
Android是一個權(quán)限分離的系統(tǒng) ,,這是利用Linux已有的權(quán)限管理機(jī)制,,通過為每一個Application分配不同的uid和gid, 從而使得不同的Application之間的私有數(shù)據(jù)和訪問(native以及java層通過這種sandbox機(jī)制)達(dá)到隔離的目的 ,。與此同時,Android還在此基礎(chǔ)上進(jìn)行擴(kuò)展,提供了permission機(jī)制,,它主要是用來對Application可以執(zhí)行的某些具體操作進(jìn)行權(quán)限細(xì)分和訪問控制,,同時提供了per-URI permission機(jī)制,用來提供對某些特定的數(shù)據(jù)塊進(jìn)行訪問,。
Application 級別通過user ID和group Id實現(xiàn)安全控制,;component級別通過permission來限制對于某一組件的訪問;在data級別通過基于permission的per URI進(jìn)行安全控制,。
uid gid gids:
Android 的權(quán)限分離的基礎(chǔ)是建立在 Linux 已有的 uid ,、 gid 、 gids 基礎(chǔ)上的 ,。
UID :Android 在 安裝一個應(yīng)用程序,,就會為 它 分配一個 uid 。其中普通 Android 應(yīng)用程序的 uid 是從 10000 開始分配 (Process.FIRST_APPLICATION_UID ),, 10000 以下是系統(tǒng)進(jìn)程的 uid ,。
GID :對 于普通應(yīng)用程序來說, gid 等于 uid ,。由于每個應(yīng)用程序的 uid 和 gid 都不相同,, 因此不管是 native 層還是 java 層都能夠達(dá)到保護(hù)私有數(shù)據(jù)的作用 。
GIDS : gids 是由框架在 Application 安裝過程中生成,,與 Application 申請的具體權(quán)限相關(guān),。 如果 Application 申請的相應(yīng)的 permission 被 granted ,而且中有對應(yīng)的 gids ,, 那么這個Application 的 gids 中將包含這個gids ,。
installer類:
構(gòu)造方法中,首先會進(jìn)行一些成員變量的初始化,,比如mContext,, mFactoryTest, mMetrics,, mSettings等,。
最重要的是初始化mInstaller這個變量:
1 | Installer installer = new Installer(); |
2 | if (installer.ping() && Process.supportsProcesses()) { |
3 | mInstaller = installer; |
Installer這個是PackageManager與底層C模塊進(jìn)行通信的工具類,同socket進(jìn)行通信,,PackageManager所有對apk的安裝,,卸載等操作都是通過Installer進(jìn)行的。對Installer的調(diào)用首先會調(diào)用ping()來判斷socket是否已經(jīng)連接,。
連接方法:connect:
01 | private boolean connect() { |
02 | if (mSocket != null ) { |
05 | Slog.i(TAG, "connecting..." ); |
07 | mSocket = new LocalSocket(); |
09 | LocalSocketAddress address = new LocalSocketAddress( |
10 | "installd" , LocalSocketAddress.Namespace.RESERVED); |
12 | mSocket.connect(address); |
14 | mIn = mSocket.getInputStream(); |
15 | mOut = mSocket.getOutputStream(); |
16 | } catch (IOException ex) { |
transaction首先會判斷連接,,如果socket連接正常,就將cmd命令寫入socket文件,并且接收返回信息,,并且返回給execute:
01 | private synchronized String transaction(String cmd) { |
03 | Slog.e(TAG, "connection failed" ); |
07 | if (!writeCommand(cmd)) { |
13 | Slog.e(TAG, "write command failed? reconnect!" ); |
14 | if (!connect() || !writeCommand(cmd)) { |
20 | String s = new String(buf, 0 , buflen); |
執(zhí)行命令的方法:execute(String cmd):
1 | private int execute(String cmd) { |
2 | String res = transaction(cmd); |
4 | return Integer.parseInt(res); |
5 | } catch (NumberFormatException ex) { |
install()方法:
01 | public int install(String name, int uid, int gid) { |
02 | StringBuilder builder = new StringBuilder( "install" ); |
09 | return execute(builder.toString()); |
其他方法:
(1) dexopt(String apkPath, int uid, boolean isPublic),;優(yōu)化dex文件
(2)movedex(String srcPath, String dstPath); 移動dex文件
(3)rmdex(String codePath),;刪除dex文件
(4)remove(String name),;移動apk
(5)rename(String oldname, String newname);重命名
(6)deleteCacheFiles(String name),;刪除cache文件
(7)clearUserData(String name),;刪除user data
(8)freeCache(long freeStorageSize);釋放cache空間
(9)setForwardLockPerm(String packagePathSuffix, int gid) 為apk文件增加前綴
(10)getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, PackageStats pStats) 獲取apk信息
(11) moveFiles(),;移動文件,。