中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

上海app網(wǎng)站開發(fā)價(jià)值信息發(fā)布平臺(tái)推廣有哪些

上海app網(wǎng)站開發(fā)價(jià)值,信息發(fā)布平臺(tái)推廣有哪些,東莞市網(wǎng)站建設(shè)平臺(tái),wordpress 代碼編寫戳藍(lán)字“牛曉偉”關(guān)注我哦! 用心堅(jiān)持輸出易讀、有趣、有深度、高質(zhì)量、體系化的技術(shù)文章,技術(shù)文章也可以有溫度。 前言 閱讀該篇之前,建議先閱讀下面的系列文章: Android深入理解包管理–PackageManagerService和它的“小伙伴…

戳藍(lán)字“牛曉偉”關(guān)注我哦!

用心堅(jiān)持輸出易讀、有趣、有深度、高質(zhì)量、體系化的技術(shù)文章,技術(shù)文章也可以有溫度。

前言

閱讀該篇之前,建議先閱讀下面的系列文章:

Android深入理解包管理–PackageManagerService和它的“小伙伴”

Android深入理解包管理–記錄存儲(chǔ)模塊

Android深入理解包管理–共享庫(kù)模塊

Android深入理解包管理—apk信息

本文摘要

這是包管理系列的最后一篇文章,本文的標(biāo)題是從上帝視角來(lái)看PackageManagerService,為啥要起這么“狂妄”的名字呢?其主要的原因是我希望從一個(gè)更全面、更高的、更清晰的視角來(lái)看明白PackageManagerService的每個(gè)模塊之間是如何協(xié)作來(lái)保證PackageManagerService的關(guān)鍵工作順利完成。通過(guò)本文您將了解到PackageManagerService被劃分為哪些模塊模塊之間是如何協(xié)作來(lái)保證各項(xiàng)工作的順利完成。(文中代碼基于Android13)

本文大綱

1. 模塊的劃分

2. 模塊的啟動(dòng)

3. 模塊相互協(xié)作守護(hù)apk的安裝

4. 模塊相互協(xié)作守護(hù)app的運(yùn)行

5. 總結(jié)

1. 模塊劃分

其實(shí)在Android深入理解包管理–PackageManagerService和它的“小伙伴”

這篇文章已經(jīng)介紹過(guò)PackageManagerService的各個(gè)模塊了,但是我還是希望把它們重新“請(qǐng)”出來(lái),以保證后面的內(nèi)容能順利連接起來(lái)。(當(dāng)然增加了快照管理模塊)

先簡(jiǎn)單介紹下PackageManagerService,它是運(yùn)行于systemserver進(jìn)程,systemserver進(jìn)程中有很多很多的服務(wù),比如大家熟知的ActivityManagerService、WindowManagerService。而PackageManagerService也是一個(gè)服務(wù),一個(gè)非常非常重要的服務(wù)。

下圖展示了PackageManagerService的幾個(gè)關(guān)鍵模塊

主要模塊有apk管理模塊、權(quán)限管理模塊、共享庫(kù)模塊、記錄存儲(chǔ)模塊、所有apk信息模塊、四大組件模塊PackageManagerService不可能只有上面的幾個(gè)模塊,它還有快照模塊、對(duì)外接口模塊、property模塊等,只不過(guò)上面的模塊較常見。

1.1 權(quán)限管理模塊

既然是權(quán)限管理模塊,那有必要先來(lái)介紹下權(quán)限,權(quán)限分為聲明權(quán)限請(qǐng)求權(quán)限。

1.1.1 聲明權(quán)限

聲明權(quán)限需要在AndroidManifest.xml文件中使用permission標(biāo)簽,如下例子:

<permission android:description="string resource"android:icon="drawable resource"android:label="string resource"android:name="string"android:permissionGroup="string"android:protectionLevel=["normal" | "dangerous" |"signature" | ...] />

每個(gè)apk都可以聲明自己的權(quán)限,那當(dāng)別的apk訪問(wèn)自己的一些關(guān)鍵信息時(shí)候就可以要求它具有某個(gè)聲明的權(quán)限后才可以訪問(wèn)。

1.1.2 請(qǐng)求權(quán)限

請(qǐng)求權(quán)限就是在AndroidManifest中通過(guò)uses-permission標(biāo)簽來(lái)使用權(quán)限,如下代碼:

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

1.1.3 權(quán)限管理模塊所做的事情

權(quán)限管理模塊所做的事情如下:

  1. 把所有的apk聲明的權(quán)限收集并集中管理起來(lái)
  2. 保存每個(gè)apk請(qǐng)求的權(quán)限和請(qǐng)求權(quán)限對(duì)應(yīng)的狀態(tài),請(qǐng)求權(quán)限對(duì)應(yīng)的狀態(tài)是指比如某個(gè)apk的請(qǐng)求的權(quán)限是否被允許、是否拒絕、是否只是允許一次
  3. 處理apk權(quán)限請(qǐng)求,當(dāng)用戶不管是點(diǎn)擊了允許、拒絕等,都需要經(jīng)過(guò)權(quán)限管理模塊

權(quán)限管理模塊把上面這些事情全權(quán)交給了PermissionManagerService服務(wù)來(lái)處理,關(guān)于權(quán)限管理后面會(huì)有系列文章來(lái)介紹。

1.2 共享庫(kù)模塊

