APK安裝流程系列文章整體內(nèi)容如下:
- APK安裝流程詳解0——前言
- APK安裝流程詳解1——有關(guān)"安裝ing"的實(shí)體類(lèi)概述
- APK安裝流程詳解2——PackageManager簡(jiǎn)介
- APK安裝流程詳解3——PackageManager與PackageManagerService
- APK安裝流程詳解4——安裝中關(guān)于so庫(kù)的哪些事
- APK安裝流程詳解5——PackageInstallerService和Installer
- APK安裝流程詳解6——PackageManagerService啟動(dòng)前奏
- APK安裝流程詳解7——PackageManagerService的啟動(dòng)流程(上)
- APK安裝流程詳解8——PackageManagerService的啟動(dòng)流程(下)
- APK安裝流程詳解9——PackageParser解析APK(上)
- APK安裝流程詳解10——PackageParser解析APK(下)
- APK安裝流程詳解11——普通應(yīng)用安裝簡(jiǎn)介
- APK安裝流程詳解12——PackageManagerService中的新安裝流程上(拷貝)
- APK安裝流程詳解13——PackageManagerService中的新安裝流程下(裝載)
- APK安裝流程詳解14——PMS中的新安裝流程上(拷貝)補(bǔ)充
- APK安裝流程詳解15——PMS中的新安裝流程下(裝載)補(bǔ)充
- APK安裝流程詳解16——Android包管理總結(jié)
- 1、設(shè)計(jì)思想
- 2、PackageManagerService的抽象理解
- 3、PackageManagerService里面的數(shù)據(jù)結(jié)構(gòu)
- 4、PackageManagerService的三大流程
- 5、PackageManagerService的體系結(jié)構(gòu)
一、設(shè)計(jì)思想
如果你是Android 系統(tǒng)中的架構(gòu)師,讓你設(shè)計(jì)一個(gè)Android的安裝系統(tǒng)中的PackageManagerService,你會(huì)怎么設(shè)計(jì)? 既然要設(shè)計(jì),咱們要首先弄清幾個(gè)問(wèn)題,我希望大家看下面的問(wèn)題的時(shí)候,多想兩個(gè)問(wèn)題:1、如果讓你設(shè)計(jì),你怎么設(shè)計(jì)。這個(gè)"類(lèi)"存在意義是什么?
- 1、為什么關(guān)機(jī)的時(shí)候手機(jī)是磚頭,而開(kāi)機(jī)后,所有APP都可以運(yùn)行了,這是為什么?
- 2、Android系統(tǒng)是通過(guò)什么手段來(lái)加載已經(jīng)安裝到手機(jī)上應(yīng)用的?
- 3、既然是加載,按照科學(xué)的架構(gòu)設(shè)計(jì),是不是應(yīng)該存在一個(gè)管理者,來(lái)全局管理,那個(gè)這個(gè)類(lèi)是什么?
- 4、在安裝一個(gè)APK的時(shí)候,APK是"死的",Android系統(tǒng)是怎么把它變成一個(gè)"活的"APP,他是怎么加載到內(nèi)存中去的
那我們就來(lái)依次來(lái)看下這幾個(gè)問(wèn)題
1、為什么關(guān)機(jī)的時(shí)候手機(jī)是磚頭,而開(kāi)機(jī)后,所有APP都可以運(yùn)行了,它是怎么加載的?
- 首先明確一點(diǎn),手機(jī)關(guān)機(jī)以后,就是一個(gè)冰冷的磚頭,只能用來(lái)"砸核桃",那開(kāi)機(jī)后,你點(diǎn)擊桌面上的任何一個(gè)圖片,都能開(kāi)啟一個(gè)APP,這說(shuō)明在開(kāi)機(jī)過(guò)程中,系統(tǒng)把已經(jīng)安裝好的APP加載到內(nèi)存中,這到底是怎么做的?所以我們反推斷,在安卓系統(tǒng)中肯定存在這么一塊區(qū)域,用于存放已經(jīng)安裝的APP的信息,在開(kāi)機(jī)的時(shí)候,通過(guò)系統(tǒng)掃描,這塊區(qū)域,把對(duì)應(yīng)的內(nèi)容加載到內(nèi)存中去。
- 其次,通過(guò)上面的分析,我們知道了在Android系統(tǒng)中存在這樣一塊區(qū)域,在開(kāi)機(jī)的的時(shí)候,加載這塊區(qū)域的信息,從而實(shí)現(xiàn)加載在內(nèi)存中去。那么我們繼續(xù)反推斷,那這塊區(qū)域的信息,是怎么來(lái)的?應(yīng)該在安裝這個(gè)APK的時(shí)候,把這個(gè)APK的信息寫(xiě)入到該區(qū)域的。這樣就可以實(shí)現(xiàn)了在安卓系統(tǒng)一次安裝后,在刪除APK文件后,還可以運(yùn)行APP了
其實(shí)上面的解答是基本上所有操作的系統(tǒng)的安裝思路,大家可以想一下在Windows下是不是也是如此。
上面說(shuō)的Android區(qū)域其實(shí)就是:“/data目錄”下的system目錄,這個(gè)目錄用來(lái)保存很多系統(tǒng)文件。主要工作是創(chuàng)建了5個(gè)位于目錄/data/system的File對(duì)象,分別是:
- packages.xml:記錄了系統(tǒng)中所有安裝的應(yīng)用信息,包括基本信息、簽名和權(quán)限
- pakcages-back.xml:packages.xml文件
- pakcages-stoped.xml:記錄系統(tǒng)中被強(qiáng)制停止的運(yùn)行的應(yīng)用信息。系統(tǒng)在強(qiáng)制停止某個(gè)應(yīng)用的時(shí)候,會(huì)將應(yīng)用的信息記錄在該文件中。
- pakcages-stoped-backup.xml:pakcages-stoped.xml文件的備份
- 保存普通應(yīng)用的數(shù)據(jù)目錄和uid等信息
這個(gè)5個(gè)文件中pakcages-back.xml和pakcages-stoped-backup.xml是備份文件。當(dāng)Android對(duì)文件packages.xml和pakcages-stoped.xml寫(xiě)之前,會(huì)先把它們備份,如果寫(xiě)文件成功了,再把備份文件刪除。如果寫(xiě)的時(shí)候,系統(tǒng)出問(wèn)題了,重啟后在需要讀取這兩個(gè)文件時(shí),如果發(fā)現(xiàn)備份文件存在,會(huì)使用備份文件的內(nèi)容,因?yàn)樵次募赡芤呀?jīng)損壞了。其中packages.xml是PackageManagerServcie啟動(dòng)時(shí),需要用到的文件。
我把我的Nexus 6P手機(jī)Root后,在/data/system 截屏如下:

我把packages.xml導(dǎo)出來(lái),文件內(nèi)容太大,我就直接截屏了,內(nèi)容如下:


