當
PMS
筆記大小寫到106kb
時,就知大事不妙,導讀叒叒叒來了java
不得已,將本來計劃一篇結束的文章分爲了以下三部分:android
前兩篇主要梳理了PMS
初始化的流程和初始化的一些細節;最後一篇對應用的安裝過程進行了簡單梳理。shell
有沒有注意梳理
字眼,關於想要深刻全面學習PMS
的同窗只能很是抱歉,本系列文章也僅僅是起到的主要流程的梳理做用。緩存
咱們先從總體上掌握,等後面遇到相關需求再來仔細研究吧(這波安慰很及時。。。。)markdown
整個模塊學習下來,簡單對PackageManagerService
吐槽一下:app
PMS
中涉及的類比較多,真正掌握須要一番時間和精力
Package
相關、Session
相關、Settings
等等PMS
的方法有點拆俄羅斯套娃
的感受,一層又一層。。。。權限
和用戶
的邏輯判斷有了上面的預期,歡迎來到PackageManagerService
的世界ide
PackageManagerService
類
PackageManagerService
代碼行數在24000
行。。。。。函數
Android
的應用管理主要是經過PackageManagerService
來完成的。PackageManagerService
負責各類APK
包的安裝、卸載、優化和查詢。oop
Android
中的應用能夠簡單分爲兩大類:系統應用
和普通應用
:post
系統應用
是指位於/system/app
和/system/priv-app
目錄下的應用
/system/priv-app
是從Android 4.4
開始出現的目錄,存放的是一些系統底層的應用,如:Settings
、SystemUI
等/system/app
存放的則是一些系統級的應用,如Calendar
、Contacts
等普通應用
是用戶安裝的應用,位於目錄/data/app
下PackageManagerService
在啓動時會掃描全部APK
文件和Jar
包,而後把它們的信息讀取到內存中,這樣系統在運行時就能迅速找到各類應用和組件信息。
掃描過程若是遇到沒有優化的文件,還要執行優化操做。
從
Android 5.0
開始引入了ART
,ART
使用預先 (AOT
) 編譯,而且從Android 7.0
開始結合使用AOT
、即時 (JIT) 編譯
和配置文件引導型編譯
來優化應用的啓動和執行效率
不着急直接分析源代碼,咱們先從使用的角度簡單瞭解下
在應用中,若是要使用PackageManagerService
服務,一般是調用Context
的getPackageManager()
方法,內容以下:
public PackageManager getPackageManager() {
if (mPackageManager != null) {
return mPackageManager;
}
IPackageManager pm = ActivityThread.getPackageManager();
if (pm != null) {
// Doesn't matter if we make more than one instance.
return (mPackageManager = new ApplicationPackageManager(this, pm));
}
return null;
}
複製代碼
調用到了ActivityThread.getPackageManager()
的方法:
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
IBinder b = ServiceManager.getService("package");
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
複製代碼
從這兩個getPackageManager()
方法的代碼中能夠看到:
返回的是ApplicationPackageManager
對象,這個對象建立時使用了IPackageManager
對象做爲參數
IPackageManager
對象是PackageManagerService
的Binder
代理對象ApplicationPackageManager
繼承自PackageManager
,在PackageManager
中定義了應用能夠訪問PackageManagerService
的全部接口
PackageManager
關係圖以下:
而對於PackageManagerService
類來講,有兩個重要成員變量:
mInstallerService
:類PackageInstallerService
的實例對象。Android
經過PackageInstallerService
來管理應用的安裝過程。
PackageInstallerService
也是一個Binder
服務,對應的代理對象是PackageInstaller
mInstaller
:類Installer
的實例對象。類結構相對簡單,有一個IInstalld mInstalld
變量,經過Binder調用
來和installd
進程通訊
apk
文件格式轉換、創建數據目錄等工做最後都是由installd
進程來完成的上述這幾個對象之間的關係圖以下:
Settings
類和packages.xml
在開始分析PackageManagerService
前,咱們要先看下Settings
類,這個類用來保存和PackageManagerService
相關的一些設置,它保存的內容在解析應用時會用到。
先看看com.android.server.pm.Settings
類的構造方法:
Settings(File dataDir, PermissionSettings permission, Object lock) {
// 省略權限相關的處理
......
// 在data目錄下建立system目錄
mSystemDir = new File(dataDir, "system");
mSystemDir.mkdirs();
// 設置目錄的屬性爲0775
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
mSettingsFilename = new File(mSystemDir, "packages.xml");
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
mPackageListFilename = new File(mSystemDir, "packages.list");
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
......
// Deprecated: Needed for migration
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
}
複製代碼
Settings
類的構造方法會在/data
目錄下建立system
目錄用來保存一些系統配置文件。建立了5個位於目錄/data/system
的File
對象:
packages.xml
:記錄系統中全部安裝的應用信息,包括基本信息、簽名和權限。packages-backup.xml
:packages.xml
文件的備份packages.list
:保存普通應用的數據目錄和uid
等信息packages-stopped.xml
:記錄系統中被強制中止運行的應用信息。系統在強制中止某個應用時,會將應用的信息記錄到文件中packages-stopped-backup.xml
:packages-stopped.xml
文件的備份packages-backup.xml
和packages-stopped-backup.xml
是備份文件。關於備份文件的邏輯是:
packages.xml
和packages-stopped.xml
寫以前,會把他們備份packages.xml
是PackageManagerService
啓動時須要用到的文件,咱們先看看文件的格式:
<package name="com.android.providers.telephony" codePath="/system/priv-app/TelephonyProvider" nativeLibraryPath="/system/priv-app/TelephonyProvider/lib" publicFlags="1007402501" privateFlags="8" ft="11e8dc5d800" it="11e8dc5d800" ut="11e8dc5d800" version="28" sharedUserId="1001" isOrphaned="true">
<sigs count="1" schemeVersion="3">
<cert index="0" />
</sigs>
<perms>
<item name="android.permission.USE_RESERVED_DISK" granted="true" flags="0" />
<item name="android.permission.INTERACT_ACROSS_USERS_FULL" granted="true" flags="0" />
<item name="android.permission.INTERACT_ACROSS_USERS" granted="true" flags="0" />
<item name="android.permission.MODIFY_PHONE_STATE" granted="true" flags="0" />
</perms>
<proper-signing-keyset identifier="1" />
</package>
複製代碼
上面是文件中的一個<package/>
標籤,表示一個應用的基本信息、簽名和聲明的權限,從內容來看基本都是解析AndroidManifest.xml
的內容。
咱們看下主要屬性和標籤:
name
表示應用的包名codePath
表示apk
文件的位置nativeLibraryPath
表示應用的native
庫的儲存路徑it
表示應用安裝時間ut
表示最後一次修改的時間version
表示應用的版本號sharedUserId
表示應用用來共享的用戶IDuserId
表示應用所屬的用戶ID<sign/>
表示應用的簽名
count
表示標籤中包含有多少個證書<cert/>
表示具體證書的值<perms/>
表示應用聲明使用的權限
<item/>
表明一項權限除了<package/>
標籤,packages.xml
中還可能存在一下標籤:
<updated-package/>
:記錄系統應用升級的狀況。當安裝了一個包名相同、版本號更高的應用後,Android
會經過此標籤記錄被覆蓋的系統應用的信息。<renamed-package/>
:記錄變動應用包名的狀況。
AndroidManifest.xml
中使用屬性package
來指定,同時在AndroidManifest.xml
中還能夠用<original-package>
來指定原始包名,對於這種狀況:
Android
會經過<renamed-package/>
標籤來記錄這種更名的狀況。<cleaning-package/>
:用來記錄那些已經刪除,可是數據目錄還暫時保留的應用的信息對於<package/>
和<updated-package/>
標籤,解析後的數據將保存在PackageSetting
的對象中。PackageSetting
類的繼承關係圖以下:
PackageSetting
繼承了PackageSettingBase
類,PackageSettingBase
又繼承了SettingBase
類
PackageSettingBase
類的成員變量中SettingBase
的mPermissionState
中SharedUserSetting
類的成員變量signatures
SharedUserSetting
用來描述具備相同sharedUserId
的應用信息
packages
是用來保存全部具備相同sharedUserId
應用對象的集合signatures
保存便可表明標籤<package/>
的PackageSetting
對象都會保存在Settings
的成員變量mPackages
中,定義以下:
final ArrayMap<String, PackageSetting> mPackages = new ArrayMap<>();
複製代碼
表明標籤<updated-package/>
的PackageSetting
對象都會保存在Settings
的成員變量mDisabledSysPackages
中,定義以下:
private final ArrayMap<String, PackageSetting> mDisabledSysPackages = new ArrayMap<String, PackageSetting>();
複製代碼
表明標籤<cleaning-package/>
的PackageSetting
對象都會保存在Settings
的成員變量mPackagesToBeCleaned
中,定義以下:
final ArrayList<PackageCleanItem> mPackagesToBeCleaned = new ArrayList<PackageCleanItem>();
複製代碼
表明標籤<renamed-package/>
的PackageSetting
對象都會保存在Settings
的成員變量mRenamedPackages
中,定義以下:
private final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>();
複製代碼
這四個對象在PackageManagerService
中會常常遇到,爲了方便後面的理解,請記一下哈
PackageManagerService
的初始化有了前面的鋪墊,咱們來看下PackageManagerService
的初始化過程。
PackageManagerService
是在SystemServer
中初始化的,分別在startBootstrapServices()
和startOtherServices()
中都進行了一些處理。相關代碼以下:
private void startBootstrapServices() {
......
// 啓動 installd,PMS依賴此服務
Installer installer = mSystemServiceManager.startService(Installer.class);
......
// 判斷vold.decrypt是否被設定爲加密狀態
// mOnlyCore=true表示加密狀態,只能處理系統應用
// 通常狀況mOnlyCore爲false
String cryptState = SystemProperties.get("vold.decrypt");
if (ENCRYPTING_STATE.equals(cryptState)) {
Slog.w(TAG, "Detected encryption in progress - only parsing core apps");
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
Slog.w(TAG, "Device encrypted - only parsing core apps");
mOnlyCore = true;
}
// 調用main()初始化PMS
mPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
mFirstBoot = mPackageManagerService.isFirstBoot();
......
// 若是設備沒有加密,嘗試啓動 OtaDexoptService
// OtaDexoptService 是用於A/B更新的一個服務,會用到PMS
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
OtaDexoptService.main(mSystemContext, mPackageManagerService);
}
}
......
}
private void startOtherServices() {
if (!mOnlyCore) {
......
// 進行dex優化
mPackageManagerService.updatePackagesIfNeeded();
}
......
// 進行磁盤維護
mPackageManagerService.performFstrimIfNeeded();
......
// PMS 準備就緒
mPackageManagerService.systemReady();
}
複製代碼
上面就是SystemServer
中和PackageManagerService
啓動相關的操做, 咱們先看下PackageManagerService
的main()
方法
PackageManagerService
的main()
方法main()
方法內容以下:
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
// Self-check for initial settings.
PackageManagerServiceCompilerMapping.checkProperties();
// 建立 PackageManagerService 對象
PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore);
// 啓用部分系統應用
m.enableSystemUserPackages();
// 將服務添加到ServiceManager
// 包括package和package_native
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
複製代碼
main()
方法比較簡單,主要進行了:
PackageManagerService
對象
PackageManagerNative
對象,只是簡單提供了三個功能接口
String[] getNamesForUids
String getInstallerForPackage
long getVersionCodeForPackage
ServiceManager
咱們來重點看下PackageManagerService
的建立過程,也就是構造方法。
PackageManagerService
的構造方法PackageManagerService
的構造方法比較長,根據構造方法中的EventLogTags
咱們能夠劃分爲5
個階段:
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
......
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
......
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);
......
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis());
......
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis());
......
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
......
}
複製代碼
BOOT_PROGRESS_PMS_START
BOOT_PROGRESS_PMS_START
階段主要進行了:
DisplayMetrics
對象、設置Installer
引用PermissionManager
對象permission
信息建立Settings
對象,並添加部分uid
信息DexManager
對象跟蹤dex
使用狀況SystemConfig
對象用來獲取系統配置信息,如:共享庫列表、權限等PackageHandler
對象,實際上是一個HandlerThread
類,並添加到Watchdog
data
分區具體代碼以下:
// ###### BOOT_PROGRESS_PMS_START 階段 ######
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,SystemClock.uptimeMillis());
// 檢測SDK版本
if (mSdkVersion <= 0) {
Slog.w(TAG, "**** ro.build.version.sdk not set!");
}
mContext = context;
// 是否爲工廠模式,工廠模式主要用於系統功能檢測
// 能夠進行一些按鍵轉義等操做,正式產品通常都爲false
mFactoryTest = factoryTest;
// 是否只處理系統應用,通常爲false
mOnlyCore = onlyCore;
// 建立DisplayMetrics對象儲存屏幕顯示信息
mMetrics = new DisplayMetrics();
// 設置installer
mInstaller = installer;
// Create sub-components that provide services / data. Order here is important.
synchronized (mInstallLock) {
synchronized (mPackages) {
// Expose private service for system components to use.
// 添加PackageManagerInternal到本地服務
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());
// 初始化多用戶管理服務
sUserManager = new UserManagerService(......);
// 初始化權限管理服務
mPermissionManager = PermissionManagerService.create(......);
mDefaultPermissionPolicy = mPermissionManager.getDefaultPermissionGrantPolicy();
// 建立Settings對象
mSettings = new Settings(mPermissionManager.getPermissionSettings(), mPackages);
}
}
// 經過addSharedUserLPw方法添加SharedUserSetting對象到Settings中
// sharedUserId 屬性相同的包能夠運行在同一個進程,或者能夠相互讀取資源
// 這裏添加了一共是7種系統的 uid:system、phone、log、nfc、bluetooth、shell、se
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
......
// 建立dexopt命令的幫助類
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
DexManager.Listener dexManagerListener = DexLogger.getListener(this,
installer, mInstallLock);
// 建立 DexManager 用來跟蹤dex文件的使用狀況
mDexManager = new DexManager(mContext, this, mPackageDexOptimizer, installer, mInstallLock, dexManagerListener);
// 建立ART管理服務
mArtManagerService = new ArtManagerService(mContext, this, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
......
// 獲取默認屏幕參數
getDefaultDisplayMetrics(context, mMetrics);
// 建立 SystemConfig 對象,用來保存系統全局配置信息
SystemConfig systemConfig = SystemConfig.getInstance();
mAvailableFeatures = systemConfig.getAvailableFeatures();
......
synchronized (mInstallLock) {
// writer
synchronized (mPackages) {
// 建立用來處理消息的線程,並添加到Watchdog中監控
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
mHandler = new PackageHandler(mHandlerThread.getLooper());
......
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
// 建立即時應用管理模塊
mInstantAppRegistry = new InstantAppRegistry(this);
// 經過 systemConfig 獲取系統中的共享庫列表
ArrayMap<String, String> libConfig = systemConfig.getSharedLibraries();
final int builtInLibCount = libConfig.size();
for (int i = 0; i < builtInLibCount; i++) {
String name = libConfig.keyAt(i);
String path = libConfig.valueAt(i);
addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
}
// 打開 SELinux 的 Policy 文件:
// 1. /security/mac_permissions.xml
// 2. /etc/security/mac_permissions.xml
SELinuxMMAC.readInstallPolicy();
......
// 讀取packages.xml文件,解析後將數據存放到mSettings中
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
// Clean up orphaned packages for which the code path doesn't exist
......
if (mFirstBoot) {
// 若是是首次啓動
// 向Init進程請求(經過setProp的方式)
// 將預編譯dex拷貝到data分區
requestCopyPreoptedFiles();
}
}
}
複製代碼
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
階段主要進行:
BOOTCLASSPATH
和SYSTEMSERVERCLASSPATH
以及系統版本信息Android M
以前版本需調整邏輯爲運行時獲取Android N
以前版本須要調整爲首次啓動vendor
,product
的overlay
目錄,收集文件信息vendor
,product
,system
,oem
等分區下的app
和priv-app
目錄,收集應用信息,並將蒐集到的信息保存到mPackages
中PMS
中的mPackages
集合與mSettings
中的mPackages
集合進行比對,過濾掉無效的應用SharedUserSetting
對象相關代碼以下:
// ###### BOOT_PROGRESS_PMS_SYSTEM_SCAN_START 階段 ######
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, startTime);
final String bootClassPath = System.getenv("BOOTCLASSPATH");
final String systemServerClassPath = System.getenv("SYSTEMSERVERCLASSPATH");
......
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade = !Build.FINGERPRINT.equals(ver.fingerprint);
......
// 對於Android M以前版本升級上來的狀況,需將系統應用程序權限從安裝升級到運行時
mPromoteSystemApps = mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
// 對於Android N以前版本升級上來的狀況,需像首次啓動同樣處理package
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
// 掃描前保存已經存在的系統 packages,系統升級後需從新申請權限
// save off the names of pre-existing system packages prior to scanning; we don't
// want to automatically grant runtime permissions for new system apps
if (mPromoteSystemApps) {
Iterator<PackageSetting> pkgSettingIter = mSettings.mPackages.values().iterator();
while (pkgSettingIter.hasNext()) {
PackageSetting ps = pkgSettingIter.next();
if (isSystemApp(ps)) {
mExistingSystemPackages.add(ps.name);
}
}
}
// 準備解析package緩存
mCacheDir = preparePackageParserCache(mIsUpgrade);
......
// 經過scanDirTracedLI掃描指定目錄的應用信息,包括:
// vendor/overlay、/product/overlay
// system/framework、system/priv-app、/system/app
// vendor/priv-app、/vendor/app
// odm/priv-app、/odm/app、
// product/priv-app、/product/app
// 並將相關的應用信息保存到mPackages中
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR),...);
scanDirTracedLI(new File(PRODUCT_OVERLAY_DIR),...);
.....
// Prune any system packages that no longer exist.
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<>();
// Stub packages must either be replaced with full versions in the /data
// partition or be disabled.
final List<String> stubSystemApps = new ArrayList<>();
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
final Iterator<PackageParser.Package> pkgIterator = mPackages.values().iterator();
while (pkgIterator.hasNext()) {
final PackageParser.Package pkg = pkgIterator.next();
if (pkg.isStub) {
stubSystemApps.add(pkg.packageName);
}
}
// 循環處理mSettings.mPackages中的應用信息
final Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
// 忽略普通應用
continue;
}
// 請注意,此處的mPackages是在PMS中的成員變量
// 裏面存放的是scanDir掃描目錄後獲得的應用信息
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
// 若是mPackages的系統應用是待升級包的,把它從mPackages中移除
// disable說明是<update-package/>標籤表示的應用
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
// 從掃描表mPackages中移除
removePackageLI(scannedPkg, true);
// 將其添加到mExpectingBetter集合中
// 在下一階段會處理
mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
}
// 執行到此處說明mPackages中沒有ps應用信息
// 也就是系統中不存在該應用
// 檢查是否屬於<update-package/>標籤
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
// 不屬於<update-package/>標籤,說明是殘留在packages.xml中的
// 移除,後面還會進行數據清理
psit.remove();
} else {
// 應用屬於<update-package/>標籤
// 添加到 possiblyDeletedUpdatedSystemApps 集合中
......
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
//delete tmp files
deleteTempPackageFiles();
final int cachedSystemApps = PackageParser.sCachedPackageReadCount.get();
// 刪除mSettings中沒有關聯任何應用的SharedUserSetting對象
mSettings.pruneSharedUsersLPw();
final long systemScanTime = SystemClock.uptimeMillis() - startTime;
......
複製代碼
BOOT_PROGRESS_PMS_DATA_SCAN_START
BOOT_PROGRESS_PMS_DATA_SCAN_START
主要進行了:
/data/app
和/data/app-private
下的應用信息,並添加到mPackages
中possiblyDeletedUpdatedSystemApps
集合,並逐一將其從Settings
的中disabledSystemPackage
集合中刪除
possiblyDeletedUpdatedSystemApps
集合中存放的是在packages.xml
文件中被標記成了<update-package/>
,可是應用文件還未找到的應用mExpectingBetter
集合。
mExpectingBetter
集合中存放的是在packages.xml
文件中被標記成了<update-package/>
,資料數據齊全,不能直接啓動,須要配合用戶目錄下的完整版應用才能啓動/data
、/vendor
、/system
等目錄查找,找到後將其掃描到mPackages
集合中StorageManager
和SetupWizard
包名,更新全部應用的動態庫路徑具體代碼以下:
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START, SystemClock.uptimeMillis());
// 掃描 /data/app 目錄,收集應用信息
scanDirTracedLI(sAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
// 掃描 /data/app-private 目錄,收集應用信息
scanDirTracedLI(sDrmAppPrivateInstallDir, mDefParseFlags
| PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
// possiblyDeletedUpdatedSystemApps中存放的應用是在packages.xml文件中被標記成了已升級的系統應用,可是文件卻不在了
// 所以這裏檢查用戶目錄下的升級文件是否存在,而後進行處理
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
// 先將應用從<update-package/>集合中移除
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
final String msg;
if (deletedPkg == null) {
// 用戶安裝目錄也不存在該升級文件
msg = "Updated system package " + deletedAppName
+ " no longer exists; removing its data";
} else {
// 用戶空間找到了升級文件,說明系統目錄下的文件可能被刪除了
// 所以,把應用的系統屬性去掉,以普通應用的方式運行
msg = "Updated system package + " + deletedAppName
+ " no longer exists; revoking system privileges";
final PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
......
}
// 放到 mExpectingBetter 列表中的應用是帶有升級包的
// 在上一階段解析時把它們從 mPackages 列表中已經移除並放到了 mExpectingBetter 列表中
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
final File scanFile = mExpectingBetter.valueAt(i);
final @ParseFlags int reparseFlags;
final @ScanFlags int rescanFlags;
// 從下面路徑中查找應用
if (FileUtils.contains(privilegedAppDir, scanFile)) {
.....
} else if (FileUtils.contains(systemAppDir, scanFile)) {
......
} else if (FileUtils.contains(privilegedVendorAppDir, scanFile)
|| FileUtils.contains(privilegedOdmAppDir, scanFile)) {
......
} else if (FileUtils.contains(vendorAppDir, scanFile)
|| FileUtils.contains(odmAppDir, scanFile)) {
......
} else if (FileUtils.contains(oemAppDir, scanFile)) {
......
} else if (FileUtils.contains(privilegedProductAppDir, scanFile)) {
......
} else if (FileUtils.contains(productAppDir, scanFile)) {
......
} else {
// 若是沒找到,不作任何處理
continue;
}
mSettings.enableSystemPackageLPw(packageName);
try {
// 掃描並處理該應用
scanPackageTracedLI(scanFile, reparseFlags, rescanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: " + e.getMessage());
}
}
}
// 此時用戶空間的掃描基本都已經完成
// 解壓安裝 stub system app
decompressSystemApplications(stubSystemApps, scanFlags);
......
}
mExpectingBetter.clear();
// 獲取StorageManager包名
mStorageManagerPackage = getStorageManagerPackageName();
// 獲取SetupWizard 包名(開機引導)
mSetupWizardPackage = getSetupWizardPackageName();
......
// 更新全部應用的動態庫路徑
updateAllSharedLibrariesLPw(null);
......
// Now that we know all the packages we are keeping,
// read and update their last usage times.
mPackageUsage.read(mPackages);
mCompilerStats.read();
複製代碼
BOOT_PROGRESS_PMS_SCAN_END
BOOT_PROGRESS_PMS_SCAN_END
階段的主要進行了:
SDK
版本,更新應用權限Android M
升級後正常啓動)設置默認首選應用UUID_DEFAULT
捲上的核心繫統應用包名,並準備相關的應用數據cache
清理mSetting
中的數據更新到packages.xml
中主要代碼以下:
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END, SystemClock.uptimeMillis());
// 若是平臺的SDK版本和上次啓動時相比發生了變化,可能permission的定義也改變了
// 所以須要從新賦予應用權限
final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion);
mPermissionManager.updateAllPermissions(
StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(),
mPermissionCallback);
ver.sdkVersion = mSdkVersion;
// If this is the first boot or an update from pre-M, and it is a normal
// boot, then we need to initialize the default preferred apps across
// all defined users.
// 根據條件設定默認的首選應用
if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
......
// 獲取 UUID_DEFAULT 上的核心繫統應用包名集合
List<String> deferPackages = reconcileAppsDataLI(StorageManager.UUID_PRIVATE_INTERNAL, UserHandle.USER_SYSTEM, storageFlags, true /* migrateAppData */, true /* onlyCoreApps */);
// 爲deferPackages集合中的應用準備應用數據
mPrepareAppDataFuture = SystemServerInitThreadPool.get().submit(...);
......
// 若是是執行OTA後的首次啓動,須要清除cache
if (mIsUpgrade && !onlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// No apps are running this early, so no need to freeze
clearAppDataLIF(...);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
......
// 把 mSettings 內容保存到 packages.xml
mSettings.writeLPr();
複製代碼
BOOT_PROGRESS_PMS_READY
BOOT_PROGRESS_PMS_READY
階段內容比較簡單,方法內容以下:
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis());
......
// 建立 PackageInstallerService
mInstallerService = new PackageInstallerService(context, this);
......
// 獲取每一個user對應的已安裝應用信息,填充到userPackages中
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
for (int userId : currentUserIds) {
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
// 將userPackages添加到 mDexManager 中用來跟蹤dex使用信息
mDexManager.load(userPackages);
......
// 觸發垃圾回收
Runtime.getRuntime().gc();
......
複製代碼
PMS
構造方法總結PackageManagerService
構造方法的執行過程就是:
packages.xml
文件內容,解析並保存在成員變量mSettings
中。
PMS
的mPackages
中。
packages.xml
文件調用時序圖以下(爲了簡潔,移除了部分方法):
startOtherServices()
中的PMS
操做前面已經介紹,在startOtherServices()
中,PMS
還進行了以下三個操做:
mPackageManagerService.updatePackagesIfNeeded()
:檢查是否須要更新package
mPackageManagerService.performFstrimIfNeeded()
:執行磁盤清理,釋放空間mPackageManagerService.systemReady()
:執行一些默認權限的檢查和package
信息更新操做以及進行一些相關服務的狀態通知(*.systemReady()
)咱們簡單來看下
updatePackagesIfNeeded()
updatePackagesIfNeeded()
用來檢查是否須要去更新packages
並進行dex
優化
方法內容以下,註釋比較詳細:
public void updatePackagesIfNeeded() {
enforceSystemOrRoot("Only the system can request package update");
// We need to re-extract after an OTA.
boolean causeUpgrade = isUpgrade();
// First boot or factory reset.
boolean causeFirstBoot = isFirstBoot() || mIsPreNUpgrade;
// We need to re-extract after a pruned cache, as AoT-ed files will be out of date.
boolean causePrunedCache = VMRuntime.didPruneDalvikCache();
// 若是不是:OTA、首次啓動、升級到Android N、虛擬機緩存調整
// 直接返回
if (!causeUpgrade && !causeFirstBoot && !causePrunedCache) {
return;
}
List<PackageParser.Package> pkgs;
synchronized (mPackages) {
// 獲取安裝的Package集合
pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
}
final long startTime = System.nanoTime();
// 執行升級操做
final int[] stats = performDexOptUpgrade(pkgs, mIsPreNUpgrade /* showDialog */,
causeFirstBoot ? REASON_FIRST_BOOT : REASON_BOOT,
false /* bootComplete */);
......
}
複製代碼
真正執行升級的方法是performDexOptUpgrade()
,咱們看下:
private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, ...) {
......
final int numberOfPackagesToDexopt = pkgs.size();
for (PackageParser.Package pkg : pkgs) {
numberOfPackagesVisited++;
boolean useProfileForDexopt = false;
if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
// 針對系統app,若是是首次啓動或者升級的狀態
// 先檢測應用的initial preopt profiles是否存在
if (profileFile.exists()) {
......
// 文件存在的話,經過Installer拷貝文件
mInstaller.copySystemProfile(profileFile.getAbsolutePath(), ...);
} else {
// 文件不存在,檢查<update-package/>標籤中的應用
PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
if (disabledPs != null && disabledPs.pkg.isStub) {
// 若是標籤中存在,而且應用類型是Stub,查找特殊路徑
String systemProfilePath = getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
profileFile = new File(systemProfilePath);
......
mInstaller.copySystemProfile(profileFile.getAbsolutePath(),...);
}
}
}
if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
......
// 若是應用不支持優化,直接跳過
continue;
}
......
// performDexOptTraced的調用關係及其噁心
// 跟蹤代碼,最後調用的是
// PackageDexOptimizer 類 dexOptPath 函數
// 函數經過mInstaller.dexopt()函數來進行轉化
// mInstaller.dexopt() 經過 Binder 遠程調用installd服務
performDexOptTraced(new DexoptOptions(
pkg.packageName,
pkgCompilationReason,
dexoptFlags));
......
}
......
}
複製代碼
performFstrimIfNeeded()
performFstrimIfNeeded()
用來進行磁盤清理工做,相關代碼以下:
public void performFstrimIfNeeded() {
enforceSystemOrRoot("Only the system can request fstrim");
// Before everything else, see whether we need to fstrim.
try {
// 獲取StorageManagerService對象
IStorageManager sm = PackageHelper.getStorageManager();
if (sm != null) {
boolean doTrim = false;
// 讀取fstrim的間隔,默認3天
final long interval = android.provider.Settings.Global.getLong(
mContext.getContentResolver(),
android.provider.Settings.Global.FSTRIM_MANDATORY_INTERVAL,
DEFAULT_MANDATORY_FSTRIM_INTERVAL);
if (interval > 0) {
// 判斷間隔
final long timeSinceLast = System.currentTimeMillis() - sm.lastMaintenance();
if (timeSinceLast > interval) {
doTrim = true;
}
}
if (doTrim) {
......
// runMaintenance先經過sm的發送H_FSTRIM消息給Handler
// 而後mVold對象經過binder調用vold進程的fstrim函數
sm.runMaintenance();
}
} else {
Slog.e(TAG, "storageManager service unavailable!");
}
} catch (RemoteException e) {
// Can't happen; StorageManagerService is local
}
}
複製代碼
systemReady()
systemReady()
主要進行的是權限相關的更新操做,以及一些服務狀態的變動。
相關代碼以下:
@Override
public void systemReady() {
enforceSystemOrRoot("Only the system can claim the system is ready");
mSystemReady = true;
...... // 省略一個和InstantApp相關的 ContentObserver
CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), this, mContext.getContentResolver(), UserHandle.USER_SYSTEM);
......
// 獲取並設置 compatibilityModeEnabled 兼容模式
boolean compatibilityModeEnabled = android.provider.Settings.Global.getInt(
mContext.getContentResolver(),
android.provider.Settings.Global.COMPATIBILITY_MODE, 1) == 1;
PackageParser.setCompatibilityModeEnabled(compatibilityModeEnabled);
......
int[] grantPermissionsUserIds = EMPTY_INT_ARRAY;
synchronized (mPackages) {
// 檢查PreferredActivity是否存在,及時清理不存在的
ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>();
for (int i=0; i<mSettings.mPreferredActivities.size(); i++) {
......
}
// 檢查用戶權限,將不是默認權限的userID添加到 grantPermissionsUserIds 集合中
for (int userId : UserManagerService.getInstance().getUserIds()) {
if (!mSettings.areDefaultRuntimePermissionsGrantedLPr(userId)) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
}
}
sUserManager.systemReady();
// 設置爲默認權限
for (int userId : grantPermissionsUserIds) {
mDefaultPermissionPolicy.grantDefaultPermissions(userId);
}
......
// 更新權限
synchronized (mPackages) {
mPermissionManager.updateAllPermissions(
StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(),
mPermissionCallback);
}
// 發送systemReady通知
if (mPostSystemReadyMessages != null) {
for (Message msg : mPostSystemReadyMessages) {
msg.sendToTarget();
}
mPostSystemReadyMessages = null;
}
// 註冊外部儲存設備監聽
final StorageManager storage = mContext.getSystemService(StorageManager.class);
storage.registerListener(mStorageListener);
// 發送關聯服務的 systemReady 通知
mInstallerService.systemReady();
mDexManager.systemReady();
mPackageDexOptimizer.systemReady();
// 獲取 StorageManager 服務並添加相關的狀態通知策略
StorageManagerInternal StorageManagerInternal = LocalServices.getService(
StorageManagerInternal.class);
StorageManagerInternal.addExternalStoragePolicy(...);
// Now that we're mostly running, clean up stale users and apps
sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL);
reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL);
// 發送 PermissionManager 的 systemReady 通知
mPermissionManager.systemReady();
......
}
複製代碼
到這裏,PMS
的初始化主要過程就梳理完了,整個流程仍是比較長的,不少細節作了忽略,接下來咱們從三個方面來看下PMS
初始化細節:
permission
文件處理APK
文件的解析過程下一篇深刻Android系統(十)PMS-2-初始化的一些細節