同樣先來(lái)簡(jiǎn)單介紹下共享庫(kù),共享庫(kù)首先它是一個(gè)庫(kù),庫(kù)大家肯定非常熟悉了,庫(kù)可以是一個(gè)jar文件 (jar包代表java庫(kù)) 也可以是一個(gè)so文件 (so是二進(jìn)制可執(zhí)行文件代表native庫(kù)),而它的形容詞共享代表該庫(kù)是可以被多個(gè)程序使用的。共享庫(kù)也就是可以被多個(gè)程序使用的庫(kù)。在Android中共享庫(kù)除了上面的意思之外,還要再加一條就是共享庫(kù)是由系統(tǒng)提供的可以被多個(gè)程序使用的系統(tǒng)庫(kù),在Android中共享庫(kù)可以是一個(gè)jar、so、apk文件。

共享庫(kù)也同樣分為聲明共享庫(kù)使用共享庫(kù),只有系統(tǒng)apk才能聲明共享庫(kù)。

共享庫(kù)模塊所做的事情如下:

  1. 把所有聲明的共享庫(kù)收集起來(lái),若共享庫(kù)之間存在依賴,則把它們的依賴也初始化
  2. 若apk中使用了某個(gè)共享庫(kù),則會(huì)根據(jù)共享庫(kù)名稱、版本信息共享庫(kù)模塊把共享庫(kù)的信息查詢出來(lái) (如共享庫(kù)文件路徑) 交給該apk

共享庫(kù)模塊把這些事情交給了SharedLibrariesImpl類來(lái)處理,關(guān)于共享庫(kù)模塊的詳細(xì)介紹可以看Android深入理解包管理–共享庫(kù)模塊
這篇文章。

1.3 記錄存儲(chǔ)模塊

記錄存儲(chǔ)模塊的主要工作是記錄apk的安裝及附加信息并且把這些信息存儲(chǔ)到文件中。也就是要想知道Android設(shè)備上有沒(méi)有安裝某個(gè)apk,是可以從記錄存儲(chǔ)模塊得知的。如果apk安裝了,則記錄存儲(chǔ)模塊會(huì)把安裝信息記錄下來(lái)。

關(guān)于該模塊的詳細(xì)介紹可以看
Android深入理解包管理–記錄存儲(chǔ)模塊

這篇文章

1.4 所有apk信息模塊

apk信息指的是apk的AndroidManifest.xml文件中配置的各種信息,比如apk版本信息、apk包名、聲明了哪些四大組件、使用了哪些權(quán)限、聲明了哪些權(quán)限、使用了哪些共享庫(kù)等。

安裝在Android設(shè)備上的apk (系統(tǒng)apk和非系統(tǒng)apk),都需要把它們的apk信息存儲(chǔ)到內(nèi)存中,以供使用者來(lái)查詢 (比如某使用者想要根據(jù)包名知道某個(gè)apk的ApplicationInfo信息),而存放所有apk信息的地方被稱為所有apk信息模塊。關(guān)于apk信息的詳細(xì)介紹可以看
Android深入理解包管理—apk信息
這篇文章。

下面是所有apk信息模塊在PackageManagerService中屬性的聲明:

//下面屬性位于PackageManagerService類//key是包名,而AndroidPackage存儲(chǔ)了解析出的AndroidManifest的信息
final WatchedArrayMap<String, AndroidPackage> mPackages = new WatchedArrayMap<>();

1.5 四大組件模塊

四大組件模塊在內(nèi)存中存儲(chǔ)了所有已安裝apk的AndroidManifest中聲明的四大組件,四大組件模塊的事情是完全交給了ComponentResolver類。

常用于以下場(chǎng)景:

  1. ActivityTaskManagerService啟動(dòng)某個(gè)Activity時(shí),需要從我這獲取對(duì)應(yīng)的Activity信息,獲取到則返回;否則啟動(dòng)Activity失效
  2. ActivityManagerService啟動(dòng)某個(gè)Service時(shí),也需要從我這獲取對(duì)應(yīng)的Service信息。同理啟動(dòng)某個(gè)BroadcastReceiverContentProvider也需要從我哦這獲取對(duì)應(yīng)的信息

下面是四大組件模塊在PackageManagerService中屬性的聲明:

//下面屬性位于PackageManagerService類final ComponentResolver mComponentResolver;

1.6 apk管理模塊

apk管理模塊從上圖可以看出它在所有模塊中的地位是多么重要,它包含的功能有掃描所有apk、apk安裝/更新/卸載、解析apk。
在后面會(huì)詳細(xì)介紹到它。對(duì)apk安裝感興趣可以查看apk安裝之謎這篇文章。

1.7 快照管理模塊

快照 (snapshot)可以理解為是數(shù)據(jù)的拷貝,在PackageManagerService的各個(gè)模塊以及各個(gè)模塊的屬性中都充斥著快照,如下部分代碼:

//Settings類//獲取Settings的快照
public Settings snapshot() {return mSnapshot.snapshot();
}private Settings(Settings r) {//Settings的很多屬性也都有自己的快照mPackages = r.mPackagesSnapshot.snapshot();mPackagesSnapshot  = new SnapshotCache.Sealed<>();mKernelMapping = r.mKernelMappingSnapshot.snapshot();mKernelMappingSnapshot = new SnapshotCache.Sealed<>();省略其他代碼······// Do not register any Watchables and do not create a snapshot cache.mSnapshot = new SnapshotCache.Sealed();
}

上面代碼只是截取了Settings (記錄存儲(chǔ)模塊)和它的屬性相關(guān)的快照,其他的各個(gè)模塊和屬性也都有相應(yīng)的快照。我剛開始看PackageManagerService代碼的時(shí)候,就被各種各樣的快照震驚了,為啥要有快照呢,它的作用是啥呢?

