相關文章 Android包管理機制系列html
PMS的建立過程分爲兩個部分進行講解,分別是SyetemServer處理部分和PMS構造方法。其中SyetemServer處理部分和AMS和WMS的建立過程是相似的,能夠將它們進行對比,這樣能夠更好的理解和記憶這一知識點。前端
PMS是在SyetemServer進程中被建立的,SyetemServer進程用來建立系統服務,不瞭解它的能夠查看Android系統啓動流程(三)解析SyetemServer進程啓動過程這篇文章。 從SyetemServer的入口方法main方法開始講起,以下所示。 frameworks/base/services/java/com/android/server/SystemServer.javajava
public static void main(String[] args) {
new SystemServer().run();
}
複製代碼
main方法中只調用了SystemServer的run方法,以下所示。 frameworks/base/services/java/com/android/server/SystemServer.javaandroid
private void run() {
try {
...
//建立消息Looper
Looper.prepareMainLooper();
//加載了動態庫libandroid_servers.so
System.loadLibrary("android_servers");//1
performPendingShutdown();
// 建立系統的Context
createSystemContext();
// 建立SystemServiceManager
mSystemServiceManager = new SystemServiceManager(mSystemContext);//2
mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
SystemServerInitThreadPool.get();
} finally {
traceEnd();
}
try {
traceBeginAndSlog("StartServices");
//啓動引導服務
startBootstrapServices();//3
//啓動核心服務
startCoreServices();//4
//啓動其餘服務
startOtherServices();//5
SystemServerInitThreadPool.shutdown();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
traceEnd();
}
...
}
複製代碼
在註釋1處加載了動態庫libandroid_servers.so。接下來在註釋2處建立SystemServiceManager,它會對系統的服務進行建立、啓動和生命週期管理。在註釋3中的startBootstrapServices方法中用SystemServiceManager啓動了ActivityManagerService、PowerManagerService、PackageManagerService等服務。在註釋4處的startCoreServices方法中則啓動了DropBoxManagerService、BatteryService、UsageStatsService和WebViewUpdateService。註釋5處的startOtherServices方法中啓動了CameraService、AlarmManagerService、VrManagerService等服務。這些服務的父類均爲SystemService。從註釋三、四、5的方法能夠看出,官方把系統服務分爲了三種類型,分別是引導服務、核心服務和其餘服務,其中其餘服務是一些非緊要和一些不須要當即啓動的服務。這些系統服務總共有100多個,咱們熟知的AMS屬於引導服務,WMS屬於其餘服務, 本文要講的PMS屬於引導服務,所以這裏列出引導服務以及它們的做用,見下表。git
引導服務 | 做用 |
---|---|
Installer | 系統安裝apk時的一個服務類,啓動完成Installer服務以後才能啓動其餘的系統服務 |
ActivityManagerService | 負責四大組件的啓動、切換、調度。 |
PowerManagerService | 計算系統中和Power相關的計算,而後決策系統應該如何反應 |
LightsService | 管理和顯示背光LED |
DisplayManagerService | 用來管理全部顯示設備 |
UserManagerService | 多用戶模式管理 |
SensorService | 爲系統提供各類感應器服務 |
PackageManagerService | 用來對apk進行安裝、解析、刪除、卸載等等操做 |
查看啓動引導服務的註釋3處的startBootstrapServices方法。 frameworks/base/services/java/com/android/server/SystemServer.javagithub
private void startBootstrapServices() {
...
traceBeginAndSlog("StartPackageManagerService");
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);//1
mFirstBoot = mPackageManagerService.isFirstBoot();//2
mPackageManager = mSystemContext.getPackageManager();
traceEnd();
...
}
複製代碼
註釋1處的PMS的main方法主要用來建立PMS,其中最後一個參數mOnlyCore表明是否只掃描系統的目錄,它在本篇文章中會出現屢次,通常狀況下它的值爲false。註釋2處獲取boolean類型的變量mFirstBoot,它用於表示PMS是否首次被啓動。mFirstBoot是後續WMS建立時所須要的參數,從這裏就能夠看出系統服務之間是有依賴關係的,它們的啓動順序不能隨意被更改。緩存
PMS的main方法以下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java架構
public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
PackageManagerServiceCompilerMapping.checkProperties();
PackageManagerService m = new PackageManagerService(context, installer,
factoryTest, onlyCore);
m.enableSystemUserPackages();
ServiceManager.addService("package", m);
return m;
}
複製代碼
main方法主要作了兩件事,一個是建立PMS對象,另外一個是將PMS註冊到ServiceManager中。 PMS的構造方法大概有600多行,分爲5個階段,每一個階段會打印出相應的EventLog,EventLog用於打印Android系統的事件日誌。app
PMS的構造方法中會獲取一些包管理須要屬性,以下所示。 frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java框架
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
LockGuard.installLock(mPackages, LockGuard.INDEX_PACKAGES);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "create package manager");
//打印開始階段日誌
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis())
...
//用於存儲屏幕的相關信息
mMetrics = new DisplayMetrics();
//Settings用於保存全部包的動態設置
mSettings = new Settings(mPackages);
//在Settings中添加多個默認的sharedUserId
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);//1
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
...
mInstaller = installer;
//建立Dex優化工具類
mPackageDexOptimizer = new PackageDexOptimizer(installer, mInstallLock, context,
"*dexopt*");
mDexManager = new DexManager(this, mPackageDexOptimizer, installer, mInstallLock);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
mOnPermissionChangeListeners = new OnPermissionChangeListeners(
FgThread.get().getLooper());
getDefaultDisplayMetrics(context, mMetrics);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config");
//獲得全局系統配置信息。
SystemConfig systemConfig = SystemConfig.getInstance();
//獲取全局的groupId
mGlobalGids = systemConfig.getGlobalGids();
//獲取系統權限
mSystemPermissions = systemConfig.getSystemPermissions();
mAvailableFeatures = systemConfig.getAvailableFeatures();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
mProtectedPackages = new ProtectedPackages(mContext);
//安裝APK時須要的鎖,保護全部對installd的訪問。
synchronized (mInstallLock) {//1
//更新APK時須要的鎖,保護內存中已經解析的包信息等內容
synchronized (mPackages) {//2
//建立後臺線程ServiceThread
mHandlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
mHandlerThread.start();
//建立PackageHandler綁定到ServiceThread的消息隊列
mHandler = new PackageHandler(mHandlerThread.getLooper());//3
mProcessLoggingHandler = new ProcessLoggingHandler();
//將PackageHandler添加到Watchdog的檢測集中
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);//4
mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this);
mInstantAppRegistry = new InstantAppRegistry(this);
//在Data分區建立一些目錄
File dataDir = Environment.getDataDirectory();//5
mAppInstallDir = new File(dataDir, "app");
mAppLib32InstallDir = new File(dataDir, "app-lib");
mAsecInternalPath = new File(dataDir, "app-asec").getPath();
mDrmAppPrivateInstallDir = new File(dataDir, "app-private");
//建立多用戶管理服務
sUserManager = new UserManagerService(context, this,
new UserDataPreparer(mInstaller, mInstallLock, mContext, mOnlyCore), mPackages);
...
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false))//6
...
}
複製代碼
在開始階段中建立了不少PMS中的關鍵對象並賦值給PMS中的成員變量,下面簡單介紹這些成員變量。
除了建立這些關鍵對象,在開始階段還有一些關鍵代碼須要去講解:
...
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
...
//打印掃描系統階段日誌
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
...
//在/system中建立framework目錄
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
...
//掃描/vendor/overlay目錄下的文件
scanDirTracedLI(new File(VENDOR_OVERLAY_DIR), mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_TRUSTED_OVERLAY, scanFlags | SCAN_TRUSTED_OVERLAY, 0);
mParallelPackageParserCallback.findStaticOverlayPackages();
//掃描/system/framework 目錄下的文件
scanDirTracedLI(frameworkDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED,
scanFlags | SCAN_NO_DEX, 0);
final File privilegedAppDir = new File(Environment.getRootDirectory(), "priv-app");
//掃描 /system/priv-app 目錄下的文件
scanDirTracedLI(privilegedAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED, scanFlags, 0);
final File systemAppDir = new File(Environment.getRootDirectory(), "app");
//掃描/system/app 目錄下的文件
scanDirTracedLI(systemAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
File vendorAppDir = new File("/vendor/app");
try {
vendorAppDir = vendorAppDir.getCanonicalFile();
} catch (IOException e) {
// failed to look up canonical path, continue with original one
}
//掃描 /vendor/app 目錄下的文件
scanDirTracedLI(vendorAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
//掃描/oem/app 目錄下的文件
final File oemAppDir = new File(Environment.getOemDirectory(), "app");
scanDirTracedLI(oemAppDir, mDefParseFlags
| PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
//這個列表表明有可能有升級包的系統App
final List<String> possiblyDeletedUpdatedSystemApps = new ArrayList<String>();//1
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
//這裏的mPackages的是PMS的成員變量,表明scanDirTracedLI方法掃描上面那些目錄獲得的
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {//2
...
//將這個系統App的PackageSetting從PMS的mPackages中移除
removePackageLI(scannedPkg, true);
//將升級包的路徑添加到mExpectingBetter列表中
mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
...
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
//這個系統App升級包信息在mDisabledSysPackages中,可是沒有發現這個升級包存在
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {//5
possiblyDeletedUpdatedSystemApps.add(ps.name);//
}
}
}
}
...
}
複製代碼
/system能夠稱做爲System分區,裏面主要存儲谷歌和其餘廠商提供的Android系統相關文件和框架。Android系統架構分爲應用層、應用框架層、系統運行庫層(Native 層)、硬件抽象層(HAL層)和Linux內核層,除了Linux內核層在Boot分區,其餘層的代碼都在System分區。下面列出 System分區的部分子目錄。
目錄 | 含義 |
---|---|
app | 存放系統App,包括了谷歌內置的App也有廠商或者運營商提供的App |
framework | 存放應用框架層的jar包 |
priv-app | 存放特權App |
lib | 存放so文件 |
fonts | 存放系統字體文件 |
media | 存放系統的各類聲音,好比鈴聲、提示音,以及系統啓動播放的動畫 |
上面的代碼還涉及到/vendor 目錄,它用來存儲廠商對Android系統的定製部分。
系統掃描階段的主要工做有如下3點:
主要來講第3點,一次OTA升級對於一個系統App會有三種狀況:
當系統App升級,PMS會將該系統App的升級包設置數據(PackageSetting)存儲到Settings的mDisabledSysPackages列表中(具體見PMS的replaceSystemPackageLIF方法),mDisabledSysPackages的類型爲ArrayMap<String, PackageSetting>
。mDisabledSysPackages中的信息會被PMS保存到packages.xml中的<updated-package>
標籤下(具體見Settings的writeDisabledSysPackageLPr方法)。 註釋2處說明這個系統App有升級包,那麼就將該系統App的PackageSetting從mDisabledSysPackages列表中移除,並將系統App的升級包的路徑添加到mExpectingBetter列表中,mExpectingBetter的類型爲ArrayMap<String, File>
等待後續處理。 註釋5處若是這個系統App的升級包信息存儲在mDisabledSysPackages列表中,可是沒有發現這個升級包存在,則將它加入到possiblyDeletedUpdatedSystemApps列表中,意爲「系統App的升級包可能被刪除」,之因此是「可能」,是由於系統尚未掃描Data分區,只能暫放到possiblyDeletedUpdatedSystemApps列表中,等到掃描完Data分區後再作處理。
public PackageManagerService(Context context, Installer installer, boolean factoryTest, boolean onlyCore) {
...
mSettings.pruneSharedUsersLPw();
//若是不是隻掃描系統的目錄,那麼就開始掃描Data分區。
if (!mOnlyCore) {
//打印掃描Data分區階段日誌
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
//掃描/data/app目錄下的文件
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0);
//掃描/data/app-private目錄下的文件
scanDirTracedLI(mDrmAppPrivateInstallDir, mDefParseFlags
| PackageParser.PARSE_FORWARD_LOCK,
scanFlags | SCAN_REQUIRE_KNOWN, 0);
//掃描完Data分區後,處理possiblyDeletedUpdatedSystemApps列表
for (String deletedAppName : possiblyDeletedUpdatedSystemApps) {
PackageParser.Package deletedPkg = mPackages.get(deletedAppName);
// 從mSettings.mDisabledSysPackages變量中移除去此應用
mSettings.removeDisabledSystemPackageLPw(deletedAppName);
String msg;
//1:若是這個系統App的包信息不在PMS的變量mPackages中,說明是殘留的App信息,後續會刪除它的數據。
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; it's data will be wiped";
// Actual deletion of code and data will be handled by later
// reconciliation step
} else {
//2:若是這個系統App在mPackages中,說明是存在於Data分區,不屬於系統App,那麼移除其系統權限。
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
+ deletedAppName;
deletedPkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_SYSTEM;
PackageSetting deletedPs = mSettings.mPackages.get(deletedAppName);
deletedPs.pkgFlags &= ~ApplicationInfo.FLAG_SYSTEM;
}
logCriticalInfo(Log.WARN, msg);
}
//遍歷mExpectingBetter列表
for (int i = 0; i < mExpectingBetter.size(); i++) {
final String packageName = mExpectingBetter.keyAt(i);
if (!mPackages.containsKey(packageName)) {
//獲得系統App的升級包路徑
final File scanFile = mExpectingBetter.valueAt(i);
logCriticalInfo(Log.WARN, "Expected better " + packageName
+ " but never showed up; reverting to system");
int reparseFlags = mDefParseFlags;
//3:根據系統App所在的目錄設置掃描的解析參數
if (FileUtils.contains(privilegedAppDir, scanFile)) {
reparseFlags = PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR
| PackageParser.PARSE_IS_PRIVILEGED;
}
...
//將packageName對應的包設置數據(PackageSetting)添加到mSettings的mPackages中
mSettings.enableSystemPackageLPw(packageName);//4
try {
//掃描系統App的升級包
scanPackageTracedLI(scanFile, reparseFlags, scanFlags, 0, null);//5
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse original system package: "
+ e.getMessage());
}
}
}
}
//清除mExpectingBetter列表
mExpectingBetter.clear();
...
}
複製代碼
/data能夠稱爲Data分區,它用來存儲全部用戶的我的數據和配置文件。下面列出Data分區部分子目錄:
目錄 | 含義 |
---|---|
app | 存儲用戶本身安裝的App |
data | 存儲全部已安裝的App數據的目錄,每一個App都有本身單獨的子目錄 |
app-private | App的私有存儲空間 |
app-lib | 存儲全部App的Jni庫 |
system | 存放系統配置文件 |
anr | 用於存儲ANR發生時系統生成的traces.txt文件 |
掃描Data分區階段主要作了如下幾件事:
//打印掃描結束階段日誌
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
Slog.i(TAG, "Time to scan packages: "
+ ((SystemClock.uptimeMillis()-startTime)/1000f)
+ " seconds");
int updateFlags = UPDATE_PERMISSIONS_ALL;
// 若是當前平臺SDK版本和上次啓動時的SDK版本不一樣,從新更新APK的受權
if (ver.sdkVersion != mSdkVersion) {
Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to "
+ mSdkVersion + "; regranting permissions for internal storage");
updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL;
}
updatePermissionsLPw(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags);
ver.sdkVersion = mSdkVersion;
//若是是第一次啓動或者是Android M升級後的第一次啓動,須要初始化全部用戶定義的默認首選App
if (!onlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : sUserManager.getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(this, user.id);
applyFactoryDefaultBrowserLPw(user.id);
primeDomainVerificationsLPw(user.id);
}
}
...
//OTA後的第一次啓動,會清除代碼緩存目錄。
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)) {
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
...
// 把Settings的內容保存到packages.xml中
mSettings.writeLPr();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
複製代碼
掃描結束結束階段主要作了如下幾件事:
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
...
mInstallerService = new PackageInstallerService(context, this);//1
...
Runtime.getRuntime().gc();//2
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "loadFallbacks");
FallbackCategoryProvider.loadFallbacks();
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
mInstaller.setWarnIfHeld(mPackages);
LocalServices.addService(PackageManagerInternal.class, new PackageManagerInternalImpl());//3
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
複製代碼
註釋1處建立PackageInstallerService,PackageInstallerService是用於管理安裝會話的服務,它會爲每次安裝過程分配一個SessionId,在Android包管理機制(二)PackageInstaller安裝APK這篇文章中提到過PackageInstallerService。 註釋2處進行一次垃圾收集。註釋3處將PackageManagerInternalImpl(PackageManager的本地服務)添加到LocalServices中, LocalServices用於存儲運行在當前的進程中的本地服務。
本篇文章介紹了PMS的建立過程,分爲兩個部分,分別是SyetemServer處理部分和PMS構造方法,PMS構造方法又分爲5個部分,分別是開始階段、掃描系統階段、掃描Data分區階段、掃描結束階段和準備階段。
參考資料
Android包管理機制
源碼分析 — PackageManagerService(一)之啓動流程
Android-6.0之PMS解析下篇
APK安裝流程詳解6——PackageManagerService啓動前奏
這裏不只分享Android、Java和移動前端相關技術,還有行業動態、技術資訊、面經和我的感悟。