PackageManagerServervice 透過 SystemServer 進程啟動,該服務會掃描系統中特定的目錄,尋找裡面的 APK 格式文件,並對這些文件進行解析(得到 AppInfo 相關訊息),最後完成安裝。 PKMS 會在安裝應用的過程中解析 APK 中的AndroidManifest.xml
文件(解析出 Android 四大組件),這些解析完的信息會保存在 Android 系統中,方便系統隨時取用。
主要功能#
- 掃描
.apk
文件,安裝系統應用
、本地應用
- 解析 AndroidManifest.xml 清單文件,分析出四大零組件、權限… 等等信息,並儲存在 PKMS 方便查詢
- 管理本地應用,其中包括
安裝
、卸載
、查詢APK信息
… 等等功能 - 分配應用程序的 UID、GID
透過 GID(Group 群組 ID)來管理權限管理,在某個群組中才能使用某些功能
使用#
我們可以透過Context#getPackageManager()
方法來取得 PKMS 服務,PackageManager 是抽象類,實際上是 ApplicationPackageManager。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PackageManager packageManager = this.getBaseContext().getPackageManager();
}
ServiceManager 取得 PKMS#
ActivityThread 透過 ServiceManager 取得 PKMS 的 IBinder,這裡的
IPackageManager 是透過 AIDL 自動產生的類,IPackageManager 透過asInterface
來取得 Java 代理類,透過該代理類來與 PKMS 通信
// ActivityThread.java
@UnsupportedAppUsage
public static IPackageManager getPackageManager() {
if (sPackageManager != null) {
return sPackageManager;
}
// 1.取得ServiceManager的代理
// 2.透過代理傳入“package”來取得PKMS的句柄(handle)
// 3.返回PKMS的代理
final IBinder b = ServiceManager.getService("package");
// 創建AIDL的代理類
sPackageManager = IPackageManager.Stub.asInterface(b);
return sPackageManager;
}
SystemServer 初始化 PKMS#
SystemServer 啟動引導服務(startBootstrapServices):PKMS 就是在這裡啟動
// SystemServer.java
public static void main(String[] args) {
new SystemServer().run();
}
private void run() {
... 省略部分
try {
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
} /* 省略 catch */
... 省略部分
// Loop forever.
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t)
...
// 安裝服務
Installer installer = mSystemServiceManager.startService(Installer.class);
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);
...
try {
... watch dog
// 呼叫PackageManagerService的靜態main方法
// @分析main
mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
domainVerificationService, mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
mOnlyCore);
} ... watch dog
...
}
startBootstrapServices#
啟動 Installer 服務,之後會用這個服務來安裝所有應用
// SystemServer.java
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
Installer installer = mSystemServiceManager.startService(Installer.class);
... 省略部分
}
VoldProperties#decrypt
判斷手機裝置是否加密(讀取init.rc
檔的設定),mOnlyCore = true
代表只運行核心程序。
// SystemServer.java
private static final String ENCRYPTING_STATE = "trigger_restart_min_framework";
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
...
// Only run "core" apps if we're encrypting the device.
String cryptState = VoldProperties.decrypt().orElse("");
if (ENCRYPTING_STATE.equals(cryptState)) {
// 只運行核心程序
... log msg
mOnlyCore = true;
} else if (ENCRYPTED_STATE.equals(cryptState)) {
... log msg
mOnlyCore = true;
}
...
}
調用PKMS#main
方法,創建 PKMS 對象
// SystemServer.java
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
...
PackageManagerService.main(mSystemContext, installer,
domainVerificationService,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF,
mOnlyCore); // 假設傳入false
} /* 省略finally */
... 省略部分
}
如果設備沒有加密,就執行 A/B OTA dexopting,OtaDexoptService#main
方法
// SystemServer.java
private void startBootstrapServices(@NonNull TimingsTraceAndSlog t) {
...
if (!mOnlyCore) {
boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
false);
if (!disableOtaDexopt) {
... trace log
try {
... watch dog
OtaDexoptService.main(mSystemContext, mPackageManagerService);
} /* catch、finally */
}
}
...
}
PKMS 在SystemServer#startBootstrapServices函數
完成初始化操作後,會在startOtherServices
做後續的操作(完成 Dex 優化、systemReady)
透過PKMS#performFstrimIfNeeded
完成 dex 優化
// SystemServer.java
private void startOtherServices(@NonNull TimingsTraceAndSlog t) {
... 省略部分
try {
mPackageManagerService.performFstrimIfNeeded();
} ...
... 省略部分
}
PKMS 準備就緒調用systemReady,加載預設權限
PKMS 分析#
PKMS main
#
透過PackageManagerService#main
方法就可以創建 PackageManagerService 物件,並且將 PKMS 透過package、package_native添加到 ServiceManager 中
// PackageManagerService.java
public static PackageManagerService main(Context context, Installer installer,
@NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
boolean onlyCore) {
// 檢查package編譯相關系統屬性
PackageManagerServiceCompilerMapping.checkProperties();
...
Injector injector = new Injector(
context, lock, installer, installLock,
new PackageAbiHelperImpl(),
backgroundHandler,
SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(i.getUserManagerService(), pm.mPmInternal, lock),
(i, pm) -> PermissionManagerService.create(context,
i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context, onlyCore),
lock),
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, lock),
(i, pm) -> AppsFilter.create(pm.mPmInternal, i),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new PackageDexOptimizer(i.getInstaller(), i.getInstallLock(),
i.getContext(), "*dexopt*"),
(i, pm) -> new DexManager(i.getContext(), pm, i.getPackageDexOptimizer(),
i.getInstaller(), i.getInstallLock()),
(i, pm) -> new ArtManagerService(i.getContext(), pm, i.getInstaller(),
i.getInstallLock()),
(i, pm) -> ApexManager.getInstance(),
(i, pm) -> new ViewCompiler(i.getInstallLock(), i.getInstaller()),
(i, pm) -> (IncrementalManager)
i.getContext().getSystemService(Context.INCREMENTAL_SERVICE),
(i, pm) -> new DefaultAppProvider(() -> context.getSystemService(RoleManager.class),
() -> LocalServices.getService(UserManagerInternal.class)),
(i, pm) -> new DisplayMetrics(),
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
i.getDisplayMetrics(), pm.mCacheDir,
pm.mPackageParserCallback) /* scanningCachingPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, pm.mOnlyCore,
i.getDisplayMetrics(), null,
pm.mPackageParserCallback) /* scanningPackageParserProducer */,
(i, pm) -> new PackageParser2(pm.mSeparateProcesses, false, i.getDisplayMetrics(),
null, pm.mPackageParserCallback) /* preparingPackageParserProducer */,
// Prepare a supplier of package parser for the staging manager to parse apex file
// during the staging installation.
(i, pm) -> new PackageInstallerService(
i.getContext(), pm, i::getScanningPackageParser),
(i, pm, cn) -> new InstantAppResolverConnection(
i.getContext(), cn, Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
(i, pm) -> new ModuleInfoProvider(i.getContext(), pm),
(i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
(i, pm) -> domainVerificationService,
(i, pm) -> {
// 負責apk安裝、卸載
HandlerThread thread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /*allowIo*/);
thread.start();
return pm.new PackageHandler(thread.getLooper());
},
new DefaultSystemWrapper(),
LocalServices::getService,
context::getSystemService);
// 調用PackageMangerService的構造函數
PackageManagerService m = new PackageManagerService(injector, onlyCore, factoryTest,
Build.FINGERPRINT, Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
Build.VERSION.INCREMENTAL);
...
// 透過package、package_native添加到ServiceManager中
ServiceManager.addService("package", m);
final PackageManagerNative pmn = m.new PackageManagerNative();
ServiceManager.addService("package_native", pmn);
return m;
}
// PackageManagerService.java
public static class Injector {
@VisibleForTesting(visibility = Visibility.PRIVATE)
interface Producer<T> {
/** Produce an instance of type {@link T} */
T produce(Injector injector, PackageManagerService packageManager);
}
...
@VisibleForTesting(visibility = Visibility.PRIVATE)
static class Singleton<T> {
private final Producer<T> mProducer;
private volatile T mInstance = null;
Singleton(Producer<T> producer) {
this.mProducer = producer;
}
T get(Injector injector, PackageManagerService packageManagerService) {
if (mInstance == null) {
mInstance = mProducer.produce(injector, packageManagerService);
}
return mInstance;
}
}
private final Singleton<PermissionManagerServiceInternal> mPermissionManagerServiceProducer;
private final Singleton<UserManagerService> mUserManagerProducer;
private final Singleton<Settings> mSettingsProducer;
private final Singleton<AppsFilter> mAppsFilterProducer;
...
private final Singleton<DisplayMetrics> mDisplayMetricsProducer;
Injector(Context context, PackageManagerTracedLock lock, Installer installer,
Object installLock, PackageAbiHelper abiHelper,
Handler backgroundHandler,
List<ScanPartition> systemPartitions,
...
Producer<PermissionManagerServiceInternal> permissionManagerServiceProducer,
Producer<UserManagerService> userManagerProducer,
Producer<Settings> settingsProducer,
Producer<DisplayMetrics> displayMetricsProducer,
) {
...
mPermissionManagerServiceProducer = new Singleton<>(permissionManagerServiceProducer);
mUserManagerProducer = new Singleton<>(userManagerProducer);
mSettingsProducer = new Singleton<>(settingsProducer);
...
mDisplayMetricsProducer = new Singleton<>(displayMetricsProducer);
}
public PermissionManagerServiceInternal getPermissionManagerServiceInternal() {
return mPermissionManagerServiceProducer.get(this, mPackageManager);
}
public Context getContext() {
return mContext;
}
public Settings getSettings() {
return mSettingsProducer.get(this, mPackageManager);
}
public DisplayMetrics getDisplayMetrics() {
return mDisplayMetricsProducer.get(this, mPackageManager);
}
...
}
PKMS 構造方法#
PackageManagerService 的構造函數中可以發現 PKMS 構造有5 個階段(寫在 EventLog 中)
階段標誌 | 說明 | 其他 |
---|---|---|
BOOT_PROGRESS_PMS_START | 初始階段,透過 Inject 內部類來取得單例的各種服務、對象 | DisplayMetrics、Installer、mPermissionManager、mSettings、mPackageDexOptimizer |
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START | 掃描系統 | |
BOOT_PROGRESS_PMS_DATA_SCAN_START | 掃描 data 區塊 | |
BOOT_PROGRESS_PMS_SCAN_END | 掃描結束 | |
BOOT_PROGRESS_PMS_READY | 準備階段 |
PKMS 有使用到多 Thread,而裡面有兩個重要的鎖需要注意
鎖名稱 | 說明 | 補充 |
---|---|---|
mPackages(小鎖) | 用於保護所有內存中解析 Package 的細節、狀態、更新 | 在持有 mInstallLock 的時候,獲取 mPackages 是安全的 |
mInstallLock(大鎖) | 用於保護所有安裝 APK 時的鎖,通常是有關到應用 APP 的重載(單線程、涉及繁重的 IO 操作) | 在獲取 mPackages 時,不該再獲取此鎖 |
第一階段 - BOOT_PROGRESS_PMS_START#
第一階段的重點是Settings#readLPw 方法,讀取
/data/system
目錄下的文件
BOOT_PROGRESS_PMS_START:取得DisplayMetrics
(解析度)、Installer
(安裝)、PermissionManager
(權限管理)、mSettings
(保存安裝信息、清除不存在的應用)、PackageDexOptimizer
(Dex 優化)… 詳細請看註釋
// PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,final String buildFingerprint, final boolean isEngBuild,final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
mOnlyCore = onlyCore;
mMetrics = injector.getDisplayMetrics();
mInstaller = injector.getInstaller();
mUserManager = injector.getUserManagerService(); // 多用戶管理
// 權限管理服務
mPermissionManager = injector.getPermissionManagerServiceInternal();
// 涉及 'data/system/' packages.xml
// packages-backup.xml
// packages.list
// packages-stopped.xml
// packages-stopped-backup.xml 文件
mSettings = injector.getSettings();
...
// 添加system、phone、log、nfc、bluetooth、shell、se、
// networkstack、uwb這幾個sharedUserLPw到mSettings中
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);
mSettings.addSharedUserLPw("android.uid.log", LOG_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.se", SE_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.networkstack", NETWORKSTACK_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.uwb", UWB_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
...
// 處理dex優化(DexOpt優化)
mPackageDexOptimizer = injector.getPackageDexOptimizer();
mDexManager = injector.getDexManager();
// Art虛擬機管理
mArtManagerService = injector.getArtManagerService();
...
// 創建/data/app文件夾
mAppInstallDir = new File(Environment.getDataDirectory(), "app");
// 安裝APK時需要的鎖,保護所有對installed的訪問
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
// 啟動PackageManagerThread,負責apk安裝、卸載
mHandler = injector.getHandler();
// 進程紀錄Handler
mProcessLoggingHandler = new ProcessLoggingHandler();
// 監聽PackageManagerThread是否超時10分鐘
Watchdog.getInstance().addThread(mHandler,
// WATCHDOG_TIMEOUT => 10分鐘
WATCHDOG_TIMEOUT);
...
// 讀取安裝相關的SELinux策略
SELinuxMMAC.readInstallPolicy();
// 讀取並解析/data/system中的xml文件
mFirstBoot = !mSettings.readLPw(sUserManager.getUsers(false));
t.traceEnd();
}
}
}
其中mSettings.addSharedUserLPw
方法是將 **SharedUserId
添加到 Setting 中;一般來講進程間數據不可共享,但有共同SharedUserId
就可以共享數據 **
mPackageDexOptimizer
是 Dex 的優化工具mHandler
綁定後台 ServiceThread 的消息隊列,PKMS 透過它來驅動 APK 複製&安裝,並且該 Handler 會由 WatchDog 來監看(防止花費過多時間)
PKMD 會訪問幾個重要的文件夾
訪問 | 資料夾 |
---|---|
File(Environment.getDataDirectory(), “app”) | /data/app |
File(Environment.getDataDirectory(), “app-lib”) | /data/app-lib |
Settings 創建#
先複習 Settings 對象由來:PKMS 的 Settings 對象會由PKMS#Inject
類提供
// PackageManager
public static class Injector {
private final Singleton<Settings> mSettingsProducer;
Injector(/* 省略參數 */) {
...
mSettingsProducer = new Singleton<>(settingsProducer);
}
public Settings getSettings() {
return mSettingsProducer.get(this, mPackageManager);
}
}
public static PackageManagerService main(Context context, Installer installer,
@NonNull DomainVerificationService domainVerificationService, boolean factoryTest,
boolean onlyCore) {
Injector injector = new Injector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
backgroundHandler,
SYSTEM_PARTITIONS,
...
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService,
lock),
);
}
Settings 類的構造函數會創建所需文件 & 文件夾,並設置它們的權限
// Settings.java
Settings(File dataDir, //帶入的dataDir是/data
RuntimePermissionsPersistence runtimePermissionsPersistence,
LegacyPermissionDataProvider permissionDataProvider,
@NonNull DomainVerificationManagerInternal domainVerificationManager,
@NonNull PackageManagerTracedLock lock) {
...
// 創建/data/system目錄
mSystemDir = new File(dataDir, "system");//'/data/system'
mSystemDir.mkdirs(); // 創建/data/system
// 文件夾權限775
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
// 創建/data/system/packages.xml
mSettingsFilename = new File(mSystemDir, "packages.xml");
// 創建/data/system/packages-backup.xml
mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml");
// 創建data/system/packages.list
mPackageListFilename = new File(mSystemDir, "packages.list");
// 設定chmod 0640
FileUtils.setPermissions(mPackageListFilename, 0640, SYSTEM_UID, PACKAGE_INFO_GID);
final File kernelDir = new File("/config/sdcardfs");
mKernelMappingFilename = kernelDir.exists() ? kernelDir : null;
// Deprecated: Needed for migration
// 創建data/system/packages-stopped.list
mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml");
// 創建data/system/packages-stopped-backup.list
mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml");
...
}
Settings - readLPw 讀取 package 文件#
mSettings#readLPw () 函數:讀取/data/system
目錄下的文件,並保存到 Setting 對象中,而文件又分為以下幾種(提出較為重要的幾個)
文件名 | 說明 | 其他 |
---|---|---|
packages.xml | 安裝 app 信息 | PKMS 掃描完目錄文件後會創建該文件,當系統執行安裝、卸載、更新等操作時都會更新這個文件 |
packages-backup.xml | 安裝 app 的備份信息 | 避免在安裝時關機,產生意外 |
packages.list | 所有安裝的 app 信息(非系統 APP) | 描述所有非系統 APK 信息,當有第三方 APP 變更時就會修改該文件 |
packages-stopped.xml | 強制停止 app 信息 | 強制停止某個應用時(用戶操作),系統會將該應用的相關訊息記錄到該文件中 |
packages-stopped-backup.xml | 強制停止 app 的備份信息 | |
**mSettings#readLPw ()** 功能:首先掃描packages.xml 、packages-backup.xml 文件,其中與 Linux 使用 UID 有關的函數如下 | ||
“package” 標籤:使用readPackageLPw 函數,讀取上一次分配的 Linux UID | ||
“shared-user” 標籤:使用readSharedUserLPw 函數,讀取上一次應用共享的 shared ID |
// Settings.java
boolean readLPw(@NonNull List<UserInfo> users) {
FileInputStream str = null;
// 如果有packages-backup.xml的話取得backup IO流
if (mBackupSettingsFilename.exists()) {
try {
str = new FileInputStream(mBackupSettingsFilename);
...
} /* 省略catch */
}
try {
if (str == null) {
...
// 沒有backup就使用packages.xml
str = new FileInputStream(mSettingsFilename);
}
// 解析xml
final TypedXmlPullParser parser = Xml.resolvePullParser(str);
int type;
// 調整xml指標位置
while ((type = parser.next()) != XmlPullParser.START_TAG
&& type != XmlPullParser.END_DOCUMENT) {
;
}
// 解析格式,判斷xml格式是否正確
if (type != XmlPullParser.START_TAG) {
... err log
return false;
}
int outerDepth = parser.getDepth();
// 開始分析xml
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
// 解析節點名稱
String tagName = parser.getName();
if (tagName.equals("package")) {
// 讀取上一次分配的Linux UID
readPackageLPw(parser, users);
} else if (tagName.equals("permissions")) {
mPermissions.readPermissions(parser);
} else if (tagName.equals("permission-trees")) {
mPermissions.readPermissionTrees(parser);
} else if (tagName.equals("shared-user")) {
// 讀取上一次應用共享的GID
readSharedUserLPw(parser, users);
} ... 省略部分else if
else {
... log
XmlUtils.skipCurrentTag(parser);
}
}
str.close();
} /* 省略catch、finally */
...
return true;
}
readPackageLPw 應用分配獨立 Linux ID#
接下來我們主要關注 “package” 標籤中的 3 元素
元素名 | 功能 | 補充 |
---|---|---|
name | 應用包名 | 必須要有 package 包名 |
userId | Linux 上次為該應用分配的獨立 UID | |
sharedUserId | 該應用沒有獨立 UID,與其它應用共享 UID | 將該應用添加進mPendingPackages 列表之後判斷 |
// Setting.java
public static final String ATTR_NAME = "name";
private final WatchedArrayList<PackageSetting> mPendingPackages = new WatchedArrayList<>();
private void readPackageLPw(TypedXmlPullParser parser, List<UserInfo> users,
ArrayMap<String, Long> originalFirstInstallTimes)
throws XmlPullParserException, IOException {
String name = null;
int userId = 0;
int sharedUserAppId = 0;
try {
// App package name
name = parser.getAttributeValue(null, ATTR_NAME);
...
userId = parser.getAttributeInt(null, "userId", 0);
sharedUserAppId = parser.getAttributeInt(null, "sharedUserId", 0);
if (name == null) {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: <package> has no name at "
+ parser.getPositionDescription());
} else if (codePathStr == null) {
...
} else if (userId > 0) { // 已分配到獨立ID
packageSetting = addPackageLPw(name.intern(), realName, new File(codePathStr),
legacyNativeLibraryPathStr, primaryCpuAbiString, secondaryCpuAbiString,
cpuAbiOverrideString, userId, versionCode, pkgFlags, pkgPrivateFlags,
null /* usesSdkLibraries */, null /* usesSdkLibraryVersions */,
null /* usesStaticLibraries */, null /* usesStaticLibraryVersions */,
null /* mimeGroups */, domainSetId);
...
} else if (sharedUserAppId != 0) { // 未分配獨立ID
if (sharedUserAppId > 0) {
// 保存該應用信息
packageSetting = new PackageSetting(name.intern(), realName,
new File(codePathStr), legacyNativeLibraryPathStr,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
versionCode, pkgFlags, pkgPrivateFlags, sharedUserAppId,
null /* usesSdkLibraries */,
null /* usesSdkLibrariesVersions */,
null /* usesStaticLibraries */,
null /* usesStaticLibraryVersions */,
null /* mimeGroups */, domainSetId);
...
// 添加到`mPendingPackages`列表
mPendingPackages.add(packageSetting);
...
} else {
...
}
} else {
...
}
} /* 省略catch */
}
addPackageLPw
函數:在 PKMS 中每個應用都是以PackageSetting
對象存在,並將其儲存在以 package name 為 Key 的 HashMap 中
// Setting.java
// 儲存全部應用的信息
final WatchedArrayMap<String, PackageSetting> mPackages;
private final AppIdSettingMap mAppIds;
PackageSetting addPackageLPw(String name, String realName, File codePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString, int uid,
... /* 省略部分 */) {
// 以name來取得PackageSetting
PackageSetting p = mPackages.get(name);
if (p != null) {
// 判斷uid
if (p.getAppId() == uid) {
// 相等代表已分配獨立UID
return p;
}
PackageManagerService.reportSettingsProblem(Log.ERROR,
"Adding duplicate package, keeping first: " + name);
return null;
}
p = new PackageSetting(name, realName, codePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
... /* 省略部分 */);
// 設定UID給該PackageSetting
p.setAppId(uid);
// 註冊該ID至系統
if (mAppIds.registerExistingAppId(uid, p, name)) {
mPackages.put(name, p);
return p;
}
return null;
}
registerExistingAppId函數:已分配的應用會從mNonSystemSettings
取出 null
// Process.java
public static final int FIRST_APPLICATION_UID = 10000;
// ------------------------------------------------------------
// AppIdSettingMap.java
private final WatchedArrayList<SettingBase> mNonSystemSettings;
public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {
// 大於FIRST_APPLICATION_UID代表是獨立應用
if (appId >= Process.FIRST_APPLICATION_UID) {
int size = mNonSystemSettings.size();
final int index = appId - Process.FIRST_APPLICATION_UID;
// fill the array until our index becomes valid
while (index >= size) {
mNonSystemSettings.add(null);
size++;
}
// 已分配會取出null
if (mNonSystemSettings.get(index) != null) {
// 重複UID
...err msg
return false;
}
mNonSystemSettings.set(index, setting);
} else {
// 小於FIRST_APPLICATION_UID代表是共享應用
...
}
return true;
}
readPackageLPw 應用分配共享 Linux ID#
接下來我們主要關注 “shared-user” 標籤中的 3 元素
元素名 | 功能 | 補充 |
---|---|---|
name | 用來描述一個共享 Linux 使用者的名稱 | |
userId | 用來描述一個共享 Linux 使用者的 ID | |
system | 描述該 ID 是系統型態、使用者型態 |
// Setting.java
private void readSharedUserLPw(TypedXmlPullParser parser, List<UserInfo> users)
throws XmlPullParserException, IOException {
String name = null;
int pkgFlags = 0;
int pkgPrivateFlags = 0;
SharedUserSetting su = null;
{
name = parser.getAttributeValue(null, ATTR_NAME);
int userId = parser.getAttributeInt(null, "userId", 0);
if (parser.getAttributeBoolean(null, "system", false)) {
pkgFlags |= ApplicationInfo.FLAG_SYSTEM;
}
if (name == null) {
...
} else if (userId == 0) {
...
} else {
if ((su = addSharedUserLPw(name.intern(), userId, pkgFlags, pkgPrivateFlags))
== null)
...
}
}
}
...
}
Setting#addSharedUserLPw
函數:使用SharedUserSetting
來描述一個共享應用;比對 ID 確認沒問題後,就可以加入mSharedUsers
列表
// Setting.java
final WatchedArrayMap<String, SharedUserSetting> mSharedUsers
= new WatchedArrayMap<>();
SharedUserSetting addSharedUserLPw(String name, int uid, int pkgFlags, int pkgPrivateFlags) {
SharedUserSetting s = mSharedUsers.get(name);
if (s != null) {
if (s.mAppId == uid) {
return s;
}
...err
return null;
}
// 創建對應對象
s = new SharedUserSetting(name, pkgFlags, pkgPrivateFlags);
// 設定ID
s.mAppId = uid;
// 嘗試註冊
if (mAppIds.registerExistingAppId(uid, s, name)) {
mSharedUsers.put(name, s);
return s;
}
return null;
}
registerExistingAppId函數:已分配的應用會從mNonSystemSettings
取出 null
// Process.java
public static final int FIRST_APPLICATION_UID = 10000;
// ------------------------------------------------------------
// AppIdSettingMap.java
private final WatchedArrayList<SettingBase> mNonSystemSettings;
public boolean registerExistingAppId(int appId, SettingBase setting, Object name) {
// 大於FIRST_APPLICATION_UID代表是獨立應用
if (appId >= Process.FIRST_APPLICATION_UID) {
...
} else {
// 小於FIRST_APPLICATION_UID代表是共享應用
if (mSystemSettings.get(appId) != null) {
...err
return false;
}
mSystemSettings.put(appId, setting);
}
return true;
}
回到readLPw
函數:經過上面分析“shared-user”
、“package”
後可以得到共享、獨立應用的相關訊息,接著就是要處理共享應用的 ID
// Settings.java
private final AppIdSettingMap mAppIds;
boolean readLPw(@NonNull List<UserInfo> users) {
...
final int N = mPendingPackages.size();
for (int i = 0; i < N; i++) {
final PackageSetting p = mPendingPackages.get(i);
final int sharedUserAppId = p.getSharedUserAppId();
// 共享ID一定大於0
if (sharedUserAppId <= 0) {
continue;
}
final Object idObj = getSettingLPr(sharedUserAppId);
if (idObj instanceof SharedUserSetting) {
final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
addPackageSettingLPw(p, sharedUser);
} else if (idObj != null) {
...
} else {
...
}
}
mPendingPackages.clear();
return true;
}
public SettingBase getSettingLPr(int appId) {
return mAppIds.getSetting(appId);
}
void addPackageSettingLPw(PackageSetting p, SharedUserSetting sharedUser) {
mPackages.put(p.getPackageName(), p);
// 如果是共享應用還要再判斷
if (sharedUser != null) {
SharedUserSetting existingSharedUserSetting = getSharedUserSettingLPr(p);
if (existingSharedUserSetting != null && existingSharedUserSetting != sharedUser) {
...err msg
sharedUser.removePackage(p);
} else if (p.getAppId() != sharedUser.mAppId) {
...err msg
}
sharedUser.addPackage(p);
p.setSharedUserAppId(sharedUser.mAppId);
// 決定最終ID
p.setAppId(sharedUser.mAppId);
}
Object userIdPs = getSettingLPr(p.getAppId());
if (sharedUser == null) {
if (userIdPs != null && userIdPs != p) {
mAppIds.replaceSetting(p.getAppId(), p);
}
} else {
if (userIdPs != null && userIdPs != sharedUser) {
mAppIds.replaceSetting(p.getAppId(), sharedUser);
}
}
}
第二階段 - BOOT_PROGRESS_PMS_SYSTEM_SCAN_START#
BOOT_PROGRESS_PMS_SYSTEM_SCAN_START:掃描系統階段,其中目錄包括(system
、vendor
、product
、odm
、oem
… 等等目錄中的priv-app
、app
、overlay
)並且該步驟仍在兩個鎖內執行
scanDirTracedLI 方法:該方法掃描 APK 包,會針對傳入的路徑掃描內部的 APK 檔案,之後會再針對 scanDirTracedLI 進行分析
// PackageManagerService.java
// Key是應用包名,Value是應用包
final ArrayMap<String, PackageParser.Package> mPackages =
new ArrayMap<String, PackageParser.Package>();
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
...
// 記錄開始時間
long startTime = SystemClock.uptimeMillis();
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
// 從init.rc中獲取環境變量BOOTCLASSPATH、
// SYSTEMSERVERCLASSPATH
final String bootClassPath =
System.getenv("BOOTCLASSPATH");
final String systemServerClassPath =
System.getenv("SYSTEMSERVERCLASSPATH");
// 獲取/system/framework目錄
File frameworkDir = new File(Environment.getRootDirectory(), "framework");
// 獲取內部版本
final VersionInfo ver = mSettings.getInternalVersion();
// 判斷是否需要更新
mIsUpgrade =
!buildFingerprint.equals(ver.fingerprint);
// Android M升級上來的版本,須將系統應用權限從安裝時申請,改為運行時申請
mPromoteSystemApps =
mIsUpgrade && ver.sdkVersion <= Build.VERSION_CODES.LOLLIPOP_MR1;
// Android N升級上來的版本,需要像首次啟動一樣處理包提取,因為沒有可用的分析數據
mIsPreNUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N;
mIsPreNMR1Upgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.N_MR1;
mIsPreQUpgrade = mIsUpgrade && ver.sdkVersion < Build.VERSION_CODES.Q;
...
// 準備解析package的緩存
mCacheDir = preparePackageParserCache(mIsEngBuild);
// 設定flag,當掃描安裝文件夾時不改變apk路徑
int scanFlags = SCAN_BOOTING | SCAN_INITIAL;
// 收集vendor/product/system_ext overlay packages.
for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getOverlayFolder() == null) {
continue;
}
// 掃描overlay…等等文件夾內的apk
scanDirTracedLI(partition.getOverlayFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
// 掃描framework文件夾內的apk
scanDirTracedLI(frameworkDir, systemParseFlags,
systemScanFlags | SCAN_NO_DEX | SCAN_AS_PRIVILEGED, 0,
packageParser, executorService);
// 判斷安裝包是否是android
if (!mPackages.containsKey("android")) {
throw new IllegalStateException(
"Failed to load frameworks package; check log for warnings");
}
for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
final ScanPartition partition = mDirsToScanAsSystem.get(i);
if (partition.getPrivAppFolder() != null) {
// 掃描priv-app文件夾
scanDirTracedLI(partition.getPrivAppFolder(), systemParseFlags,
systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0,
packageParser, executorService);
}
// 掃描/system/app文件夾
scanDirTracedLI(partition.getAppFolder(), systemParseFlags,
systemScanFlags | partition.scanFlag, 0,
packageParser, executorService);
}
...
if (!mOnlyCore) {
// do this first before mucking with mPackages for the "expecting better" case
final int numPackages = mPackages.size();
for (int index = 0; index < numPackages; index++) {
final AndroidPackage pkg = mPackages.valueAt(index);
if (pkg.isStub()) {
stubSystemApps.add(pkg.getPackageName());
}
}
// 倒序掃描所有應用
for (int index = packageSettings.size() - 1; index >= 0; index--) {
final PackageSetting ps = packageSettings.valueAt(index);
// 如果包有FLAG_SYSTEM忽略
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}
/*
* If the package is scanned, it's not erased.
*/
final AndroidPackage scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
//若在disabled packages list,添加進
// via OTA,再將其移除
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
...
//將系統App的PackageSetting從PKMS中mPackage移除
removePackageLI(scannedPkg, true);
// 將升級包的路徑添加到mExpectingBetter列表中
mExpectingBetter.put(ps.name, ps.getPath());
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; it's data will be wiped");
// 系統APP將不存在,移除該APP的數據
removePackageDataLIF(ps, userIds, null, 0, false);
} else {
// we still have a disabled system package, but, it still might have
// been removed. check the code path still exists and check there's
// still a package. the latter can happen if an OTA keeps the same
// code path, but, changes the package name.
final PackageSetting disabledPs =
mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.getPath() == null || !disabledPs.getPath().exists()
|| disabledPs.pkg == null) {
// 該系統APP在isDisabledSystemPackage中,並且沒有發現升級包
possiblyDeletedUpdatedSystemApps.add(ps.name);
} else {
// We're expecting that the system app should remain disabled, but add
// it to expecting better to recover in case the data version cannot
// be scanned.
mExpectingBetter.put(disabledPs.name, disabledPs.getPath());
}
}
}
}
...
}
}
掃描升級系統 APP - system 文件夾#
目前階段(BOOT_PROGRESS_PMS_SYSTEM_SCAN_START
)主要是掃描/system
文件夾:這個目錄下文件夾都如何規劃放置
Android 系統架構有分為應用層、應用框架層、系統運行層、硬件抽象層、內核層
system 內文件夾 | 放置內容 | 補充 |
---|---|---|
app | 系統 app | 包括 google 內置、手機廠商 app |
framework | 應用框架 jar 包 | 主要放 jar 包、vdex |
priv-app | 特權 app | |
lib | 放置動態 so 文件 | |
fonts | 系統字體 | 多是 ttf 檔 |
media | 系統音效 | 像是鈴聲、提示音、系統啟動動畫 |
第二個目的是掃描系統文件並處理,處理的重點是 ==OTA 升級 ==,系統會將可升級的系統應用標記為 DisabledSystemPackage,並且有 3 種狀況
系統 APP 有更新:透過 removePackageLI 將系統 App 的 PackageSetting 從 PKMS 中 mPackage 移除,並添加到 mExpectingBetter 列表
系統 APP 被移除:透過removePackageDataLIF移除系統 APP 數據
沒有升級包:系統應用為 DisabledSystemPackage,但沒有發現升級包,代表系統升級包可能被刪除
第三階段 - BOOT_PROGRESS_PMS_DATA_SCAN_START#
BOOT_PROGRESS_PMS_DATA_SCAN_START:主要會掃描/data
文件夾
掃描處理、更新/data
目錄的應用信息(也會及時移除不需要的數據)
處理上一步遺留的 possiblyDeletedUpdatedSystemApps 列表
- 如果無法從 mPackage 中取得 Package 則會刪除該 APP
- 如果可以取得 Package 但不是系統 APP,並且會做以下這些事情
- 移除 System 權限
- 移除 Package
- 重新掃描 Package 路徑的 APK
掃描 mExpectingBetter 列表 - 取得系統 APP 升級包的路徑,並且會做以下這些事情
- 根據系統 APP 所在的目錄設定掃描的解析參數
- 將 PackageName 設定給
mSetting#mPackages
中(removeDisabledSystemPackageLPw 方法) - 清除 mExpectingBetter 列表
// PackageManagerService.java
private final File mAppInstallDir;
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
// 取得/data/app資料夾
mAppInstallDir = new File(Environment.getDataDirectory(), "app");
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
...
if (!mOnlyCore) {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
// 掃描/data/app文件夾
scanDirTracedLI(mAppInstallDir, 0, scanFlags | SCAN_REQUIRE_KNOWN, 0,
packageParser, executorService);
}
// 關閉Parser流(解析Package xml的流)
packageParser.close();
// 關閉Executor的全部任務
List<Runnable> unfinishedTasks = executorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException("Not all tasks finished before calling close: "
+ unfinishedTasks);
}
if (!mOnlyCore) {
// 2.掃描上一步所遺留的APP包(倒序)
for (int i = possiblyDeletedUpdatedSystemApps.size() - 1; i >= 0; --i) {
final String packageName = possiblyDeletedUpdatedSystemApps.get(i);
final AndroidPackage pkg = mPackages.get(packageName);
final String msg;
// 從禁用系統列表(mDisabledSystemPackage)中移除
mSettings.removeDisabledSystemPackageLPw(packageName);
if (pkg == null) {
// 應該要找到升級包,但沒找到(移除該APP)
msg = "Updated system package " + packageName
+ " no longer exists; removing its data";
// (實際上並非馬上移除)
} else {
// 如果有取到pkg,代表該APP存在Data區中,
// 不屬於System app,移除系統權限
msg = "Updated system package " + packageName
+ " no longer exists; rescanning package on data";
// 以下,刪除並重新掃描數據包
removePackageLI(pkg, true); // 刪除
try {
final File codePath = new File(pkg.getPath());
// 重新掃描
scanPackageTracedLI(codePath, 0, scanFlags, 0, null);
} catch (PackageManagerException e) {
Slog.e(TAG, "Failed to parse updated, ex-system package: "
+ e.getMessage());
}
}
// 如果我們還有一個包設置[ie.它是以前掃描並為系統所知]
// 但是,我們沒有該Pkg [即。從/data掃描它時出錯
// partition],徹底刪除包數據。
final PackageSetting ps = mSettings.getPackageLPr(packageName);
if (ps != null && mPackages.get(packageName) == null) {
// 移除data內出錯的數據包
removePackageDataLIF(ps, userIds, null, 0, false);
}
logCriticalInfo(Log.WARN, msg);
}
// 3.遍歷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);
for (int i1 = mDirsToScanAsSystem.size() - 1; i1 >= 0; i1--) {
final ScanPartition partition = mDirsToScanAsSystem.get(i1);
// 根據系統APP所在的目錄設定掃描的解析參數
if (partition.containsPrivApp(scanFile)) {
reparseFlags = systemParseFlags;
// 設定掃描參數
rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
| partition.scanFlag;
break;
}
if (partition.containsApp(scanFile)) {
reparseFlags = systemParseFlags;
rescanFlags = systemScanFlags | partition.scanFlag;
break;
}
}
if (rescanFlags == 0) {
Slog.e(TAG, "Ignoring unexpected fallback path " + scanFile);
continue;
}
//將PackageName對應的包設置數據(PackagesSetting)
//添加到mSetting的mPackages中
mSettings.enableSystemPackageLPw(packageName);
try {
// 掃描系統APP的升級包
final AndroidPackage newPkg = scanPackageTracedLI(
scanFile, reparseFlags, rescanFlags, 0, null);
// We rescanned a stub, add it to the list of stubbed system packages
if (newPkg.isStub()) {
stubSystemApps.add(packageName);
}
} /* 省略catch */
}
}
//解壓&安裝根系統應用
//該操做要確保最後執行,來確保所有存根被替代or禁用
// Stub(存根)
installSystemStubPackages(stubSystemApps, scanFlags);
...
}
// 清除升級列表
mExpectingBetter.clear();
// 取得Storage manage包名
mStorageManagerPackage = getStorageManagerPackageName();
// 解決保護action過濾器,只允許setup wizard為這些action有最高權限的過濾
mSetupWizardPackage = getSetupWizardPackageNameImpl();
...
// 讀取並更新要保留的package的上次使用時間
mPackageUsage.read(packageSettings);
mCompilerStats.read();
}
}
scanDirTracedLI - 分析 data 目錄內容#
/data
文件夾可成為 Data 分區,它個主用公用有兩個
儲存所有用戶的個人數據
儲存所有用戶的配置文件
接著來看 /data 目錄下的子目錄都放那些數據
/data 底下目錄 | 含意 |
---|---|
app | 儲存該收機裝置,自己安裝的 APP 應用 |
data | 儲存所有已安裝的 APP 數據,其中也包括 System APP 數據 |
app-private | APP 的私有儲存空間 |
app-lib | 儲存所有 APP 的 JNI Lib |
system | 存放系統配置文件 |
anr | 用於存放 ANR 發生時,系統生成的traces.text 文件 |
第四階段 - BOOT_PROGRESS_PMS_SCAN_END#
BOOT_PROGRESS_PMS_SCAN_END 階段升級後首次啟動,要清除不必要的緩存數據、權限,更新package.xml
檔案(packages.xml 用來儲存所有 APP 的信息)
SDK 版本更變,重新更新權限
OTA 升級後首次啟動,清除不要要緩存
OTA 英文全稱是Over-the-Air Technology
,即空間下載技術,是手機透過行動網絡對手機系統,應用程序進行管理的技術
權限更新完成後清理相關數據
透過 mSetting 的內容保存並更新 package.xml 文件,這樣以後 PKMS 創建時就會讀取到新的 Setting
// PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
...
// 進入第四階段
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
// 權限重置
mPermissionManager.onStorageVolumeMounted(
StorageManager.UUID_PRIVATE_INTERNAL, mIsUpgrade);
ver.sdkVersion = mSdkVersion;
// 如果是第一次啟動或從pre-M升級上來,並且是正常啟動,那我們需要初始化User定義的首選預設應用
if (!mOnlyCore && (mPromoteSystemApps || mFirstBoot)) {
for (UserInfo user : mInjector.getUserManagerInternal().getUsers(true)) {
mSettings.applyDefaultPreferredAppsLPw(user.id);
}
}
//在啟動期間確實為系統用戶準備儲存空間
//因為像是SettingsProvider、SystemUI無法等待使用者啟動
final int storageFlags;
if (StorageManager.isFileEncryptedNativeOrEmulated()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE;
}
...
// 在OTA升級成功後的首次啟動,不必要的緩存,但不清除應用程序的配置文件
if (mIsUpgrade && !mOnlyCore) {
Slog.i(TAG, "Build fingerprint changed; clearing code caches");
for (int i = 0; i < packageSettings.size(); i++) {
final PackageSetting ps = packageSettings.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
// 沒有應用會在這時啟動,所以不必凍結
clearAppDataLIF(ps.pkg, UserHandle.USER_ALL,
FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL
| Installer.FLAG_CLEAR_CODE_CACHE_ONLY
| Installer.FLAG_CLEAR_APP_DATA_KEEP_ART_PROFILES);
}
}
ver.fingerprint = Build.FINGERPRINT;
}
// 在Launcher中隱藏他們的icon(Android-Q之前的非系統應用)
if (!mOnlyCore && mIsPreQUpgrade) {
Slog.i(TAG, "Whitelisting all existing apps to hide their icons");
int size = packageSettings.size();
for (int i = 0; i < size; i++) {
final PackageSetting ps = packageSettings.valueAt(i);
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
continue;
}
ps.disableComponentLPw(PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
UserHandle.USER_SYSTEM);
}
}
// clear only after permissions and other defaults have been updated
mPromoteSystemApps = false;
// 所有的改變都在掃描中完成
ver.databaseVersion = Settings.CURRENT_DATABASE_VERSION;
// 更新package.xml
t.traceBegin("write settings");
writeSettingsLPrTEMP();
t.traceEnd();
...
}
}
第五階段 - BOOT_PROGRESS_PMS_READY#
BOOT_PROGRESS_PMS_READY:PKMS 最後階段
PackageInstallerService 用於管理安裝 Session 服務,每次安裝過程都會分配一個 SessionId
要求觸發 GC 回收內存
// PackageManagerService.java
public PackageManagerService(Injector injector, boolean onlyCore, boolean factoryTest,
final String buildFingerprint, final boolean isEngBuild,
final boolean isUserDebugBuild, final int sdkVersion, final String incrementalVersion) {
...
// CHECKSTYLE:OFF IndentationCheck
synchronized (mInstallLock) {
// writer
synchronized (mLock) {
...
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
...
// PermissionController是一個系統核心,預設同意&管理權限
mRequiredPermissionControllerPackage = getRequiredPermissionControllerLPr();
... 省略部分
// 取得安裝器服務
mInstallerService = mInjector.getPackageInstallerService();
...
// 讀取&更新dex檔案的用法
// 在PM init結束時執行這個操作,以便所有包都協調其數據目錄
// 建構可以驗證的文件並建構內存緩存
// 使用文件預計很小,因此與其它活動相比,加載&驗證它都滿花費時間的
final Map<Integer, List<PackageInfo>> userPackages = new HashMap<>();
for (int userId : userIds) {
userPackages.put(userId, getInstalledPackages(/*flags*/ 0, userId).getList());
}
mDexManager.load(userPackages);
if (mIsUpgrade) {
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_DURATION_REPORTED,
BOOT_TIME_EVENT_DURATION__EVENT__OTA_PACKAGE_MANAGER_INIT_TIME,
SystemClock.uptimeMillis() - startTime);
}
// 屬性被重構後,重構live computer
mLiveComputer = createLiveComputer();
}
}