快照的作用就是為了快速的檢索數(shù)據(jù),大家都知道PackageManagerService中有各種各樣的數(shù)據(jù),并且數(shù)據(jù)量都很大,為了保持?jǐn)?shù)據(jù)的一致性,在更新/添加/刪除/訪問(wèn)這些數(shù)據(jù)的時(shí)候是都加了各種各樣的的,而如果沒(méi)有快照的話,比如在訪問(wèn)這些數(shù)據(jù)的時(shí)候是需要獲取相應(yīng)的鎖,如果沒(méi)有獲取到則需要等待,想想這個(gè)過(guò)程是非常影響查詢速度的。

那為了解決以上問(wèn)題快照就誕生了,每個(gè)模塊及相關(guān)屬性都有自己快照也就是拷貝,那當(dāng)訪問(wèn)這些數(shù)據(jù)的時(shí)候就從快照中直接獲取這速度是不是提升了很多 (其實(shí)就是以空間換時(shí)間罷了)。那當(dāng)模塊或者相關(guān)屬性的數(shù)據(jù)發(fā)生變化了會(huì)做何種處理呢?答案是發(fā)生變化的模塊或?qū)傩灾匦律勺约旱目煺铡?/p>

快照管理模塊很顯然就是管理了所有的快照,而它對(duì)應(yīng)的是Computer類,該類是一個(gè)接口,它的實(shí)現(xiàn)類是ComputerEngine快照管理模塊還有另外一個(gè)作用就是各種數(shù)據(jù)的代理者,PackageManagerService它是一個(gè)binder server,它的使用者可以通過(guò)binder通信的方式從它獲取各種數(shù)據(jù),而獲取的各種數(shù)據(jù)都是先要經(jīng)過(guò)快照管理模塊,而快照管理模塊把各種快照數(shù)據(jù)組裝起來(lái)返回給使用方。

PackageManagerService的快照Computer是最頂級(jí)的快照,它包含了各個(gè)模塊的快照,而每個(gè)模塊的快照又包含了自己相關(guān)屬性的快照。那當(dāng)某個(gè)模塊或者模塊屬性發(fā)生變化的時(shí)候,該變化信息會(huì)傳遞到PackageManagerServicePackageManagerService開始重新收集所有的快照,收集過(guò)程只要相應(yīng)的快照沒(méi)有發(fā)生變化,則依然使用它,否則重新生成快照。

關(guān)于快照管理模塊先暫時(shí)介紹到這。

1.8 小結(jié)

那簡(jiǎn)單總結(jié)下各個(gè)模塊:

  1. 權(quán)限管理模塊負(fù)責(zé)apk權(quán)限相關(guān)的事情,比如請(qǐng)求某個(gè)權(quán)限,apk權(quán)限狀態(tài)存儲(chǔ),收集所有apk聲明的權(quán)限
  2. 共享庫(kù)模塊負(fù)責(zé)apk使用到的所有共享庫(kù)
  3. 記錄存儲(chǔ)模塊會(huì)把a(bǔ)pk相關(guān)的很多信息記錄并且存儲(chǔ)到文件中,比如apk安裝后關(guān)于apk安裝的信息會(huì)存儲(chǔ)下來(lái),這樣就可以供其他使用者檢索
  4. 所有apk信息模塊會(huì)收集所有已安裝apk的AndroidManifest解析出來(lái)的信息,以供其他使用者檢索
  5. 四大組件模塊為了加快檢索四大組件的速度,會(huì)把所有已安裝apk的四大組件信息收集起來(lái)
  6. apk管理模塊主要負(fù)責(zé)apk的安裝/卸載/更新,它是根基模塊,因?yàn)樗哪硞€(gè)功能會(huì)對(duì)其他模塊產(chǎn)生影響。
  7. 快照管理模塊主要目的為加快訪問(wèn)PackageManagerService中的各種數(shù)據(jù)。

2. 模塊的啟動(dòng)

在Android深入理解包管理–PackageManagerService和它的“小伙伴”
中介紹過(guò)模塊的啟動(dòng),但是我覺(jué)得介紹的有些“潦草”,故在此更詳細(xì)的介紹下。

模塊的啟動(dòng)主要是想展示給大家,在PackageManagerService的啟動(dòng)過(guò)程中,各個(gè)模塊的啟動(dòng)都做了啥?為啥要這樣做?

下圖展示了PackageManagerService在啟動(dòng)過(guò)程中,每個(gè)模塊所做的事情:

前幾個(gè)模塊的啟動(dòng),其實(shí)都在為掃描所有apk做準(zhǔn)備,而掃描所有apk是PackageManagerService啟動(dòng)過(guò)程中做的非常重要的一件事情,如果不掃描所有apk,那PackageManagerService就完全不知道當(dāng)前Android設(shè)備上所有已安裝apk的具體apk信息 (apk信息指的是apk的AndroidManifest.xml文件中配置的各種信息如apk版本信息、apk包名、聲明了哪些四大組件等),不知道具體apk信息PackageManagerService猶如一個(gè)廢掉的服務(wù),不能提供任何有用的服務(wù)。

2.1 共享庫(kù)模塊啟動(dòng)

共享庫(kù)分為內(nèi)置共享庫(kù)聲明的共享庫(kù)

內(nèi)置共享庫(kù)很容易理解就是系統(tǒng)內(nèi)置的共享庫(kù),內(nèi)置共享庫(kù)可以理解為靜態(tài)的,因?yàn)樗鼈兊男畔⒈蛔x取到內(nèi)存后是不會(huì)發(fā)生變化的。