圖片看不清,可以看下面的縮減版
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<packages>
<version sdkVersion="23" databaseVersion="3" fingerprint="google/angler/angler:6.0.1/MTC20L/3230295:user/release-keys" />
<version volumeUuid="primary_physical" sdkVersion="23" databaseVersion="23" fingerprint="google/angler/angler:6.0.1/MTC19T/2741993:user/release-keys" />
<permission-trees>
<item name="com.google.android.googleapps.permission.GOOGLE_AUTH" package="com.google.android.gsf" />
</permission-trees>
<permissions>
<item name="android.permission.REAL_GET_TASKS" package="android" protection="18" />
<item name="android.permission.REMOTE_AUDIO_PLAYBACK" package="android" protection="2" />
.....
<item name="com.android.voicemail.permission.ADD_VOICEMAIL" package="android" protection="1" />
</permissions>
<package name="com.google.android.youtube" codePath="/system/app/YouTube" nativeLibraryPath="/system/app/YouTube/lib" primaryCpuAbi="arm64-v8a" publicFlags="945307205" privateFlags="0" ft="11e9134c000" it="11e9134c000" ut="11e9134c000" version="107560144" userId="10075">
<sigs count="1">
<cert index="0" key="30820252308201bb02044934987e300d06092a864886f70d01010405003070310b3009060355040613025553310b3009060355040813024341311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c652c20496e6331143012060355040b130b476f6f676c652c20496e633110300e06035504031307556e6b6e6f776e301e170d3038313230323032303735385a170d3336303431393032303735385a3070310b3009060355040613025553310b3009060355040813024341311630140603550407130d4d6f756e7461696e205669657731143012060355040a130b476f6f676c652c20496e6331143012060355040b130b476f6f676c652c20496e633110300e06035504031307556e6b6e6f776e30819f300d06092a864886f70d010101050003818d00308189028181009f48031990f9b14726384e0453d18f8c0bbf8dc77b2504a4b1207c4c6c44babc00adc6610fa6b6ab2da80e33f2eef16b26a3f6b85b9afaca909ffbbeb3f4c94f7e8122a798e0eba75ced3dd229fa7365f41516415aa9c1617dd583ce19bae8a0bbd885fc17a9b4bd2640805121aadb9377deb40013381418882ec52282fc580d0203010001300d06092a864886f70d0101040500038181004086669ed631da4384ddd061d226e073b98cc4b99df8b5e4be9e3cbe97501e83df1c6fa959c0ce605c4fd2ac6d1c84cede20476cbab19be8f2203aff7717ad652d8fcc890708d1216da84457592649e0e9d3c4bb4cf58da19db1d4fc41bcb9584f64e65f410d0529fd5b68838c141d0a9bd1db1191cb2a0df790ea0cb12db3a4" />
</sigs>
<perms>
<item name="com.google.android.c2dm.permission.RECEIVE" granted="true" flags="0" />
<item name="android.permission.USE_CREDENTIALS" granted="true" flags="0" />
<item name="com.google.android.providers.gsf.permission.READ_GSERVICES" granted="true" flags="0" />
<item name="com.google.android.youtube.permission.C2D_MESSAGE" granted="true" flags="0" />
<item name="android.permission.MANAGE_ACCOUNTS" granted="true" flags="0" />
<item name="android.permission.NFC" granted="true" flags="0" />
<item name="android.permission.CHANGE_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.RECEIVE_BOOT_COMPLETED" granted="true" flags="0" />
<item name="com.google.android.gms.permission.AD_ID_NOTIFICATION" granted="true" flags="0" />
<item name="android.permission.INTERNET" granted="true" flags="0" />
<item name="android.permission.ACCESS_NETWORK_STATE" granted="true" flags="0" />
<item name="android.permission.VIBRATE" granted="true" flags="0" />
<item name="android.permission.ACCESS_WIFI_STATE" granted="true" flags="0" />
<item name="android.permission.WAKE_LOCK" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="11" />
<domain-verification packageName="com.google.android.youtube" status="0">
<domain name="youtu.be" />
<domain name="m.youtube.com" />
<domain name="youtube.com" />
<domain name="www.youtube.com" />
</domain-verification>
</package>
上面是我手機(jī)packages.xml的一個(gè)片段。我們看下里面的"youtube"應(yīng)用。通過(guò)標(biāo)簽<package>記錄了一個(gè)應(yīng)用的基本信息,簽名和聲明的權(quán)限。
(1)<package>表示包信息,下面我們就來(lái)解釋下標(biāo)簽<package>中的屬性
- name表示應(yīng)用的包名
- codePath表示的是apk文件的路徑
- nativeLibraryPath表示應(yīng)用的native庫(kù)的存儲(chǔ)路徑
- flags是指應(yīng)用的屬性,如FLAG_SYSTEM、FLAG_PERSISTENT等
- it表示應(yīng)用安裝的時(shí)間
- ut表示應(yīng)用最后一次修改的時(shí)間
- version表示應(yīng)用的版本號(hào)
- userId表示所屬于的id
(2)<sign>表示應(yīng)用的簽名,下面我們就來(lái)解釋下 標(biāo)簽<sign>中的屬性
- count表示標(biāo)簽中包含有多少個(gè)證書(shū)
- cert表示具體的證書(shū)的值
(3)<perms>表示應(yīng)用聲明使用的權(quán)限,每一個(gè)子標(biāo)簽代表一項(xiàng)權(quán)限
通過(guò)上面的內(nèi)容,我們知道Android系統(tǒng)通過(guò)packages.xml文件來(lái)存儲(chǔ)應(yīng)用信息的,所以我們舉一反三,新安裝的APK,肯定是把新安裝的APK相關(guān)信息寫(xiě)入這個(gè)packages.xml文件中,那么怎么把這個(gè)xml文件,映射到內(nèi)存中的? 那我們就來(lái)看第二個(gè)問(wèn)題
2、Android系統(tǒng)是通過(guò)什么手段來(lái)加載已經(jīng)安裝到手機(jī)上應(yīng)用的
上面提到了,應(yīng)用的信息都存儲(chǔ)在packages.xml中的<package>標(biāo)簽里面,那我們是怎么加載到內(nèi)存中去的?大家平時(shí)是存儲(chǔ)數(shù)據(jù)庫(kù)的時(shí)候都是怎么做的?對(duì)的,一般都是一個(gè)實(shí)體類(lèi)對(duì)應(yīng)數(shù)據(jù)庫(kù)中的一個(gè)表;其中每一個(gè)對(duì)象對(duì)應(yīng)的是數(shù)據(jù)庫(kù)中的一條數(shù)據(jù)。同理,Android系統(tǒng)也是這樣設(shè)計(jì)的,<package>標(biāo)簽里面記錄的包信息其實(shí)是一一對(duì)應(yīng)的PackageSetting類(lèi)。

PackageSetting繼承了PackageSettingBase類(lèi),PackageSettingBase類(lèi)繼承自GrantedPremisson類(lèi)。應(yīng)用的基本信息保存在PackageSettingBase類(lèi)的成員變量中,聲明的權(quán)限保存在GrantedPremissions類(lèi),簽名則保存在SharedUserSetting類(lèi)的成員變量signatures中。標(biāo)簽<package>所標(biāo)識(shí)的應(yīng)用PackageSetting對(duì)象都保存在Setting的mPackages中,定義如下:
// com.android.server.pm.Settings.java
final HashMap<String, PackageSetting> mPackages =
new HashMap<String, PackageSetting>();
在packages.xml中除了標(biāo)簽<package>,還有<updated-package>、<cleaning-package>和<renamed-package> 這三種標(biāo)簽。
- <updated-package> 標(biāo)簽表示升級(jí)包覆蓋的系統(tǒng)應(yīng)用,對(duì)應(yīng)的是PackageSetting,在Settings里面同樣用mPackages 變量表示
- <cleaning-package> 標(biāo)簽用來(lái)記錄那些已經(jīng)刪除,但是數(shù)據(jù)目錄還暫時(shí)保留的應(yīng)用的信息。對(duì)應(yīng)的是PackageCleanItem。在Settings里面用mPackagesToBeCleaned變量表示
- <renamed-package> 標(biāo)簽用來(lái)記錄系統(tǒng)中改名的應(yīng)用。它的記錄信息都插入到mSettings的mRenamedPackages對(duì)象中。
其中mPackagesToBeCleaned和mRenamedPackages在mSettings.java的定義如下:
// com.android.server.pm.Settings.java
// Packages that have been uninstalled and still need their external
// storage data deleted.
final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
// Packages that have been renamed since they were first installed.
// Keys are the new names of the packages, values are the original
// names. The packages appear everwhere else under their original
// names.
final HashMap<String, String> mRenamedPackages = new HashMap<String, String>();
上面用大量的文筆說(shuō)Settings,那么它是什么東西?下面就讓我繼續(xù)來(lái)看下一個(gè)問(wèn)題
3、既然是加載,按照科學(xué)的架構(gòu)設(shè)計(jì),是不是應(yīng)該存在一個(gè)管理者,來(lái)全局管理,那個(gè)這個(gè)類(lèi)是什么?
這個(gè)類(lèi)就是Settings
Settings是Android的包的全局管理者,用于協(xié)助PackageManagerService保存所有的安裝包信息,同時(shí)用于存儲(chǔ)系統(tǒng)執(zhí)行過(guò)程中的一些設(shè)置,PackageManagerService和Settings之間的類(lèi)圖關(guān)系如下:

