日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android system server之PackageManagerService详细分析

發(fā)布時間:2025/4/5 Android 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android system server之PackageManagerService详细分析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
概要
本篇主要分析了系統(tǒng)啟動階段包管理服務(wù)的啟動流程,其中的幾個接口在 apk 安裝時也會被調(diào)用。包管理服務(wù)啟動時主要做的工作大致有如下幾方面:


?? 1. 建立 java 層的 installer 與 c 層的 installd 的 socket 聯(lián)接,使得在上層的 install,remove,dexopt等功能最終由 installd 在底層實現(xiàn)

?? 2. 建 立 PackageHandler 消 息 循 環(huán) , 用 于 處 理 外 部 的 apk 安 裝 請 求 消 息 , 如 adbinstall,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,ts,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)行管理。調(diào)用 installer.install()進(jìn)行安裝工作,檢查 apk 里的 dex 文件是否需要再優(yōu)化,如果需要優(yōu)化則通過輔助工具 dexopt 進(jìn)行優(yōu)化處理;將解析出的 componet 添加到 pkg 的對應(yīng)列表里;對 apk 進(jìn)行簽名和證書校驗,進(jìn)行完整性驗證。
?8. 將解析的每個 apk 的信息保存到 packages.xml 和 packages.list 文件里,
packages.list 記錄了如下數(shù)據(jù):pkgName,userId,debugFlag,dataPath(包的數(shù)據(jù)路徑)

?