而聲明的共享庫(kù)指由系統(tǒng)apk聲明的共享庫(kù)。而聲明的共享庫(kù)可以理解為是動(dòng)態(tài)的,apk聲明了共享庫(kù)后,聲明的共享庫(kù)有可能被刪除 (該apk被刪除了后者apk刪除了該共享庫(kù)),也有可能被升級(jí) (apk聲明的共享庫(kù)升級(jí)了)等。

正因?yàn)閮?nèi)置共享庫(kù)和聲明的共享庫(kù)分別是靜態(tài)的動(dòng)態(tài)的,也就導(dǎo)致內(nèi)置共享庫(kù)信息是可以提前從文件中讀取到內(nèi)存中,而聲明的共享庫(kù)它是動(dòng)態(tài)的,它的任何變化都會(huì)影響到它的使用者,因此聲明的共享庫(kù)是不會(huì)存儲(chǔ)在文件中的,需要在掃描所有apk階段重新收集。

共享庫(kù)模塊的啟動(dòng)主要的工作是初始化內(nèi)置共享庫(kù),共享庫(kù)模塊作為PackageManagerService啟動(dòng)的第一個(gè)模塊,提前啟動(dòng)的主要原因是為掃描所有apk做準(zhǔn)備的,在掃描所有apk的時(shí)候有可能某個(gè)apk使用了某個(gè)內(nèi)置共享庫(kù),那這時(shí)候肯定需要從共享庫(kù)模塊查出該共享庫(kù)的信息,因此共享庫(kù)模塊的啟動(dòng)要放在前面。

關(guān)于共享庫(kù)模塊可以查看共享庫(kù)模塊這篇文章

下面是相關(guān)代碼,自行取閱:

//下面代碼位于PackageManagerService構(gòu)造方法中//從 SystemConfig.getInstance() 中把所有的內(nèi)置共享庫(kù)信息讀取出來(lái)ArrayMap<String, SystemConfig.SharedLibraryEntry> libConfig = systemConfig.getSharedLibraries();final int builtInLibCount = libConfig.size();for (int i = 0; i < builtInLibCount; i++) {//依次把共享庫(kù)信息添加到 mSharedLibraries 中mSharedLibraries.addBuiltInSharedLibraryLPw(libConfig.valueAt(i)); }long undefinedVersion = SharedLibraryInfo.VERSION_UNDEFINED;//下面代碼處理共享庫(kù)之間的依賴for (int i = 0; i < builtInLibCount; i++) {String name = libConfig.keyAt(i);SystemConfig.SharedLibraryEntry entry = libConfig.valueAt(i);final int dependencyCount = entry.dependencies.length;for (int j = 0; j < dependencyCount; j++) {final SharedLibraryInfo dependency =computer.getSharedLibraryInfo(entry.dependencies[j], undefinedVersion);if (dependency != null) {computer.getSharedLibraryInfo(name, undefinedVersion).addDependency(dependency);}}}

2.2 記錄存儲(chǔ)模塊啟動(dòng)

記錄存儲(chǔ)模塊它的主要作用是把記錄已安裝apk、記錄所有apk聲明的權(quán)限等,其中記錄已安裝apk的信息包括apk的版本號(hào)apk的包名、apk文件路徑、apk的appid、apk簽名信息、apk請(qǐng)求權(quán)限及權(quán)限狀態(tài)等。也就是可以從記錄存儲(chǔ)模塊知道哪個(gè)apk安裝了,apk安裝信息都有哪些等。

記錄存儲(chǔ)模塊啟動(dòng)主要的工作就是從已經(jīng)存儲(chǔ)的文件中把存儲(chǔ)的信息讀取出來(lái)交給對(duì)應(yīng)的數(shù)據(jù)類 (PackageSetting),這樣就可以知道安裝了哪些apk了。

記錄存儲(chǔ)模塊提前啟動(dòng)的主要原因除了為掃描所有apk做準(zhǔn)備,還為權(quán)限管理模式初始化做準(zhǔn)備,在掃描所有apk的時(shí)候肯定是需要知道某個(gè)系統(tǒng)apk是否已經(jīng)安裝,已經(jīng)安裝的話就需要用新apk與老apk進(jìn)行一些比較 (比如簽名信息是否一致)。為啥只是針對(duì)某個(gè)系統(tǒng)apk,因?yàn)槠胀╝pk的安裝只能通過(guò)正常的用戶手動(dòng)觸發(fā),而系統(tǒng)apk的安裝是在掃描階段進(jìn)行的。

關(guān)于記錄存儲(chǔ)模塊可以看
記錄存儲(chǔ)模塊
這篇文章

下面是相關(guān)代碼,自行取閱:

//下面代碼位于PackageManagerService構(gòu)造方法中//從 /data/system/packages.xml及其他文件中把保存的數(shù)據(jù)讀出來(lái)
mFirstBoot = !mSettings.readLPw(computer,  mInjector.getUserManagerInternal().getUsers(/* excludePartial= */ true,/* excludeDying= */ false,/* excludePreCreated= */ false));

2.3 權(quán)限管理模塊初始化

權(quán)限分為聲明權(quán)限使用權(quán)限,不管是apk聲明的權(quán)限還是apk使用的權(quán)限都是在記錄存儲(chǔ)模塊中存儲(chǔ)著的,當(dāng)記錄存儲(chǔ)模塊啟動(dòng)的時(shí)候,這些信息都會(huì)被讀取出來(lái)交給對(duì)應(yīng)的數(shù)據(jù)類。

權(quán)限管理模塊初始化就是使用記錄存儲(chǔ)模塊讀取到的權(quán)限信息來(lái)初始自己,初始化完畢后就可以從權(quán)限管理模塊知道所有apk都聲明了哪些權(quán)限,并且可以知道哪些apk使用了哪些權(quán)限,權(quán)限狀態(tài)是啥 (拒絕、允許等)。