大圖地址1
Settings里面有3個(gè)重要的成員變量:mShareUsers,mPackages,mSharedUsers 。如下:
final ArrayMap<String, SharedUserSetting> mSharedUsers =
new ArrayMap<String, SharedUserSetting>();
final ArrayMap<String, PackageSetting> mPackages =
new ArrayMap<String, PackageSetting>();
final ArraySet<String, SharedUserSetting> mSharedUsers =
new ArraySet<String, SharedUserSetting>();
- mShareUsers是一個(gè)以String類(lèi)型的name為"key",ShareUserSetting對(duì)象為"value"的ArrayMap。
- mPackages是一個(gè)以String類(lèi)型的name為"key",PackageSetting對(duì)象為"value"的ArrayMap。
- mSharedUsers 是一個(gè)以String類(lèi)型的name(比如"android.uid.system")為"key",以SharedUserSetting 對(duì)象為"value"的HashMap
其中ShareUserSetting類(lèi)繼承自GrantedPermissions ,內(nèi)部包含一個(gè)ArraySet類(lèi)型的packages ,這個(gè)packages保存了聲明相同的shareUserId的Package的權(quán)限設(shè)置信息(PackageSetting )通過(guò)上面的問(wèn)題,我們知道PackageSetting繼承自PackageSettingBase,同時(shí)PackageSetting中保存著package的多種信息。
如下圖:

上面提到了一個(gè)概念是SharedUserSetting,那么ShareUserSetting的作用什么是什么?那我們就來(lái)看下:
SharedUserSetting用來(lái)描述具有相同的sharedUserId的應(yīng)用信息,它的成員變量packages保存了所有具有相同sharedUserId的應(yīng)用信息引用。這些應(yīng)用的簽名時(shí)相同的,所有只需要在成員變量signatures中保存一份。通過(guò)這個(gè)對(duì)象,Android運(yùn)行時(shí)很容易檢索到某個(gè)應(yīng)用擁有相同的sharedUserId的其他應(yīng)用。其中應(yīng)用的簽名保存在ShardUserSetting類(lèi)的成員變量signatures中。
我們?cè)诳聪到y(tǒng)應(yīng)用的AndroidManifest.xml中會(huì)發(fā)現(xiàn)
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="com.android.settings" coreApp="true"
android:sharedUserId="android.uid.system"
android:versionCode="1"
android:versionName="1.0" >
</manifest>
shareUserId與UID相關(guān),作用是:
- 1、兩個(gè)或多個(gè)APK或者進(jìn)程聲明了同一種sharedUserId的APK可以共享批次的數(shù)據(jù),并且可以在運(yùn)行在同一進(jìn)程中(相當(dāng)于進(jìn)程是系統(tǒng)的用戶,某些進(jìn)程可以歸為同一用戶使用,相當(dāng)于Linux系統(tǒng)中的GroupId)
- 2、通過(guò)聲明特定的sharedUserId,該APK所在的進(jìn)程將被賦予指定的
2.通過(guò)聲明特定的sharedUserId,該APK所在的進(jìn)程將被賦予指定的UID,將被賦予該UID特定的權(quán)限。
在Settings中和用戶有關(guān)的還有兩個(gè)重要變量,即mUserIds 和mOtherUserIds
private final ArrayList<Object> mUserIds = new ArrayList<Object>();
private final SparseArray<Object> mOtherUserIds =
new SparseArray<Object>();
他們都是以UID為索引,得到對(duì)應(yīng)的ShardUserSetting對(duì)象。更多的關(guān)于Android系統(tǒng)中關(guān)于"用戶"的信息,在后面"用戶模塊"再單獨(dú)講解
4、在安裝一個(gè)APK的時(shí)候,APK是"死的",Android系統(tǒng)是怎么把它變成一個(gè)"活的"APP,他是怎么加載到內(nèi)存中去的
這里就不得不提一下PackageParser這個(gè)類(lèi),這個(gè)類(lèi)負(fù)責(zé)在APK文件安裝的時(shí)候,解析AndroidManifest。
在Android中,Settings提供可持續(xù)化的包信息管理,PackageSetting是一個(gè)存儲(chǔ)單元,表示一個(gè)pkg信息。我們?cè)诮馕鯝PK安裝包的時(shí)候,會(huì)用到PackageParser,在PackageParser里面有一個(gè)字段是PackageParse.Package。這個(gè)PackageParse.Package其實(shí)是對(duì)應(yīng)的上面packages.xml里面的<package>標(biāo)簽。同時(shí)PackageParse.Package也可以理解為pkg信息在內(nèi)存中的一個(gè)實(shí)時(shí)信息,關(guān)機(jī)后變消失,重啟后重新生成,所以PackageParse.Package中的信息一致保證最新。PackageParse.Packag、Settings和PackageSetting三者的關(guān)系如下:

Settings中保存了一個(gè)包名和PackagesSetting的映射表,PackageParse.Package中的mExtras引用指向了對(duì)應(yīng)的PackageSetting實(shí)例,而PackageParse中保存了一個(gè)PackageParse.Package列表

從上到下,介紹如下:
1:PackageParser.Package對(duì)應(yīng)一個(gè)apk完整的原始數(shù)據(jù)
2:PackageSetting包含一個(gè)PackageParser對(duì)象實(shí)例,說(shuō)明它也對(duì)應(yīng)一個(gè)apk包的數(shù)據(jù),不同的是,它還包括apk相關(guān)配置數(shù)據(jù),比如apk內(nèi)部哪些component是被disable等。
3:Settings包含了PackageSetting對(duì)象列表,也就是說(shuō)它包含了系統(tǒng)所有apk數(shù)據(jù),還有就是PackageParser,顧名思義,負(fù)責(zé)APK數(shù)據(jù)解析
4:PackageManagerService是全局的包管理器
5、補(bǔ)充一點(diǎn):
Settings里面的主要關(guān)聯(lián)關(guān)系如下圖:

二、PackageManagerService的抽象理解
上面說(shuō)了很多,我們?cè)偕仙粋€(gè)高度,PackageManagerService到底應(yīng)該怎么去理解它?
每一個(gè)組織結(jié)構(gòu),都有一套自己的管理機(jī)制,比如任何一家公司,都會(huì)存在下面三個(gè)元素:管理者(經(jīng)理)、被管理者(員工)、管理機(jī)制(公司的規(guī)章制度及KPI考核等)。同理在Android的系統(tǒng)的世界里面,也有一家公司叫"包管理"。如果要研究Android的包管理機(jī)制,同樣可以從以下幾個(gè)角度來(lái)思考?
- 管理者是誰(shuí),他的職責(zé)是什么?
- 被管理者是誰(shuí),他的職責(zé)是什么?
- 管理機(jī)制是什么,它是如何運(yùn)轉(zhuǎn)的?
所謂包,其實(shí)就是一種文件的格式,比如APK包,JAR包等,在Android中存活著很多包,所有的應(yīng)用程序都是APK包,很多構(gòu)成Android運(yùn)行環(huán)境的都是JAR包,還有一些以so為后綴的庫(kù)文件,包管理者很重要的一個(gè)職責(zé)就是識(shí)別不同的包,統(tǒng)一維護(hù)這些包的信息。當(dāng)有一個(gè)包進(jìn)入(安裝)或者離開(kāi)(卸載)Android世界,都需要向包管理者申報(bào),其他管理部分要獲取包的具體信息,也都需要向包管理者申請(qǐng)。
如同一家公司是由人與人協(xié)作工作的,不同包之間也需要進(jìn)行協(xié)作。既然有協(xié)作,自然就有協(xié)作的規(guī)范,一個(gè)包可以干什么,不可以干什么,都需要有一個(gè)明確的范圍界定,這就是包管理中的權(quán)限設(shè)計(jì)。涉及到的內(nèi)容非常廣泛,Android的權(quán)限管理、SELinux,都是包管理中權(quán)限設(shè)計(jì)的組成部分。同理Android的世界就像一個(gè)井然有序的一家公司,既有包管理部門(mén),也有其他各種管理部門(mén),比如電源管理部門(mén),窗口管理部門(mén)等等。大家不僅各司其職,而且也有來(lái)往。比如在APK安裝到Activity的顯示,看著很簡(jiǎn)單的過(guò)程,其實(shí)卻需要大量的管理部門(mén)參與進(jìn)來(lái),不斷地進(jìn)行數(shù)據(jù)解析、封裝、傳遞、呈現(xiàn),其內(nèi)部機(jī)制十分復(fù)雜。
現(xiàn)在大家想一下上面三個(gè)問(wèn)題的答案,我詳細(xì)大部分人的前兩個(gè)答案是一致的,管理者是PackageManagerService,被管理是各種"包",最后一個(gè)答案是各有千秋,這里是沒(méi)有標(biāo)準(zhǔn)答案的,希望大家能自己找到自己的答案。
三、PackageManagerService里面的數(shù)據(jù)結(jié)構(gòu)
PackageManagerService涉及的數(shù)據(jù)結(jié)構(gòu)非常多,在分析源碼時(shí),很容易陷入各種數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系,難以自拔,以至于看不到包管理的全貌。我在這里簡(jiǎn)單的總結(jié)了一下各個(gè)數(shù)據(jù)結(jié)構(gòu)的職能如下:
- PackageManangerService :包管理的核心服務(wù)
- com.android.server.pm.Settings :所有包的管理信息
- com.android.server.pm.PackageSetting :?jiǎn)我话男畔?/li>
- com.android.server.pm.BasePermission :系統(tǒng)中已有的權(quán)限
- com.android.server.pm.PermissionState :授權(quán)狀態(tài)
—————————————分隔符—————————————
- PackageParser:包解析器
- PackageParser.Package :解析得到的包信息
- PackageParser.Component :組件的基類(lèi),其子類(lèi)對(duì)應(yīng)到AndroidManifest.xml中定義的不同組件
- PackageParser.Activity 對(duì)應(yīng)AndroidManifest.xml中定義<Activity>和<Receiver>標(biāo)簽
- PackageParser.Service :對(duì)應(yīng)AndroidManifest.xml中定義<Service/>標(biāo)簽
- PackageParser.Provider :對(duì)應(yīng)AndroidManifest.xml中定義<Provider/> 標(biāo)簽
- PackageParser.Instrumentation :對(duì)應(yīng)AndroidManifest.xml中定義<Instrumentation/> 標(biāo)簽
- PackageParser.Permission :對(duì)應(yīng)AndroidManifest.xml中定義<permission/> 標(biāo)簽
- PackageParser.PermissionGroup :對(duì)應(yīng)AndroidManifest.xml中定義<permission-group/> 標(biāo)簽
- PackageLite :輕量的包信息
- ApkLite :輕量級(jí)的APK信息
- IntentInfo :組件所定義的<intent-filter/>信息,保存了每個(gè)<intent-filter/>節(jié)點(diǎn)的信息,是基類(lèi),它的子類(lèi)是ActivityIntentInfo、ServiceIntentInfo和ProviderIntentInfo
- ActivityIntentInfo :保存<activity/>和<Receiver/>節(jié)點(diǎn)下的<intent-filter/>節(jié)點(diǎn)
- ServiceIntentInfo :保存<service/>節(jié)點(diǎn)下的<intent-filter/>節(jié)點(diǎn)
- ProviderIntentInfo:保存<provider/> 節(jié)點(diǎn)下的<intent-filter/>節(jié)點(diǎn)