??????????????????????????????????? 圖 1 主流程圖
詳細(xì)分析
在 systemserver.java 中啟動包管理服務(wù)
pm=PackageManagerService.main(context,factoryTest != SystemServer.FACTORY_TEST_OFF);
main 函數(shù)主要功能是構(gòu)造 PackageManagerService 實例,然后添加到 ServiceManager 中。
??? public static final IPackageManager main(Context context, boolean factoryTest) {
??????? PackageManagerService m = new PackageManagerService(context, factoryTest);
??????? ServiceManager.addService("package", m);
??????? return m;
??? }
PackageManagerService(context, factoryTest) 是 包 管 理 服 務(wù) 的 主 進(jìn) 程 。 它 完 成 了對/system/app,/data/app,/system/framework,/data/app-private 下的 apk 文件的解析。詳細(xì)流程如下:
????????????? 初始化過程:
?????????? ?? 判斷 ro.build.type 是否等于 eng;
?????????? ?? 創(chuàng)建系統(tǒng)顯示像素實例 mMetrics = new DisplayMetrics();
????????????? 創(chuàng)建 mSettings 實例 mSettings = new Settings(),Settings 類是 PackageManagerService 的一個
????????????? 靜態(tài)子類,它的作用主要是保持動態(tài)設(shè)置的信息,通過 Settings()構(gòu)造函數(shù)在/data/system 下
????????????? 創(chuàng)建了三個文件名:packages.xml,packages-backup.xml(這個文件在 mSettings.writeLP()里被刪除了),packages.list。
????????????? mSettings 增加 android.uid.system,android.uid.phone,android.uid.log 三個共享用戶 ID,同時授予其系統(tǒng)權(quán)限。
?????????? ? //建立 installer 與 installd 的 socket 聯(lián)接
?????????? ? Installer installer = new Installer();
?????????? ? installer.ping() && Process.supportsProcesses();
???????? ? ? installd 完成以下一些命令
??????????? struct cmdinfo cmds[] = {
? ? ? ? ? ? ?? ? { "ping",???????????? 0, do_ping },
? ? ? ? ? ? ? ?? { "install",????????? 3, do_install },
? ? ? ? ? ? ? ?? { "dexopt",????????? 3, do_dexopt },
?? ? ? ? ? ? ? ? { "movedex",????????? 2, do_move_dex },
? ? ? ? ? ? ? ?? { "rmdex",??????????? 1, do_rm_dex },
? ? ? ? ? ? ? ?? { "remove",?????????? 1, do_remove },
? ? ? ? ? ? ? ?? { "rename",????????? 2, do_rename },
? ? ? ? ? ? ?? ? { "freecache",?????? 1, do_free_cache },
? ? ? ? ? ? ?? ? { "rmcache",?????????????? 1, do_rm_cache },
? ? ? ? ? ? ? ?? { "protect",?????????????? 2, do_protect },
? ? ? ? ? ? ?? ? { "getsize",?????????????? 3, do_get_size },
? ? ? ? ? ? ? ?? { "rmuserdata",?????????? 1, do_rm_user_data },
?? ? ? ? ? ? ? ? { "movefiles",???????? 0, do_movefiles },
?????????? };
//獲取當(dāng)前缺省的顯示像素
?????????????????? WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
????????????????? Display d = wm.getDefaultDisplay();
????????????????? d.getMetrics(mMetrics);
建立一個消息循環(huán),用于處理 apk 安裝時的請求消息處理(這些請求來自 adb install/push,包安裝器,android market 下載安裝 apk 時發(fā)送的)
???????????????? mHandlerThread.start();
??????????????? mHandler = new PackageHandler(mHandlerThread.getLooper());
這個消息循環(huán)處理的消息事件如下:
??? static final int SEND_PENDING_BROADCAST = 1;
??? static final int MCS_BOUND = 3;
??? static final int END_COPY = 4;
??? static final int INIT_COPY = 5;
??? static final int MCS_UNBIND = 6;
??? static final int START_CLEANING_PACKAGE = 7;
??? static final int FIND_INSTALL_LOC = 8;
??? static final int POST_INSTALL = 9;
??? static final int MCS_RECONNECT = 10;
??? static final int MCS_GIVE_UP = 11;
??? static final int UPDATED_MEDIA_STATUS = 12;
??? static final int WRITE_SETTINGS = 13;
//創(chuàng)建/data/data 和/data/app-private 目錄
File dataDir = Environment.getDataDirectory();//獲得/data 目錄
mAppDataDir = new File(dataDir, "data");
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
// Read permissions from /system/etc/permission directory.
//這些文件在 framework/base/data/etc
Void readPermissions()
{
?????? //解析/system/etc/permission/下的*.xml 文件,獲取權(quán)限信息
?????? //最后解析該目錄下的 platform.xml 文件,使該文件里的權(quán)限在棧頂出現(xiàn),以便預(yù)先處理
?????? //這個文件記錄了系統(tǒng)級應(yīng)用的 uid 及其擁有的權(quán)限
??????? File permFile = new File(Environment.getRootDirectory(),"etc/permissions/platform.xml");
??????? readPermissionsFromXml(permFile);
??????? //該函數(shù)的功能如下:
????????? 通過 xml 解 析 器 解 釋 *.xml 文 件 , 提 取 標(biāo) 簽 名 “ group” , "permission" , "assign-permission","library","feature"并進(jìn)行相應(yīng)處理。在 platform.xml 中對底層的系統(tǒng)用戶和組ID(group ids)同上層的由平臺管理的 permission 名字之間進(jìn)行了關(guān)系映射,使它們關(guān)聯(lián)起來。當(dāng)一個應(yīng)用被授予某個權(quán)限后,同時屬于已知的組 ID,這個應(yīng)用就可以進(jìn)行允許這個組的文件系統(tǒng)操作,如(read,write,execute )。這里記錄了一些系統(tǒng)級的應(yīng)用的 uid 對應(yīng)的permission
???? //每個標(biāo)簽的含義:
group:安裝到系統(tǒng)中的所有 APK 都具備的組 ID。
permission:可以指定一個權(quán)限與幾個組 ID 對應(yīng)。當(dāng)一個 APK 被授予這個權(quán)限時,它也同時屬于這幾個組。
assign-permission:把一個權(quán)限賦予一個 UID,當(dāng)進(jìn)程使用這個 UID 運(yùn)行時,就具備了這個權(quán)限。
library:為系統(tǒng)添加一些擴(kuò)展庫用的。對應(yīng)的.jar 文件放在/system/framework/目錄下。比如Google Map 相關(guān)的庫。
feature : 每 添 加 一 個 硬 件 , 都 要 增 加 對 應(yīng) 的 feature 。 將 以 上 解 析 的 結(jié) 果 對 應(yīng) 放 入mGlobalGids,mSettings.mPermissions,mSystemPermissions,mSharedLibraries,,mAvailableFeatures 等幾個 list 中供系統(tǒng)查詢和權(quán)限配置使用。
}
//readLP()會判斷/data/system/packages.xml 文件是否存在,如果不存在則返回 false,如果存在則進(jìn)行解析,在系統(tǒng)第一次啟動時 packages.xml 文件是不存在的,由 writeLP()創(chuàng)建該文件,并將該文件寫到 nand 上,下次開機(jī)會直接讀取并解析這個文件。解析的過程即是按照 xml定義的標(biāo)簽,將對應(yīng)的屬性和值添加到全局列表中。packages.xml 文件中記錄了系統(tǒng)安裝的所有 apk 的屬性權(quán)限的信息,當(dāng)系統(tǒng)中的 apk 安裝,刪除或升級時,改文件就會被更新。
<permissions> 標(biāo) 簽 定 義 了 目 前 系 統(tǒng) 中 定 義 的 所 有 權(quán) 限 。 主 要 分 為 兩 類 : 系 統(tǒng) 定 義 的(package 屬性為 Android)和 APK 定義的(package 屬性為 APK 的包名)
sharedUserId/userId:Android 系統(tǒng)啟動一個普通的 APK 時,會為這個 APK 分配一個獨立的UID , 這 就 是 userId 。 如 果 APK 要 和 系 統(tǒng) 中 其 它 APK 使 用 相 同 的 UID 的 話 , 那 就 是sharedUserId。perms:APK 的 AndroidManifest.xml 文件中,每使用一個<uses-permission>標(biāo)簽,<perms>標(biāo)簽中就會增加一項。
<shared-user> 代 表 一 個 共 享 UID , 通 常 , 共 同 實 現(xiàn) 一 系 列 相 似 功 能 的 APK 共 享 一 個UID。<perms>標(biāo)簽中的 權(quán)限代表了這個共享 UID 的權(quán)限,所有使用的同一個共享 UID 的APK 運(yùn)行在同一進(jìn)程中,這個進(jìn)程的 UID 就是這個共享 UID,這些 APK 都具有這個共享UID 的權(quán)限。
name:共享 UID 的名字,在 APK 的 Android:sharedUserId 屬性中使用。
userId:使用這個共享 UID 的所有 APK 運(yùn)行時所在的進(jìn)程的 UID。
mRestoredSettings = mSettings.readLP();
// 判 斷 boot class path 里 的 文 件 ( jar 文 件 ) 是 否 需 要 dexopt( 判 斷 標(biāo) 準(zhǔn) 是 檢 查DvmGlobals.bootClassPath 是否已經(jīng)包含這個文件),如果需要先將文件添加到 libFiles 里,同時 進(jìn) 行 dexopt : 由 Installer 通 過 socket 將 命 令 傳 給 installd 的 run_dexopt, 最 終 調(diào) 用 的是/system/bin/dexopt 對 jar 包進(jìn)行處理。如果已經(jīng)進(jìn)行了 dexopt 動作,則將/data/dalvik-cache下的以 data 開頭的文件刪除,后續(xù)重新建立。如果外部庫 mSharedLibraries 列表存在,也要檢 查 列 表 中 的 元 素 是 否 需 要 dexopt, 如 果 需 要 則 和 boot class path 進(jìn) 行 相 同 處 理 。 對于/system/framework 下 apk 和 jar 文件檢查是否需要 dexopt.
String bootClassPath = System.getProperty("java.boot.class.path");
?if (bootClassPath != null) {
?????? String[] paths = splitString(bootClassPath, ':');
??????????? for (int i=0; i<paths.length; i++) {
?????????????? try {
???????????????????????? if (dalvik.system.DexFile.isDexOptNeeded(paths[i])) {//是否需要 dexopt
????????????????????????????? libFiles.add(lib);//添加到 libFiles 列表
????????????????????????????? mInstaller.dexopt(paths[i], Process.SYSTEM_UID, true);//進(jìn)行 dexopt
?????????????????????????? }
????????????????????? }
???????????? }
? }
//對 framework-res.apk 不進(jìn)行 dexopt 直接添加到 libFiles
?????? libFiles.add(mFrameworkDir.getPath() + "/framework-res.apk");
// 啟 動 AppDirObserver 線 程 監(jiān) 測 /system/framework , /system/app , /data/app , /data/app-private 幾個目錄的事件,主要監(jiān)聽的是 add 和 remove 事件。對于目錄監(jiān)聽底層通過 inotify機(jī)制實現(xiàn),inotify 是在 2.6.13 中引入的新功能,它為用戶態(tài)監(jiān)視文件系統(tǒng)的變化提供了強(qiáng)大的支持;inotify 是一種文件系統(tǒng)的變化通知機(jī)制,如文件增加 ,刪除等事件可以立刻讓用戶態(tài)得知,當(dāng)監(jiān)測到事件發(fā)生時該線程做何處理呢?
MframeworkInstallObserver =
??????????????? new AppDirObserver(mFrameworkDir.getPath(),OBSERVER_EVENTS, true);
mFrameworkInstallObserver.startWatching();
//調(diào)用 scanDirLI 解析以上目錄下的 apk 文件,該函數(shù)是包管理服務(wù)的重要函數(shù),在后面有詳細(xì)的分析
??? private void scanDirLI(File dir, int flags, int scanMode) {
?????? String[] files = dir.list();
?????? for (i=0; i<files.length; i++)
?????? {
????????? File file = new File(dir, files[i]);
????????? PackageParser.Package pkg =
???????????????? scanPackageLI(file,flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
????????? if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
?????????????????? mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
?????????????? // Delete the apk
?????????????? file.delete();
????????? }
?????? }
???? }
//對于不存在的 system apk 調(diào)用以下函數(shù)刪除掉
??? Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
??? PackageSetting ps = psit.next();
??? if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
???????????????????????? &&!mPackages.containsKey(ps.name)
???????????????????????? && !mSettings.mDisabledSysPackages.containsKey(ps.name))
??? {
?????????? psit.remove();
?????????? mInstaller.remove(ps.name);
??? }
//在解析完以上目錄下的 apk 后,更新應(yīng)用的權(quán)限
??????? updatePermissionsLP(null, null, true, regrantPermissions, regrantPermissions);
//writeLP 會 生 成 packages.xml 和 packages.list 文 件 ,packages.list 的 數(shù) 據(jù) 格 式 是 :pkgName,userId,debugFlag,dataPath(包的數(shù)據(jù)路徑),packages.xml 保存了每個已經(jīng)安
裝 apk 的詳盡的信息
??????? mSettings.writeLP();
以上是包管理服務(wù)在系統(tǒng)啟動時做的全部工作。
//
//
//
///
下面解析其中一個比較重要的函數(shù) scanDirLI:
private void scanDirLI(File dir, int flags, int scanMode) {
???????? String[] files = dir.list();
???????? for (i=0; i<files.length; i++)
???????? {
????????????? File file = new File(dir, files[i]);
????????????? PackageParser.Package pkg =
???????????????????????? scanPackageLI(file,flags|PackageParser.PARSE_MUST_BE_APK, scanMode);
????????????? if (pkg == null && (flags & PackageParser.PARSE_IS_SYSTEM) == 0 &&
?????????????????????? mLastScanError == PackageManager.INSTALL_FAILED_INVALID_APK) {
????????????????? // Delete the apk
????????????????? file.delete();
????????????? }
???????? }
???? }
這 個 函 數(shù) 結(jié) 構(gòu) 比 較 簡 單 , 對 監(jiān) 測 的 幾 個 目 錄 下 的 每 一 個 apk 文 件 繼 續(xù) 通 過scanPackageLI(file,flags|PackageParser.PARSE_MUST_BE_APK, scanMode) 進(jìn) 行 解 析 , 對 不存在且安裝失敗已經(jīng)無效的非系統(tǒng) apk 直接刪除。