權(quán)限管理模塊初始化的主要原因同樣也是為了掃描所有apk做準(zhǔn)備,關(guān)于權(quán)限管理模塊后面有相關(guān)系列文章介紹。

下面是相關(guān)代碼,自行取閱:

//下面代碼位于PackageManagerService構(gòu)造方法中//把所有apk聲明的權(quán)限交給mPermissionManager
mPermissionManager.readLegacyPermissionsTEMP(mSettings.mPermissions); 
//下面方法會(huì)使用每個(gè)apk的權(quán)限狀態(tài)初始化自己
mPermissionManager.readLegacyPermissionStateTEMP();

2.4 掃描所有apk

掃描所有apk是歸apk管理模塊,上面一直都在提掃描所有apk,它是PackageManagerService啟動(dòng)過(guò)程中最重要的事情沒(méi)有之一。為啥要叫掃描apk呢?

其實(shí)掃描apk是屬于安裝apk中的重要環(huán)節(jié),掃描apk對(duì)于系統(tǒng)apk的話是一個(gè)安裝或者升級(jí)的過(guò)程,對(duì)于普通apk來(lái)說(shuō)就是一個(gè)“查漏補(bǔ)缺”的過(guò)程 (比如某個(gè)系統(tǒng)apk把聲明的某個(gè)共享庫(kù)刪除了,則使用了該共享庫(kù)的apk就需要做調(diào)整)。掃描apk所做的主要事情如下:

  1. 把a(bǔ)pk信息從AndroidManifest文件中解析出來(lái)
  2. 在依據(jù)解析出來(lái)的apk信息,去記錄存儲(chǔ)模塊查詢?cè)揳pk是否已經(jīng)安裝,若安裝的話進(jìn)行升級(jí)方面的操作 (比如新老apk進(jìn)行版本比較);若沒(méi)有安裝則進(jìn)行安裝方面的操作,比如為apk創(chuàng)建data目錄等。
  3. 如果apk中AndroidManifest文件中的權(quán)限發(fā)生了則會(huì)通知權(quán)限管理模塊進(jìn)行增加/刪除/更新對(duì)應(yīng)權(quán)限;如果apk中聲明了共享庫(kù) (只有系統(tǒng)apk才可以聲明共享庫(kù)),則會(huì)通知共享庫(kù)模塊增加相應(yīng)的共享庫(kù)等操作。
  4. 解析出來(lái)的apk信息經(jīng)過(guò)步步驗(yàn)證后,最終會(huì)存放在所有apk信息模塊四大組件模塊,這樣就可以供其他使用者使用了。

掃描apk最終的結(jié)果就是apk信息經(jīng)過(guò)重重校驗(yàn),apk信息最終存放在所有apk信息模塊和四大組件模塊,這樣使用者就可以使用這些信息了,比如startActivity的時(shí)候ActivityTaskManagerService會(huì)從四大組件模塊中拿到Activity的信息。同時(shí)掃描apk也會(huì)或多或少的影響到權(quán)限管理模塊、共享庫(kù)模塊記錄存儲(chǔ)模塊。(到達(dá)如何影響的會(huì)在下面apk安裝環(huán)節(jié)介紹)

掃描所有apk分為掃描所有系統(tǒng)apk掃描所有普通apk,先進(jìn)行掃描所有系統(tǒng)apk,后進(jìn)行掃描所有普通apk,為啥是這樣的順序呢?原因是這樣的只有系統(tǒng)apk才能聲明共享庫(kù),因此需要先把所有的系統(tǒng)apk都掃描完后,共享庫(kù)模塊才能把所有聲明的共享庫(kù)收集起來(lái),供普通apk來(lái)使用。

存放系統(tǒng)apk的目錄主要是位于productvendor、systemsystem_ext、apex分區(qū)下的overlayapp、priv-app、framework目錄 (若在分區(qū)下存在相應(yīng)的目錄),而位于priv-app目錄下的apk是擁有特權(quán)的系統(tǒng)apk,這里的特權(quán)是具有特殊權(quán)限的簡(jiǎn)稱。存放普通apk的目錄是data分區(qū)的app目錄下。

掃描所有apk先掃描存放系統(tǒng)apk的目錄,再掃描存放普通apk的目錄,如下相關(guān)代碼:

//下面代碼位于PackageManagerService構(gòu)造方法中final int[] userIds = mUserManager.getUserIds();
//packageParser的作用是解析apk
PackageParser2 packageParser = mInjector.getScanningCachingPackageParser();
//掃描系統(tǒng)apk
mOverlayConfig = mInitAppsHelper.initSystemApps(packageParser, packageSettings, userIds,startTime); 
//掃描非系統(tǒng)apk
mInitAppsHelper.initNonSystemApps(packageParser, userIds, startTime); 
packageParser.close();

2.5 共享庫(kù)模塊再度登場(chǎng)

掃描所有apk是先掃描所有系統(tǒng)apk,然后在掃描所有普通apk。而在掃描所有系統(tǒng)apk的時(shí)候是沒(méi)有把系統(tǒng)apk中使用共享庫(kù)信息補(bǔ)全的 (如果該系統(tǒng)apk確實(shí)使用了某個(gè)共享庫(kù))。

先來(lái)解釋下啥叫共享庫(kù)信息補(bǔ)全,比如某系統(tǒng)apk在AndroidManifest.xml文件中使用uses-library標(biāo)簽使用了某個(gè)共享庫(kù),共享庫(kù)信息補(bǔ)全就是從共享庫(kù)模塊把該apk使用的共享庫(kù)信息 (共享庫(kù)文件路徑、名稱等)查詢出來(lái),并且交給該apk。