—————————————分隔符—————————————
- PackageInfo :跨進(jìn)程傳遞的包數(shù)據(jù),包解析時(shí)生成
- PackageItemInfo :一個(gè)應(yīng)用包內(nèi)所有組件項(xiàng)和通用信息的基類(lèi)。提供最基本的屬性集,如:label、icon、meta-data等。
- ApplicationInfo:代表一個(gè)特定應(yīng)用的基本信息,對(duì)應(yīng)AndroidManifest里面的<application>
- InstrumentationInfo:用作進(jìn)行instrumentation的測(cè)試的片段,對(duì)應(yīng)AndroidManifest里面的<instrumentation>
- PermissionInfo:代表一個(gè)特定的權(quán)限,對(duì)應(yīng)AndroidManifest里面的<permission/>
- PermissionGroupInfo :一個(gè)特定的權(quán)限組,對(duì)應(yīng)AndroidManifest里面的<permission-group/>
- ComponentInfo:代表一個(gè)應(yīng)用內(nèi)組件(如activityInfo、serviceInfo、ProviderInfo)通用信息的基類(lèi)。一般不會(huì)直接使用該類(lèi),它設(shè)計(jì)為了不同應(yīng)用的組件共享統(tǒng)一的定義。
- ActivityInfo :對(duì)應(yīng)AndroidManifest.xml里面的注冊(cè)的<activity/>標(biāo)簽和<receiver/>標(biāo)簽。代表一個(gè)Activity或者receiver
- ServiceInfo :對(duì)應(yīng)AndroidManifest.xml里面的注冊(cè)的<service/>標(biāo)簽。代表一個(gè)service
- ProviderInfo :對(duì)應(yīng)AndroidManifest.xml里面的注冊(cè)的<service/>標(biāo)簽。代表一個(gè)Provider
- Intent:根據(jù)特定的條件找到匹配的組件
- IntentFilter :Intent過(guò)濾器
- ResolveInfo
- IntentResolver :Intent解析器,其子類(lèi)用于不同組件的Intent解析
保存了所有<activity/>或者<receiver/>節(jié)點(diǎn)信息。(Activity或者BroadcastReceiver信息就是用該自定義類(lèi)保存的)
- ActivityIntentResolver :保存所有<activity/>和<receiver/>節(jié)點(diǎn)信息。(Activity或者BroadcastReceiver信息就是用該自定義類(lèi)保存的)
保存了所有<service/>節(jié)點(diǎn)信息。(Service信息就是用該自定義類(lèi)保存的)。- ServiceIntentResolver :保存了所有<service /> 節(jié)點(diǎn)信息。(Service信息就是用該自定義類(lèi)保存的)
- ProviderIntentReslover:保存了所有 <provider /> 節(jié)點(diǎn)信息
- PackageHandler :包管理的消息處理器
- HandlerParams :消息的數(shù)據(jù)載體
- InstallParams : 用于APK的安裝
- MeasureParams:用于查詢(xún)某個(gè)已安裝的APK占據(jù)存儲(chǔ)空間的大小(例如在設(shè)置程序中得到某個(gè)APK的緩存文件大小)
- MoveParams :用于已安裝APK的位置移動(dòng)
- InstallArgs :APK的安裝參數(shù)
- FileInstallArgs :針對(duì)是安裝在內(nèi)部存儲(chǔ)的APK
- AsecInstallArgs :針對(duì)安裝在SD卡上的APK
- MoveInfoArgs : 移動(dòng)APK
這么龐大的數(shù)據(jù)結(jié)構(gòu),其各個(gè)數(shù)據(jù)結(jié)構(gòu)的類(lèi)圖如下:

大圖地址3
四、PackageManagerService的三大過(guò)程組
如果大家想對(duì)Android系統(tǒng)有一個(gè)大致的了解,就必須要要了解PackageManagerService的三大流程
- 1、包掃描的過(guò)程組:
即Android將一個(gè)APK文件的靜態(tài)信息轉(zhuǎn)化為可以管理的數(shù)據(jù)結(jié)構(gòu)- 2、包安裝的過(guò)程組:
即包管理接納一個(gè)新成員的體現(xiàn)。- 3、包查詢(xún)的過(guò)程組:
即Intent的定義和解析是包查詢(xún)的核心,通過(guò)包查詢(xún)服務(wù)可以獲取到一個(gè)包的信息
下面我們來(lái)一一進(jìn)行簡(jiǎn)單的介紹
(一)、包掃描過(guò)程組——即開(kāi)機(jī)掃描過(guò)程
1、為什么要進(jìn)行包掃描?
掃描目錄的目的:
掃描Android系統(tǒng)的幾個(gè)目標(biāo)文件中的APK,從而建立合適的數(shù)據(jù)結(jié)構(gòu)以及管理諸如Package信息、四大組件、授權(quán)信息等各種信息。抽象的地看,PackageManagerService像一個(gè)工廠,它解析實(shí)際的物理文件(APK文件),以及生成符合自己要求的產(chǎn)品。比如PackageManagerService將解析APK包中的AndroidManifest.xml,并根據(jù)其中聲明的Activity標(biāo)簽來(lái)創(chuàng)建與此對(duì)應(yīng)的對(duì)象,并保存到PackageParser.Package類(lèi)型的變量中,然后通過(guò)PackageManagerService的scanPackageDirtyLI()方法將解析后的組件數(shù)據(jù)統(tǒng)計(jì)到PackageManagerService的本地變量中,用于管理查詢(xún)調(diào)用,當(dāng)系統(tǒng)中任意某個(gè)APK的package發(fā)生改變時(shí),如卸載,升級(jí)等操作都會(huì)更新package的統(tǒng)計(jì)數(shù)據(jù)到PackageManagerService,PackageManagerService正式基于擁有系統(tǒng)中所有的Package的信息才能勝任"包管理"這個(gè)管理者的角色。PackageManagerService的工作流程相對(duì)簡(jiǎn)單,復(fù)雜的是其中用于保存各種信息的數(shù)據(jù)結(jié)構(gòu)和它們的關(guān)聯(lián)關(guān)系,以及對(duì)應(yīng)影響結(jié)果的策略控制(比如系統(tǒng)應(yīng)用和普通應(yīng)用)
2、包掃描過(guò)程組的不同理解
如果把包掃描過(guò)程組看成一件事,那么這件事就是:
調(diào)用PackageManagerService類(lèi)的靜態(tài)方法main()方法來(lái)獲取PackageManagerService對(duì)象
如果把包掃描過(guò)程組看成兩件事,那么這兩件事就是
1、創(chuàng)建PackageManagerService對(duì)象
2、將PackageManagerService向ServiceManager注冊(cè),即加入SMS,方便后續(xù)其他進(jìn)程或者app通過(guò)ServiceManager獲得PackageManagerService服務(wù)。
如果把包掃描過(guò)程組看成三件事,那么這三件事是:
1、先讀取保存在packages.xml中記錄的系統(tǒng)關(guān)機(jī)前記錄所有安裝的APP信息, 將其保存在PackageManagerServiced中mSettings中的mPackages中。
2、掃描指定的若干目錄中的app,并把信息記錄在PackageManagerServiced的mPackages中。
3、最后上面的兩者進(jìn)行對(duì)比,看是否有升級(jí)的APP,然后進(jìn)行相關(guān)處理,最后寫(xiě)入package.xml中
當(dāng)然換一個(gè)角度,以掃描角度來(lái)看,也可以把包掃描分解成另外三個(gè)階段:
- 掃描目標(biāo)文件夾之前的準(zhǔn)備工作
- 掃描目標(biāo)文件夾
- 掃描目標(biāo)文件夾之后的工作
如果把包掃描過(guò)程組看成四件事,那么這四件事是:
1、讀取響應(yīng)的配置文件
2、優(yōu)化APK和Jar包
3、掃描系統(tǒng)中所有安裝的應(yīng)用
4、把掃描出的所有應(yīng)用信息進(jìn)行保存
如果把包掃描過(guò)程組劃分的更細(xì),則我將其分為6大步驟
- 1、變量初始化,包括mSettings,mInstaller,mPackageDexOptimizer等等
- 2、讀取配置文件
- 3、掃描系統(tǒng)Package,包含Dex優(yōu)化
- 4、保存掃描信息
- 5、掃描非系統(tǒng)應(yīng)用
- 6、更新數(shù)據(jù)
如果把包掃描過(guò)程組劃分的更細(xì),則我將其分為9大步
第一步:創(chuàng)建Settings對(duì)象,并調(diào)用其addSharedUserLPw()方法,保存ShareUserSetting信息
第二步:創(chuàng)建Installer對(duì)象,用于Native進(jìn)程installd交互
第三步:創(chuàng)建ThreadHandler線程,并以其Looper為參數(shù)創(chuàng)建PackageHandler對(duì)象,用于程序的安裝和卸載
第四步:根據(jù)Installer對(duì)象和/data/user文件對(duì)象創(chuàng)建UserManager對(duì)象,用于多用戶管理
第五步:調(diào)用readPermissions()方法,從/system/etc/permissions目錄下的XML文件讀取權(quán)限信息
第六步:調(diào)用Settings對(duì)象的readLPw()方法解析/data/system目錄下的文件:
第七步:掃描/system/frameworks目錄以及BOOTCLASSPATH和platform.xml定義的系統(tǒng)目錄下的jar和APK文件是否需要dex優(yōu)化,如果需要?jiǎng)t調(diào)用Installer.dexopt()方法來(lái)發(fā)送消息給installd讓它優(yōu)化;如果任意一個(gè)文件執(zhí)行了dex優(yōu)化操作,刪除/data/dalvik-cache目錄下的緩存文件
第八步:創(chuàng)建AppDirObserver對(duì)象監(jiān)聽(tīng)/system/frameworks、/system/app、/vendor/app(廠商定制)、/data/app、/data/app-private5個(gè)目錄,并調(diào)用scanDirLI()方法掃描其中的APK文件:
第九步:匯總上面掃描XML和APK得到的信息,并寫(xiě)入文件;
3、如果把包掃描過(guò)程組劃分為"方法級(jí)"的流程,如下圖:

大圖地址3
4、溫馨提醒
- 在packages.xml中<package>標(biāo)簽記錄的APP的安裝信息。有獨(dú)立uid的APP,后面再反序列化的時(shí)候,會(huì)映射為PackageSetting對(duì)象,保存在mSettings的mPackages中;有sharedUid的APP,后面反序列化的時(shí)候,會(huì)映射為PendingPackage對(duì)象,保存在mSettings的mPendingPackages中。
- 對(duì)于<share-user>標(biāo)簽記錄的的share uid信息,封裝為SharedUserSetting對(duì)象,保存到mSettings里面的mSharedUser中,在此過(guò)程中遇到的uid和 shared uid都保存在mUserIds中,并讓每個(gè)uid指向與之關(guān)聯(lián)的PackageSetting對(duì)象,或者SharedUserSetting對(duì)象
5、小結(jié)
- PackageManagerService是伴隨著系統(tǒng)進(jìn)程啟動(dòng)而啟動(dòng)的,最終會(huì)構(gòu)造一個(gè)PackageManagerService對(duì)象,此后,PackageManagerService將成為Android世界的包管理者,對(duì)外提供包的增、刪、改、查的操作
- 在PackageManagerService的啟動(dòng)過(guò)程中,最重要的是對(duì)所有靜態(tài)APK文件進(jìn)行掃描,生成一個(gè)在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)Package,PackageManagerService實(shí)際上就是維護(hù)這所有在內(nèi)存中的數(shù)據(jù)結(jié)構(gòu)。已有的包的歷史信息會(huì)寫(xiě)入磁石,PackageManagerService的Settings專(zhuān)門(mén)來(lái)管理寫(xiě)入磁盤(pán)的包信息。
- 所有包的信息掃描完成后,需要對(duì)應(yīng)用進(jìn)行授權(quán),這是Android權(quán)限管理的一部分。隨著 Android版本的升級(jí),授權(quán)機(jī)制略有區(qū)別,總體框架是:每個(gè)APK都可以聲明權(quán)限,并為權(quán)限設(shè)定保護(hù)級(jí)別,其他APK需要使用這些權(quán)限的時(shí)候,需要先申請(qǐng),再由系統(tǒng)判定是否進(jìn)行授權(quán)。
(二)、包安裝的過(guò)程組——即安裝一個(gè)新的APK
安裝一個(gè)APK的其大致流程如下:

通常,安裝一個(gè)APK 通常分為以下4種方式
- 安裝系統(tǒng)應(yīng)用
- 網(wǎng)絡(luò)下載應(yīng)用安裝
- ADB工具安裝
- 第三方應(yīng)用安裝
下面我們就依次介紹下
1、 安裝系統(tǒng)應(yīng)用
系統(tǒng)的應(yīng)用的安裝主要在PackageManagerService的main方法里面進(jìn)行操作的
其順序如下:
第一步:PackageManagerService.main()初始化注冊(cè)
第二步:建立Java層的installer與C層的intalld的socket聯(lián)接
第三步:建立PackageHandler消息循環(huán)
第四步:調(diào)用成員變量mSettings的readLPw()方法恢復(fù)上一次的安裝信息
第五步:.jar文件的detopt優(yōu)化
第六步:scanDirLI函數(shù)掃描特定目錄的APK文件解析
第七步:updatePermissionsLPw()函數(shù)分配權(quán)限
第八步:調(diào)用mSettings.writeLPr()保存安裝信息
2、 網(wǎng)絡(luò)下載應(yīng)用安裝
其順序如下:
第一步:調(diào)用PackageManagerService的installPackage方法
第二步:上面的方法調(diào)用installPackageWithVerfication(),進(jìn)行權(quán)限校驗(yàn),發(fā)送INIT_COPY的msg
第三步:進(jìn)入PackageManagerService的doHandleMessage方法的INIT_COPY分支
第四步:成功綁定了com.android.defcontainer.DefaultContainerService服務(wù),進(jìn)入MCS_BOUND分支
第五步:里面調(diào)用PackageManagerService中內(nèi)部抽象類(lèi)HandlerParams的子類(lèi)InstallParams的startCopy方法。
第六步:抽象類(lèi)的HandlerParams的startCopy方法調(diào)用了HandlerParams子類(lèi)的handleStartCopy和handlerReturnCode兩個(gè)方法
第七步:handlesStartCopy方法調(diào)用了InstallArgs的子類(lèi)copyApk,它負(fù)責(zé)將下載的APK文件copy到/data/app
第八步:handleReturnCode調(diào)用handleReturnCode方法
第九步:調(diào)用PackageManagerService服務(wù)的installPackageLI(PackageParser.Package, int, int, UserHandle, String, String,PackageInstalledInfo)方法進(jìn)行APK掃描。
第十步:上面的方法判斷是否APP應(yīng)安裝,調(diào)用installNewPackageLI或replacePackageLI方法
第十一步:調(diào)用updateSettingsLI方法進(jìn)行更新PackageManagerService的Settings
第十二步:發(fā)送what值為POST_INSTALL的Message給PackageHandler進(jìn)行處理
第十三步:發(fā)送what值為MCS_UNBIND的Message給PackageHandler,進(jìn)而調(diào)用PackageHandler.disconnectService()中斷連接
3、 ADB工具安裝
Android Debug Bridge (adb)是SDK自帶的管理設(shè)備的工具,通過(guò)ADB命令的方式也可以為手機(jī)或者模擬器安裝應(yīng)用,其入口函數(shù)為pm.java
Android Debug Bridge (adb) 是SDK自帶的管理設(shè)備的工具,通過(guò)ADB命令行的方式也可以為手機(jī)或模擬器安裝應(yīng)用,其入口函數(shù)源文件為pm.java
其順序如下:
第一步:pm.java的runInstall()方法
第二步:參數(shù)不對(duì)會(huì)調(diào)用showUsage方法,彈出使用說(shuō)明
第三步:正常情況runInstall會(huì)調(diào)用mPm變量的installPackageWithVerification方法
第四步:由于pm.java中的變量mPm是PackageManagerService的實(shí)例,所以實(shí)際上是調(diào)用PackageManagerService的installPackageWithVerfication()方法
第五步:進(jìn)入PackageManagerService的doHandleMessage方法的INIT_COPY分支
第六步:成功綁定了com.android.defcontainer.DefaultContainerService服務(wù),進(jìn)入MCS_BOUND分支
第七步:里面調(diào)用PackageManagerService中內(nèi)部抽象類(lèi)HandlerParams的子類(lèi)InstallParams的startCopy方法。
第八步:抽象類(lèi)的HandlerParams的startCopy方法調(diào)用了HandlerParams子類(lèi)的handleStartCopy和handlerReturnCode兩個(gè)方法
第九步:handlesStartCopy方法調(diào)用了InstallArgs的子類(lèi)copyApk,它負(fù)責(zé)將下載的APK文件copy到/data/app
第十步:handleReturnCode調(diào)用handleReturnCode方法
第十一步:調(diào)用PackageManagerService服務(wù)的installPackageLI(PackageParser.Package, int, int, UserHandle, String, String,PackageInstalledInfo)方法進(jìn)行APK掃描。
第十二步:上面的方法判斷是否APP應(yīng)安裝,調(diào)用installNewPackageLI或replacePackageLI方法
第十三步:調(diào)用updateSettingsLI方法進(jìn)行更新PackageManagerService的Settings
第十四步:發(fā)送what值為POST_INSTALL的Message給PackageHandler進(jìn)行處理
第十五步:發(fā)送what值為MCS_UNBIND的Message給PackageHandler,進(jìn)而調(diào)用PackageHandler.disconnectService()中斷連接

4、 第三方應(yīng)用安裝
第一步:調(diào)用PackageInstallerActivity的onCreate方法初始化安裝界面
第二步:初始化界面以后調(diào)用initiateInstall方法
第三步:上面的方法調(diào)用startInstallConfirm方法,彈出確認(rèn)和取消安裝的按鈕
第四步:點(diǎn)擊確認(rèn)按鈕,打開(kāi)新的activity:InstallAppProgress
第五步:InstallAppProgress類(lèi)初始化帶有進(jìn)度條的界面之后,調(diào)用PackageManager的installPackage方法
第六步:PackageManager是PackageManagerService實(shí)例,所以就是調(diào)用PackageManagerService的installPackage方法
第七步:調(diào)用PackageManagerService的installPackage方法
第八步:上面的方法調(diào)用installPackageWithVerfication(),進(jìn)行權(quán)限校驗(yàn),發(fā)送INIT_COPY的msg
第九步:進(jìn)入PackageManagerService的doHandleMessage方法的INIT_COPY分支
第十步:成功綁定了com.android.defcontainer.DefaultContainerService服務(wù),進(jìn)入MCS_BOUND分支
第十一步:里面調(diào)用PackageManagerService中內(nèi)部抽象類(lèi)HandlerParams的子類(lèi)InstallParams的startCopy方法。
第十二步:抽象類(lèi)的HandlerParams的startCopy方法調(diào)用了HandlerParams子類(lèi)的handleStartCopy和handlerReturnCode兩個(gè)方法
第十三步:handlesStartCopy方法調(diào)用了InstallArgs的子類(lèi)copyApk,它負(fù)責(zé)將下載的APK文件copy到/data/app
第十四步:handleReturnCode調(diào)用handleReturnCode方法
第十五步:調(diào)用PackageManagerService服務(wù)的installPackageLI(PackageParser.Package, int, int, UserHandle, String, String,PackageInstalledInfo)方法進(jìn)行APK掃描。
第十六步:上面的方法判斷是否APP應(yīng)安裝,調(diào)用installNewPackageLI或replacePackageLI方法
第十七步:調(diào)用updateSettingsLI方法進(jìn)行更新PackageManagerService的Settings
第十八步:發(fā)送what值為POST_INSTALL的Message給PackageHandler進(jìn)行處理
第十九步:發(fā)送what值為MCS_UNBIND的Message給PackageHandler,進(jìn)而調(diào)用PackageHandler.disconnectService()中斷連接

點(diǎn)擊放大查看高清無(wú)碼大圖
小結(jié):
- 1、安裝和卸載都是通過(guò)PackageManager,實(shí)質(zhì)上是實(shí)現(xiàn)了PackageManagerService來(lái)完成具體的操作,所有細(xì)節(jié)和邏輯均可以在PackageManagerService中跟蹤查看。
- 2、所有安裝方式殊途同歸,最終就是回到PackageManagerService中,然后調(diào)用底層本地代碼的installd來(lái)完成的。
- 3、APK的安裝過(guò)程主要分為以下幾步:
- 拷貝到apk文件到指定目錄
- 解壓縮apk,拷貝文件,創(chuàng)建應(yīng)用的數(shù)據(jù)目錄
- 解析apk的AndroidManifest.xml文件
- 向Launcher應(yīng)用申請(qǐng)?zhí)砑觿?chuàng)建快捷方式
(三)、包查詢(xún)的過(guò)程組——即解析Intent并找到其配備的組件
1、包管理是以什么樣的形式對(duì)外提供服務(wù)那?
在寫(xiě)應(yīng)用程序時(shí),我們通常會(huì)利用應(yīng)用自身的上下文環(huán)境Context來(lái)獲取包管理服務(wù),如下:
// 獲取一個(gè)PackageManager的對(duì)象實(shí)例
PackageManager pm = context.getPackageManager();
// 通過(guò)PackageManager對(duì)象獲取指定包名的包信息
PackageInfo pi = pm.getPackageInfo("com.android.contacts", 0);
這么一段簡(jiǎn)單的代碼,其實(shí)蘊(yùn)含很多的深意
- 1、上面已經(jīng)講解過(guò)了PackageManagerService和其管理的各種數(shù)據(jù)結(jié)構(gòu),都是運(yùn)行在系統(tǒng)進(jìn)程之中。在應(yīng)用進(jìn)程中獲取的PackageManager對(duì)象,只是PackageManagerService在應(yīng)用進(jìn)程中的一個(gè)代理,不同的應(yīng)用進(jìn)程都有不同的代理,意味著不同應(yīng)用進(jìn)程中的PackageManager是不同的,但是管理者PackageManagerService有且只有一個(gè)
- 2、運(yùn)行在應(yīng)用進(jìn)程中的PackageManager要與運(yùn)行在系統(tǒng)進(jìn)程中的PackageManagerService進(jìn)行通信,通信手段是Android中最常見(jiàn)的Binder機(jī)制。因此會(huì)有一個(gè)IPackageManager.aidl文件,用于描兩者通信的接口。另外,應(yīng)用進(jìn)程中的PackageInfo對(duì)象。PackageInfo其實(shí)就是由系統(tǒng)進(jìn)程傳遞到應(yīng)用進(jìn)程的對(duì)象