?


? ? ? ? ? ? ? ? ? ? ? ? ? ??? ? ?? ? ? ???? ???? ??? ???????????

???????????????????? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 圖 2 scanDirLI 流程分析

scanPackageLI 是 一 個 重 定 義 函 數(shù) , 它 的 作 用 是 : 用 PackageParser 的 兩 個 重 定 義 函 數(shù)parsePackage 解析 package 的 asset,res,建立 asset 資源文件路徑;解析 AndroidManifest.xml文件,建立 PackageParser.Package 結(jié)構(gòu),這個結(jié)構(gòu)保存了從 AndroidManifest.xml 解析出的package 的信息。對 package 進(jìn)行數(shù)字簽名及完整性校驗,
private PackageParser.Package scanPackageLI(File scanFile, int parseFlags, int scanMode)
{
????? //實例化一個 PackageParser 對象
????????? PackageParser pp = new PackageParser(scanPath);
?????? // parsePackage 也是一個重定義函數(shù),它主要做了三件事,一個是解析 apk 中的 asset下 的 文 件 , 一 個 是 解 析 res 下 的 文 件 。 然 后 通 過 重 定 義 函 數(shù)???? parsePackage(Resources res, XmlResourceParser parser, int flags, String[] outError) 對 apk 的AndroidManifest.xml 進(jìn)行解析,將每個標(biāo)簽對應(yīng)的信息添加到每個包的相關(guān)列表中,如將標(biāo)簽 application 下 的 activity 通 過 pkg.activities.add(a) 添 加 到 package 的 activities 列 表 , 將service 添加到 owner.services.add(s)。
???? PackageParser.Package pkg = pp.parsePackage(scanFile, scanPath, mMetrics, parseFlags);
??? //檢查這個 package 是否已經(jīng)存在,以及是否重命名過,以及該系統(tǒng) package 是否可以被更新,如果可以被更新,則對比系統(tǒng)分區(qū)和 data 分區(qū)的 package 版本,如果系統(tǒng)分區(qū)的
???? package 高于 data 分區(qū)的版本,則保留系統(tǒng)分區(qū)的 package
???? //對 package 進(jìn)行簽名認(rèn)證,如果是 system img 里的,只是通過 AndroidManifest.xml 獲得簽名,對簽名校驗,不會對全部文件進(jìn)行有效性檢查;否則,就要結(jié)合 META-INF/進(jìn)行
?????? 簽名和有效性校驗collectCertificatesLI(pp, ps, pkg, scanFile, parseFlags);
???? //調(diào)用重定義函數(shù)繼續(xù)進(jìn)行解析,將每個 apk 解析出的標(biāo)簽信息添加到全局的列表里。如將 每 個 apk 的 recervers 列 表 里 的 元 素 pkg.receivers.get(i), 通 過????????????????? mReceivers.addActivity(a,"receiver")添加到全局列表 mReceivers 里
???? return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE);
}
<補(bǔ)充知識>
res/raw 和 assets 區(qū)別
*res/raw 和 assets 的相同點:
??????????? 1. 兩者目錄下的文件在打包后會原封不動的保存在 apk 包中,不會被編譯成二進(jìn)制。
?*res/raw 和 assets 的不同點:
??????????? 1. res/raw 中 的 文 件 會 被 映 射 到 R.java 文 件 中 , 訪 問 的 時 候 直 接 使 用 資 源 ID 即R.id.filename ; assets 文 件 夾 下 的 文 件 不 會 被 映 射 到 R.java 中 , 訪 問 的? 時 候 需 要AssetManager 類。
??????? ? ? 2.res/raw 不可以有目錄結(jié)構(gòu),而 assets 則可以有目錄結(jié)構(gòu),也就是 assets 目錄下可以再建立文件夾
*讀取文件資源:
1.讀取 res/raw 下的文件資源,通過以下方式獲取輸入流來進(jìn)行寫操作InputStream is = getResources().openRawResource(R.id.filename);
2.讀取 assets 下的文件資源,通過以下方式獲取輸入流來進(jìn)行寫操作
AssetManager am = null;
am = getAssets();
InputStream is = am.open("filename");
(用于內(nèi)置文件但不知道文件名稱,需要篩選出想要的文件然后拷貝到目標(biāo)目錄中,推薦內(nèi)置在 assets 文件夾中)
1.res/raw 目錄:
通過反射的方式得到 R.java 里面 raw 內(nèi)部類里面所有的資源 ID 的名稱,然后通過名稱獲取資源 ID 的值來讀取我們想要的文件。
2.assets 目錄:
getAssets().list("");來獲取 assets 目錄下所有文件夾和文件的名稱,再通過這些名稱讀取我們想要的文件。另,在處理 asset 時,android 限制最大的數(shù)據(jù)是 1M,超出后會報錯誤。
</>
public Package parsePackage(File sourceFile, String destCodePath, DisplayMetrics metrics, int
flags)
{
????????? //解析/asset 下的文件
????????? assmgr = new AssetManager();
????????? int cookie = assmgr.addAssetPath(mArchiveSourcePath);
????????? parser = assmgr.openXmlResourceParser(cookie, "AndroidManifest.xml");
????????? //解析/Res 下的文件,通過 parsePackage 函數(shù)解析 AndroidManifest.xml 文件
????????? Resources res = new Resources(assmgr, metrics, null);
????????? pkg = parsePackage(res, parser, flags, errorText);
????????? // 設(shè)置代碼路徑和資源路徑
????????? pkg.mPath = destCodePath;
????????? pkg.mScanPath = mArchiveSourcePath;
}
Package parsePackage(Resources res, XmlResourceParser parser, int flags, String[] outError)
{
解析 AndroidManifest.xml 里的各個標(biāo)簽,并對 pkg 的 mVersionCode,mSharedUserId,mSharedUserLabel,installLocation 等 變 量 賦 值 。 對 于 application , permission-
group , permission , permission-tree , uses-permission , uses-configuration , uses-feature , uses-sdk , supports-screens , protected-broadcast , instrumentation , original-
package,adopt-permissions,eat-comment 等標(biāo)簽調(diào)用相關(guān)函數(shù)進(jìn)行處理 解析出每個標(biāo)簽下的子標(biāo)簽的信息,然后將這些信息添加到每個 package 的對應(yīng)列表中,如將 application 下的activity 通過 pkg.activities.add(a)添加到 package 的 activities 列表。
????? //將 pkg 返回
????? return pkg;
}
private PackageParser.Package scanPackageLI(PackageParser.Package pkg, int parseFlags, int
scanMode) {
?????? (1)Check all shared libraries and map to their actual file path.
?????? (2)check pkg.reqFeatures in mAvailableFeatures
?????? (3)Check and note if we are renaming from an original package name
?????? (4)Check if we are renaming from an original package name.
?????? 對于 original package 不是太了解,還需要繼續(xù)研究
?????? 判斷新裝應(yīng)用的 content providers 是否與已經(jīng)安裝應(yīng)用的產(chǎn)生沖突。
?????? if (mPlatformPackage == pkg) {//如果包名以 android 開頭的,則將應(yīng)用的 dataDir 設(shè)為/data/system
????????? // The system package is special.
????????? dataPath = new File (Environment.getDataDirectory(), "system");
????????? pkg.applicationInfo.dataDir = dataPath.getPath();
???? }else {
????????? // This is a normal package, need to make its data directory.
????????? dataPath = getDataPathForPackage(pkg);
???? if (dataPath.exists()) {//如果路徑存在,使用 FileUtils.getPermissions 獲取 dataPath 的權(quán)限,
????????? if (mOutPermissions[1] == pkg.applicationInfo.uid || !Process.supportsProcesses())
????????????? {
???????????????? pkg.applicationInfo.dataDir = dataPath.getPath();
????????????? } else {
?????????????????? mInstaller.remove(pkgName);//將該包刪除
?????????????????? mInstaller.install(pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.uid);
??????????????????? //重新安裝該應(yīng)用
????????????? }
???????????? pkg.applicationInfo.dataDir = dataPath.getPath();//dataDir 重新賦值
???? }
??? else
????????????? //如果路徑不存在則直接 install 安裝
???? {
??????????????? mInstaller.install(pkgName, pkg.applicationInfo.uid, pkg.applicationInfo.uid);
????? }
????? // Perform shared library installation and dex validation and
???? // optimization, if this is not a system app.
???? performDexOptLI(pkg, forceDex);
???????? //如果新的應(yīng)用已經(jīng)安裝,請求 ActivityManager 將舊的 kill 掉,以免使用時造成混亂
??????? if ((parseFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
????????? killApplication(pkg.applicationInfo.packageName,pkg.applicationInfo.uid);
???? }
????????? // Add the new setting to mSettings
????????? mSettings.insertPackageSettingLP(pkgSetting, pkg);
????????? // Add the new setting to mPackages
????????? mPackages.put(pkg.applicationInfo.packageName, pkg);
????????? // Make sure we don't accidentally delete its data.
????????? mSettings.mPackagesToBeCleaned.remove(pkgName);
????????? 以下將每個包的 provider,service,activity 等信息添加到全局列表中
????????? mServices.addService(s);
? mReceivers.addActivity(a, "receiver");
? mActivities.addActivity(a, "activity");
? mPermissionGroups.put(pg.info.name, pg);
? permissionMap.put(p.info.name, bp);
? mInstrumentation.put(a.getComponentName(), a);
? mProtectedBroadcasts.add(pkg.protectedBroadcasts.get(i));
}

總結(jié)

以上是生活随笔為你收集整理的Android system server之PackageManagerService详细分析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。