那為啥沒(méi)有把系統(tǒng)apk中使用共享庫(kù)信息補(bǔ)全呢?其主要原因還是因?yàn)?strong>只有系統(tǒng)apk才能聲明共享庫(kù),比如正在掃描某個(gè)系統(tǒng)apk,而它使用的共享庫(kù)對(duì)應(yīng)的系統(tǒng)apk還沒(méi)有被掃描,則這時(shí)候該系統(tǒng)apk的共享庫(kù)就沒(méi)有補(bǔ)全。那針對(duì)這種情況該咋辦呢?辦法就是在掃描完所有apk后,在去把所有系統(tǒng)apk中使用的共享庫(kù)信息一起補(bǔ)全 (如果該系統(tǒng)apk確實(shí)使用了某個(gè)共享庫(kù))。

下面是相關(guān)代碼,請(qǐng)自行取閱:

//下面代碼位于PackageManagerService構(gòu)造方法中//下面方法會(huì)把所有apk的共享庫(kù)信息補(bǔ)全 ((如果該apk確實(shí)使用了某個(gè)共享庫(kù))
mSharedLibraries.updateAllSharedLibrariesLPw(null, null, Collections.unmodifiableMap(mPackages)); 

2.6 小結(jié)

共享庫(kù)模塊、記錄存儲(chǔ)模塊權(quán)限管理模塊三個(gè)模塊的啟動(dòng)為掃描所有apk做準(zhǔn)備,而掃描所有apk又分為掃描所有系統(tǒng)apk和掃描所有普通apk,掃描所有apk最終的結(jié)果是所有apk信息最終存放在了所有apk信息模塊四大組件模塊,這樣使用者就可以從PackageManagerService獲取到某個(gè)apk的信息了,比如獲取某個(gè)Activity的信息。

而掃描所有apk也會(huì)或多或少的影響共享庫(kù)模塊記錄存儲(chǔ)模塊、權(quán)限管理模塊,比如掃描某個(gè)系統(tǒng)apk,該系統(tǒng)apk聲明了新的權(quán)限、聲明了新的共享庫(kù),則會(huì)把聲明的共享庫(kù)信息記錄在共享庫(kù)模塊,而聲明的權(quán)限則會(huì)通知權(quán)限管理模塊增加此權(quán)限,同時(shí)記錄存儲(chǔ)模塊也會(huì)把該權(quán)限存儲(chǔ)到文件中。

3. 模塊相互協(xié)作守護(hù)apk的安裝

本節(jié)主要想介紹模塊之間的相互協(xié)作來(lái)守護(hù)apk的安裝,先假設(shè)要安裝的apk,在它的AndroidManifest.xml文件中聲明了權(quán)限使用了某個(gè)權(quán)限、使用了某個(gè)共享庫(kù)、聲明了四大組件

下圖展示了安裝該apk的過(guò)程
image

那結(jié)合上圖來(lái)進(jìn)行介紹。

3.1 apk的安裝

apk的安裝首先需要把要安裝的apk拷貝到/data/app目錄下,首先先從AndroidManifest.xml中把a(bǔ)pk的基礎(chǔ)信息 (apk包名、版本號(hào)、簽名信息等)解析出來(lái);其次使用解析出來(lái)的基礎(chǔ)信息進(jìn)行apk完整性驗(yàn)證,主要驗(yàn)證apk有沒(méi)有被改過(guò);當(dāng)然還有其他的步驟如果已經(jīng)安裝了該apk,則需要驗(yàn)證新老apk的版本信息,還需要驗(yàn)證新老apk的簽名信息是不是一致;這些步驟都驗(yàn)證通過(guò)后,會(huì)從AndroidManifest.xml中把a(bǔ)pk的所有信息 (四大組件、權(quán)限等等) 都解析出來(lái);最后會(huì)使用apk信息經(jīng)過(guò)準(zhǔn)備、掃描、調(diào)和、提交階段來(lái)保證apk最后的安裝完成。

上面只是簡(jiǎn)單的介紹了apk的安裝過(guò)程,關(guān)于apk安裝更詳細(xì)的介紹可以看apk安裝之謎這篇文章。

3.2 各模塊協(xié)作

apk安裝的提交階段會(huì)做以下事情:

  1. 該apk的安裝信息 (apk包名、版本信息、apk文件路徑、appid、聲明和使用的權(quán)限等) 以PackageSetting對(duì)象添加到記錄存儲(chǔ)模塊,記錄存儲(chǔ)模塊會(huì)把所有的PackageSetting對(duì)象重新寫入到文件中
  2. 該apk信息 (apk包名、聲明的四大組件、版本信息、解析的權(quán)限等) 添加到所有apk信息模塊
  3. 該apk信息中的聲明的四大組件信息添加到四大組件模塊
  4. 因?yàn)樵揳pk使用了某個(gè)共享庫(kù),則會(huì)從共享庫(kù)模塊把該共享庫(kù)信息查詢出來(lái)交給PackageSetting對(duì)象
  5. 因?yàn)樵揳pk聲明和使用了權(quán)限,則聲明和使用的權(quán)限會(huì)被添加到權(quán)限管理模塊

注:對(duì)PackageSetting陌生,可以看下Android深入理解包管理–記錄存儲(chǔ)模塊

這篇文章

3.3 apk安裝最后一步