PackageManagerService作為包管理的最核心組成部分,伴隨著系統(tǒng)的啟動(dòng)而創(chuàng)建,并一直運(yùn)行系統(tǒng)進(jìn)程中。當(dāng)應(yīng)用程序需要獲取包管理服務(wù)時(shí),會(huì)生成一個(gè)PackageManager對(duì)PackageManagerService進(jìn)行通信。在包解析時(shí)就會(huì)生成包信息,即XXInfo這一類(lèi)數(shù)據(jù)結(jié)構(gòu),PackageManagerService將這些數(shù)據(jù)傳遞給需要的應(yīng)用進(jìn)程。
管理者對(duì)內(nèi)設(shè)計(jì)了復(fù)雜的管理機(jī)制,對(duì)外封裝了簡(jiǎn)單的使用接口。這種設(shè)計(jì)在Android中大量出現(xiàn),比如ActivityManagerService、WindowManagerService、PowerManagerService等,基本所有的系統(tǒng)服務(wù)都遵循這種設(shè)計(jì)規(guī)范。對(duì)于應(yīng)用程序而言,不需關(guān)心管理者的實(shí)現(xiàn)原理,只需要理解接口的使用場(chǎng)景
Android在全局定義了IPackageManager,接口,描述了包管理者對(duì)外提供的功能,運(yùn)行在系統(tǒng)進(jìn)程中的PackageManagerService實(shí)現(xiàn)了IPackageManager接口,作為包管理的服務(wù)端,客戶端通過(guò)IPackageManager接口請(qǐng)求包服務(wù)。為了方便客戶端進(jìn)行包服務(wù),Android做了多層的封裝。應(yīng)用進(jìn)程作為客戶端,通過(guò)PackageManager便可使用包服務(wù),客戶端實(shí)際存在的對(duì)象是ApplicationPackageManager,它封裝了IPackageManager的所有接口。在應(yīng)用進(jìn)程來(lái)看,客戶端和服務(wù)端的概念是模糊的,明確的只有運(yùn)行環(huán)境的概念,即Context。包服務(wù)就存在于應(yīng)用進(jìn)程的運(yùn)行環(huán)境中,需要時(shí)直接拿出來(lái)使用即可。
“運(yùn)行環(huán)境(Context)”是Android的設(shè)計(jì)哲學(xué)之一,Android有意弱化進(jìn)程,強(qiáng)化運(yùn)行環(huán)境,這是面向應(yīng)用開(kāi)發(fā)者的設(shè)計(jì)。運(yùn)行環(huán)境是什么并不是一個(gè)很好回到的問(wèn)題??梢詫⑵漕?lèi)比為我們的工作環(huán)境,當(dāng)我們需要辦公設(shè)備時(shí),只需要向管理部門(mén)申請(qǐng),并不需要關(guān)心辦公設(shè)備如何采購(gòu),辦公設(shè)備對(duì)一般的工作人員而言,就像是工作環(huán)境中天然存在的東西。
2、包管理的具體服務(wù)形式——Intent的解析:
在Android中,使用Intent來(lái)表達(dá)意圖,最終會(huì)有一個(gè)響應(yīng)者。當(dāng)系統(tǒng)產(chǎn)生一個(gè)Intent后,如何找到它的響應(yīng)者?這需要對(duì)Intent進(jìn)行解析。作為所有包信息管理者的中樞,PackageManagerService自然有義務(wù)承擔(dān)解析Intent的責(zé)任。要解析Intent,就需要了解Intent的結(jié)構(gòu),標(biāo)識(shí)了一個(gè)Intent身份的信息由兩部分構(gòu)成:
- 主要信息:主要信息Action和Data。Action用于表明Intent所要執(zhí)行的操作,譬如ACTION_VIEW,ACTION_EDIT;Data用于表明執(zhí)行操作的數(shù)據(jù),譬如聯(lián)系人數(shù)據(jù),數(shù)據(jù)是以URI來(lái)表達(dá)的。再舉兩個(gè)Action和Data成對(duì)出現(xiàn)的例子:
- ACTION_VIEW:content://contacts/people/1 :標(biāo)識(shí)查看聯(lián)系人數(shù)據(jù)庫(kù)中,ID為1的聯(lián)系人信息
- ACTION_DIAL:tel:119 :表達(dá)撥打電話給119
上面兩個(gè)例子的URI并不一樣,完整的URI格式為scheme://host:port/path。
- 次要信息:除了主要標(biāo)記的信息,Intent還可以附加很多額外的信息,比如Category,Type,Componten和Extra:
- Category:標(biāo)識(shí)Intent的類(lèi)別,譬如CATEGROY_LAUNCHER標(biāo)識(shí)對(duì)屬于左面的圖標(biāo)這一類(lèi)的對(duì)象執(zhí)行操作
- Type:標(biāo)識(shí)Intent所有操作的數(shù)據(jù)類(lèi)型,就是MIMEType,譬如要操作PNG圖片,那Type就可以設(shè)置為png
- Component:標(biāo)識(shí)Intent要操作的對(duì)象
- Extra:標(biāo)識(shí)Intent所傳遞的數(shù)據(jù)
上述這些數(shù)據(jù)都實(shí)現(xiàn)了Parcelable接口。
之所以Intent信息的主次之分,是因?yàn)榻馕鯥ntent的規(guī)則需要有一個(gè)依據(jù),主要信息是最能表達(dá)意圖的,而次要信息則是解析規(guī)則的一個(gè)補(bǔ)充。這就像大家在做自我介紹的時(shí)候,總是先說(shuō)姓名、籍貫這些主要的信息,再額外補(bǔ)充愛(ài)好、特長(zhǎng)這些次要信息,這樣一來(lái)在和其他人交朋友的時(shí)候,其他人就可以先根據(jù)籍貫、姓名鎖定我。如果我們只介紹愛(ài)好、特長(zhǎng),那么別人鎖定的范圍就比較廣,因?yàn)橛邢嗤瑦?ài)好或者特長(zhǎng)的人比較多。
Intent身份信息,其實(shí)就是Android的一種設(shè)計(jì)語(yǔ)言,譬如"打電話給119",只需要發(fā)出Action為ACTION_DIAL,URI為“tel:119”的Intent即可,剩下的就交給Android系統(tǒng)去理解這個(gè)意圖。任何組件只要按照規(guī)則發(fā)生,都會(huì)被Android系統(tǒng)正確的理解。
而根據(jù)Intent的方式不同,可以將Intent分為兩類(lèi):
- 顯示(Explicit):明確指明需要誰(shuí)來(lái)響應(yīng)Intent。這一類(lèi)Intent的解析過(guò)程比較簡(jiǎn)單
- 隱式(Implicit):有系統(tǒng)找出合適的目標(biāo)來(lái)響應(yīng)Intent。這一類(lèi)Intent的解析過(guò)程比較復(fù)雜,由于目標(biāo)明確,所以需要經(jīng)過(guò)層層篩選才能找到最合適的響應(yīng)者。
之所以Intent有顯式和隱式之分,是因?yàn)榻馕鯥ntent的方式不同,如果我指定要和某某交朋友,那么發(fā)出的這一類(lèi)請(qǐng)求,就是顯式Intent;如果沒(méi)有指定交朋友的對(duì)象,只是說(shuō)找到跟我愛(ài)好相同的人,那發(fā)出的這一類(lèi)請(qǐng)求,就是隱式的Intent。對(duì)待這兩種Intent顯然有不同的解析方式。
如果和"運(yùn)行環(huán)境Context"一樣,Intent也是面向應(yīng)用程序設(shè)計(jì),同樣是弱化了了進(jìn)程的概念。應(yīng)用程序只需表明"我想要什么",不需要關(guān)心索要的東西在什么地方,如何找到索要的東西。Intent是Android通信的手段之一,可以承載要傳遞的信息,至于信息怎么從發(fā)起進(jìn)程傳遞到目標(biāo)進(jìn)程,應(yīng)用程序可以毫不關(guān)心。
Intent最后一個(gè)響應(yīng)者是一個(gè)Android組件,Android組件都可以定義IntentFilter,前面說(shuō)了包解析器的時(shí)候,說(shuō)到了每一個(gè)Component類(lèi)中都有一個(gè)IntentInfo對(duì)象的數(shù)組,而IntentInfo則是IntentFilter的子類(lèi)。既然一個(gè)Android組件可以定義多個(gè)IntentFilter,那么Intent想要匹配到最終的組件,則需要通過(guò)組件所定義的所有IntentFilter:

多個(gè)IntentFilter之間是"或"的關(guān)系,哪怕其他所有IntentFilter都匹配失敗,只要有一個(gè)IntentFilter通過(guò),最終Intent還是找到了可以響應(yīng)的組件。
每一個(gè)IntentFilter就像是一個(gè)定義了白名單規(guī)則的過(guò)濾器,只有滿足白名單的要求才會(huì)放行。Intent的過(guò)濾規(guī)則,其實(shí)就是針對(duì)Intent的身份信息的匹配規(guī)則,當(dāng)Intent的身份信息與IntentFilter所規(guī)定的要求匹配上,則允許通過(guò);否則,Intent就被過(guò)濾掉了。IntentFilter的過(guò)濾規(guī)則包含以下三個(gè)方面:
- Action:每個(gè)IntentFilter可以定義零個(gè)或多個(gè)<action標(biāo)簽>,如果Intent想要通過(guò)這個(gè)IntentFilter,則Intent所轄的Action需要匹配其中至少一個(gè)。
- Category:每一個(gè)IntentFilter可以定義零個(gè)或者多個(gè)<category>標(biāo)簽,如果Intent想要通過(guò)這個(gè)IntentFilter,則Intent所轄的Categroy必須是IntentFilter所定義的Category的子集,才能通過(guò)IntentFileter。譬如Intent設(shè)置了兩個(gè)Category:CATEGORY_LAUNCHER和CATEGORY_MAIN,只有那些至少定義了兩項(xiàng)Category的IntentFilter,才會(huì)放行該Intent。啟動(dòng)Activity時(shí),會(huì)為Intent設(shè)置默認(rèn)的Category,即CATEGORY_DEFAULT。目標(biāo)Activity需要添加一個(gè)category偽CATEGORY_DEFAULT的IntentFilter來(lái)匹配這一類(lèi)隱式的Intent。
- Data:每一個(gè)IntentFilter可以定義零個(gè)或多個(gè)<data>,數(shù)據(jù)可以通過(guò)類(lèi)型(MIMEType)和位置(URI)來(lái)描述,如果Intent想要通過(guò)這個(gè)IntentFilter,則Intent所轄的Data需要匹配其中至少一個(gè)。
在了解Intent的身份信息和IntentFilter的規(guī)則定義之后,就可以介紹Intent解析的過(guò)程了,PackageManagerService有四大組件的Intent解析器,分別是ActivityIntentResolver用于解析發(fā)往Activity或Broadcast的Intent,ServiceIntentResolver用于解析發(fā)往Service的Intent,ProviderIntentResolver用于解析發(fā)往Provider的Intent,系統(tǒng)每收到一個(gè)Intent的解析請(qǐng)求時(shí),就會(huì)使用對(duì)應(yīng)的解析器,他們都是IntentResolver的子類(lèi)。
IntentResolver的職能就是解析Intent,它包含了所有IntentFilter,同時(shí)有一個(gè)重要的成員函數(shù)queryIntent(),接受Intent作為參數(shù),返回查詢(xún)結(jié)構(gòu):一個(gè)ResolveInfo對(duì)象的數(shù)據(jù)。因?yàn)榭赡苡卸鄠€(gè)組件來(lái)響應(yīng)一個(gè)Intent,所以返回結(jié)果是一個(gè)數(shù)組??上攵摵瘮?shù)就是針對(duì)輸入的Intent,按照前面所述的過(guò)濾規(guī)則,逐個(gè)與IntentFilter進(jìn)行匹配,直到找到最終的響應(yīng)者,便加入返回結(jié)果的列表。
- ResolveInfo是最終的Intent解析結(jié)果的數(shù)據(jù)結(jié)構(gòu),并不復(fù)雜,就是各類(lèi)組件信息的一個(gè)包裝。需要注意的是,其中的組件信息ActivityInfo、ProviderInfo、ServiceInfo只有一個(gè)不為空,這樣就可以區(qū)分不同組件的解析結(jié)果。
- 解析"顯式"的Intent,如果Intent中有設(shè)置Component,則說(shuō)明已經(jīng)顯式的指明由誰(shuí)來(lái)響應(yīng)Intent。根據(jù)Component可以獲取到對(duì)應(yīng)的 ActivityInfo,再封裝成ResolveInfo便可以作為結(jié)果返回了。
- 解析"隱式"的Intent,該處邏輯比較復(fù)雜,后面講解Activity的啟動(dòng)流程時(shí)再詳細(xì)講解。
3、小結(jié)
- 包管理對(duì)外提供服務(wù)的形式基于Bidner機(jī)制,服務(wù)端是運(yùn)行在系統(tǒng)進(jìn)程中的PackageManagerService,包查詢(xún)服務(wù)是使用范圍很廣的一類(lèi)服務(wù),很多其他服務(wù)都需要用到包信息,都是通過(guò)PackageManagerService獲取的。
- 包查詢(xún)服務(wù)的核心是Intent解析,PackageManagerService中實(shí)現(xiàn)了不同組件的解析器。針對(duì)一個(gè)輸入的Intent,解析得到可以響應(yīng)的組件。Android為此設(shè)計(jì)了IntentFilter機(jī)制,定義了Intent匹配規(guī)則,最終解析實(shí)現(xiàn)在IntentResolver.queryIntent()函數(shù)中
五、PackageManagerService的體系結(jié)構(gòu)

大圖地址
六、總結(jié)
本片文章主要講解了包管理的三個(gè)大的過(guò)程:包掃描過(guò)程、包查詢(xún)過(guò)程、包安裝過(guò)程,其中重點(diǎn)的是包安裝的過(guò)程。我們?cè)賮?lái)復(fù)習(xí)一下:
APK的安裝流程如下:
復(fù)制APK安裝包到/data/app目錄下,解壓縮并掃描安裝包,向資源管理器注入APK資源,解析AndroidManifest文件,并在/data/data目錄下創(chuàng)建對(duì)應(yīng)的應(yīng)用數(shù)據(jù)目錄,然后針對(duì)Dalvik/ART環(huán)境優(yōu)化dex文件,保存到dalvik-cache目錄,將AndroidManifest文件解析出的組件、權(quán)限注冊(cè)到PackageManagerService并發(fā)送廣播
具體流程如下:
├── PMS.installPackage()
└── PMS.installPackageAsUser()
|傳遞 InstallParams 參數(shù)
PackageHandler.doHandleMessage().INIT_COPY
|
PackageHandler.doHandleMessage().MCS_BOUND
├── HandlerParams.startCopy()
│ ├── InstallParams.handleStartCopy()
│ │ └──InstallArgs.copyApk()
│ └── InstallParams.handleReturnCode()
│ └── PMS.processPendingInstall()
│ ├── InstallArgs.doPreInstall()
│ ├── PMS.installPackageLI()
│ │ ├── PackageParser.parsePackage()
│ │ ├── PackageParser.collectCertificates()
│ │ ├── PackageParser.collectManifestDigest()
│ │ ├── PackageDexOptimizer.performDexOpt()
│ │ ├── InstallArgs.doRename()
│ │ │ └── InstallArgs.getNextCodePath()
│ │ ├── replacePackageLI()
│ │ │ ├── shouldCheckUpgradeKeySetLP()
│ │ │ ├── compareSignatures()
│ │ │ ├── replaceSystemPackageLI()
│ │ │ │ ├── killApplication()
│ │ │ │ ├── removePackageLI()
│ │ │ │ ├── Settings.disableSystemPackageLPw()
│ │ │ │ ├── createInstallArgsForExisting()
│ │ │ │ ├── deleteCodeCacheDirsLI()
│ │ │ │ ├── scanPackageLI()
│ │ │ │ └── updateSettingsLI()
│ │ │ └── replaceNonSystemPackageLI()
│ │ │ ├── deletePackageLI()
│ │ │ ├── deleteCodeCacheDirsLI()
│ │ │ ├── scanPackageLI()
│ │ │ └── updateSettingsLI()
│ │ └── installNewPackageLI()
│ │ ├── scanPackageLI()
│ │ └── updateSettingsLI()
│ ├── InstallArgs.doPostInstall()
│ ├── BackupManager.restoreAtInstall()
│ └── sendMessage(POST_INSTALL)
│ |
│ PackageHandler.doHandleMessage().POST_INSTALL
│ ├── grantRequestedRuntimePermissions()
│ ├── sendPackageBroadcast()
│ └── IPackageInstallObserver.onPackageInstalled()
└── PackageHandler.doHandleMessage().MCS_UNBIND
└── PackageHandler.disconnectService()
至此,整個(gè)APK安裝流程詳解全部說(shuō)完,謝謝!