apk安裝的最后一步就是創(chuàng)建data目錄dex優(yōu)化。創(chuàng)建data目錄這樣app在運(yùn)行的時(shí)候就可以把私有數(shù)據(jù)存儲(chǔ)在該目錄下,dex優(yōu)化可以讓app運(yùn)行更快。

3.4 小結(jié)

apk的安裝過(guò)程,小結(jié)如下:

  1. 會(huì)在記錄存儲(chǔ)模塊存儲(chǔ)下該apk的安裝信息 (apk包名、appid、apk路徑等)、聲明的權(quán)限 (若聲明了權(quán)限)、使用的權(quán)限及狀態(tài) (若使用了權(quán)限),并且會(huì)把這些信息寫入文件
  2. apk信息會(huì)存放在所有apk信息模塊
  3. apk聲明的四大組件會(huì)存放在四大組件模塊
  4. apk的權(quán)限 (若聲明了權(quán)限或者使用了權(quán)限)會(huì)存放在 權(quán)限管理模塊

4. 模塊相互協(xié)作守護(hù)app的運(yùn)行

上面介紹了模塊之間的相互協(xié)作守護(hù)apk的安裝,那現(xiàn)在咱們來(lái)看下模塊之間相互協(xié)作來(lái)保證app的運(yùn)行。

大家都知道一個(gè)app開始運(yùn)行,可以通過(guò)啟動(dòng)一個(gè)Activity或者啟動(dòng)一個(gè)Service或者啟動(dòng)一個(gè)ContentProvider或者啟動(dòng)一個(gè)BroadcastReceiver。那我就用啟動(dòng)一個(gè)Activity,來(lái)看PackageManagerService的各個(gè)模塊是如何守護(hù)app運(yùn)行的,這個(gè)過(guò)程用到的模塊主要有快照管理模塊、所有apk信息模塊四大組件模塊、記錄存儲(chǔ)模塊*這四個(gè)模塊,那就從這三個(gè)模塊講起。

4.1 快照管理模塊

在啟動(dòng)一個(gè)Activity的時(shí)候,ActivityTaskManagerService會(huì)通過(guò)Intent信息從PackageManagerService服務(wù)查詢?cè)?em>Intent對(duì)應(yīng)的Activity信息 (該信息會(huì)被封裝為ActivityInfo對(duì)象),而該查詢?nèi)蝿?wù)PackageManagerService會(huì)交給快照管理模塊。

下面是相關(guān)代碼,自行取閱:

//ComputerEngine類public final @NonNull List<ResolveInfo> queryIntentActivitiesInternal(Intent intent,String resolvedType, @PackageManager.ResolveInfoFlagsBits long flags,@PackageManagerInternal.PrivateResolveFlags long privateResolveFlags,int filterCallingUid, int userId, boolean resolveForStart,boolean allowDynamicSplits) {省略代碼······}

4.2 四大組件模塊

快照管理模塊是沒(méi)有真正的查詢服務(wù)的,而真正的查詢Activity信息需要從四大組件模塊獲取,四大組件模塊會(huì)根據(jù)Intent中的ComponentName查詢到相應(yīng)的Activity信息。

如下是相關(guān)代碼:

//ComputerEngine類protected ActivityInfo getActivityInfoInternalBody(ComponentName component,@PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) {//四大組件模塊的實(shí)現(xiàn)者就是mComponentResolver,調(diào)用它的getActivity方法查詢到Activity信息ParsedActivity a = mComponentResolver.getActivity(component);省略代碼······}

4.3 所有apk信息模塊和記錄存儲(chǔ)模塊

通過(guò)啟動(dòng)一個(gè)Activity來(lái)啟動(dòng)一個(gè)app,不僅僅只需要Activity的信息,還需要Application的信息 (該信息存放在ApplicationInfo對(duì)象),為啥還需要ApplicationInfo信息呢?

主要原因是當(dāng)app第一次運(yùn)行的時(shí)候,它需要知道apk文件路徑、共享庫(kù)文件路徑 (若使用共享庫(kù))、包名、app的data目錄等等。比如知道了apk文件路徑、共享庫(kù)文件路徑 便可以把它們加入到自己的ClassLoader,這樣app運(yùn)行時(shí)就可以找到自己的類了;比如知道了app的data目錄就可以知道當(dāng)前app運(yùn)行時(shí)候存放數(shù)據(jù)的私有目錄在哪了。而以上這些信息都存放在ApplicationInfo對(duì)象,是需要提前獲取到的,以便app從ActivityManagerService獲取這些信息的時(shí)候可以順利獲取到。

ApplicationInfo的獲取是從所有apk信息模塊記錄存儲(chǔ)模塊拿到的,記錄存儲(chǔ)模塊存儲(chǔ)了共享庫(kù)信息 (若存在使用共享庫(kù))等。

如下代碼:

//ComputerEngine類protected ActivityInfo getActivityInfoInternalBody(ComponentName component,@PackageManager.ResolveInfoFlagsBits long flags, int filterCallingUid, int userId) {//四大組件模塊的實(shí)現(xiàn)者就是mComponentResolver,調(diào)用它的getActivity方法查詢到Activity信息ParsedActivity a = mComponentResolver.getActivity(component);AndroidPackage pkg = a == null ? null : mPackages.get(a.getPackageName());if (pkg != null && mSettings.isEnabledAndMatch(pkg, a, flags, userId)) {PackageStateInternal ps = mSettings.getPackage(component.getPackageName());if (ps == null) return null;if (shouldFilterApplication(ps, filterCallingUid, component, TYPE_ACTIVITY, userId)) {return null;}//調(diào)用generateActivityInfo方法return PackageInfoUtils.generateActivityInfo(pkg,a, flags, ps.getUserStateOrDefault(userId), userId, ps);}省略代碼······}//PackageInfoUtils類private static ActivityInfo generateActivityInfo(AndroidPackage pkg, ParsedActivity a,@PackageManager.ComponentInfoFlagsBits long flags,@NonNull PackageUserStateInternal state, @Nullable ApplicationInfo applicationInfo,@UserIdInt int userId, @Nullable PackageStateInternal pkgSetting) {省略代碼······//構(gòu)建ApplicationInfoif (applicationInfo == null) {applicationInfo = generateApplicationInfo(pkg, flags, state, userId, pkgSetting);}if (applicationInfo == null) {return null;}//構(gòu)建ActivityInfofinal ActivityInfo info = PackageInfoWithoutStateUtils.generateActivityInfoUnchecked(a, flags, applicationInfo);assignSharedFieldsForComponentInfo(info, a, pkgSetting, userId);return info;}

4.4 小結(jié)

不論是啟動(dòng)一個(gè)Activity或者啟動(dòng)一個(gè)Service或者啟動(dòng)一個(gè)ContentProvider或者啟動(dòng)一個(gè)BroadcastReceiver的方式來(lái)啟動(dòng)一個(gè)app,都需要去PackageManagerService查詢相應(yīng)的組件信息和ApplicationInfo信息,只有查詢到正確的信息后,才能執(zhí)行下一步操作;否則停止啟動(dòng)過(guò)程。

5. 總結(jié)

本文主要是通過(guò)“上帝的視角”來(lái)看清楚PackageManagerService的各模塊是如何保證PackageManagerService的主要工作如何進(jìn)行的,在PackageManagerService啟動(dòng)過(guò)程,每個(gè)模塊都做了哪些提前的準(zhǔn)備工作來(lái)保證掃描所有apk工作的順利完成;在apk安裝過(guò)程中,apk信息會(huì)存儲(chǔ)在所有apk信息模塊四大組件模塊,當(dāng)然在安裝過(guò)程中或多或少還會(huì)用到其他模塊;在app運(yùn)行時(shí),需要從PackageManagerService的相關(guān)模塊中獲取對(duì)應(yīng)組件和ApplicationInfo信息來(lái)保證后面啟動(dòng)流程的正確執(zhí)行,關(guān)于包管理系列的文章就全部介紹完畢。

請(qǐng)?zhí)砑訄D片描述

http://www.risenshineclean.com/news/35966.html

相關(guān)文章:

  • 浙江網(wǎng)站建設(shè)報(bào)價(jià)seo指的是搜索引擎
  • 湖北中牛建設(shè)有限公司網(wǎng)站網(wǎng)站搜索
  • 哪個(gè)網(wǎng)站有ae免費(fèi)模板競(jìng)價(jià)托管咨詢微競(jìng)價(jià)
  • 現(xiàn)在幫人做網(wǎng)站賺錢嗎bt種子bt天堂
  • 建設(shè)政府信息網(wǎng)站如何注冊(cè)網(wǎng)站平臺(tái)
  • 做航空產(chǎn)品的網(wǎng)站有哪些搜索量用什么工具查詢
  • 如何將網(wǎng)站指向404太原百度網(wǎng)站快速優(yōu)化
  • 煙臺(tái)網(wǎng)站建設(shè)哪家好呢網(wǎng)絡(luò)顧問(wèn)
  • 手機(jī)網(wǎng)站js特效個(gè)人博客登錄入口
  • 廣州建站模板搭建西安百度競(jìng)價(jià)開戶
  • 作風(fēng)建設(shè)網(wǎng)站海曙seo關(guān)鍵詞優(yōu)化方案
  • 東莞微網(wǎng)站建設(shè)費(fèi)用深圳seo優(yōu)化公司排名
  • 成都市建設(shè)局官網(wǎng)seo優(yōu)化方式包括
  • 邯鄲網(wǎng)站建設(shè)安聯(lián)網(wǎng)絡(luò)nb抖音推廣引流平臺(tái)
  • 網(wǎng)站開發(fā) 招標(biāo)采購(gòu)參數(shù)愛站網(wǎng)關(guān)鍵詞
  • 網(wǎng)站怎樣做優(yōu)化調(diào)整百度公司招聘崗位
  • 國(guó)內(nèi)建網(wǎng)站知名企業(yè)網(wǎng)站制作廠家有哪些
  • 網(wǎng)站開發(fā)運(yùn)用到的相關(guān)技術(shù)百度競(jìng)價(jià)推廣方案的制定
  • 網(wǎng)站制作公司上海微信引流推廣
  • 做好網(wǎng)站建設(shè)的重要性app優(yōu)化建議
  • 做壞事小視頻網(wǎng)站企業(yè)培訓(xùn)計(jì)劃
  • 泰安百度做網(wǎng)站的百度搜索熱度排名
  • 涼山網(wǎng)站開發(fā)推廣計(jì)劃怎么做
  • dreamweaver教程做網(wǎng)站新浪網(wǎng)今日烏魯木齊新聞
  • 網(wǎng)站搭建 審查重慶搜索排名提升
  • 做代還的人都聚集在哪些網(wǎng)站怎么開網(wǎng)店
  • 渭南做網(wǎng)站怎么免費(fèi)創(chuàng)建個(gè)人網(wǎng)站
  • 自己0基礎(chǔ)怎么創(chuàng)業(yè)seo搜索引擎優(yōu)化人員
  • 網(wǎng)站建設(shè) 北京優(yōu)化網(wǎng)站建設(shè)
  • 東莞做網(wǎng)站那家好網(wǎng)站優(yōu)化聯(lián)系