PKMS
PKMS 就是 PackageManagerServervice:它是透过 SystemServer 进程 启动,该服务会 扫描系统中特定的目录,寻找里面的APK格式文件,并对这些文件进行解析(得到AppInfo相关讯息),最后完成安装
PKMS 会在安装应用的过程中解析 APK 中的 AndroidManifest.xml 文件(解析出 Android 四大组件),这些解析完的信息会保存在 Android 系统中,方便系统随时取用
PMS - 主要功能
扫描 .apk 文件,安装 系统应用、本地应用
Parser AndroidManifest.xml 清单文件,分析出四大零组件、权限…等等信息,并储存在 PKMS 方便查询
管理本地应用,其中包括 安装、卸载、查询 APK 信息 …等等功能
分配应用程序的 UID、GID
透过GID(Group群组ID)来管理权限管理,在某个群组中才能使用某些功能
PKMS - AIDL 使用
一般来说我们可以透过Context#getPackageManager()方法 来取得 PKMS 服务(其实它是取得 KMS 的代理),PackageManager 是抽象,实作类是 ApplicationPackageManager
// 调用 PKMS 方式
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// AIDL 代理对象
// @ getPackageManager 分析
PackageManager packageManager = this.getBaseContext().getPackageManager();
}ServiceManager 取得 PKMS - IPackageManager 代理
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 是 init 进程所孵化的第一个进程,在里面会有许多系统服务会启动,而其中又区分为三种
启动引导服务(startBootstrapServices):PKMS 就是在这里启动
核心进程(startCoreServices)
其他服务(startOtherServices)
// 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 - PKMS 启动部分
启动 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 */
}
}
... 省略部分
}分析 startOtherServices - PKMS 后续操作
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 - 初始化 PKMS 物件 - Injector
透过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取得的数据则是单例
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;
}IInject 是 PKMS 中的一个内部类,可以透过它来达到 单例的功能 (并且有延迟加载的功能)、其他类可以取得PKMS实例
// 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;
}
}
// 透过 Singleton 泛型创建出来的都是单例对象
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;
// 透过 injector 取得需要物件
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) {
// 启动 PackageManager Thread,负责 apk 安装、卸载
mHandler = injector.getHandler();
// 进程纪录 Handler
mProcessLoggingHandler = new ProcessLoggingHandler();
// 监听 PackageManager Thread 是否超时10分钟
Watchdog.getInstance().addThread(mHandler,
// WATCHDOG_TIMEOUT => 10 分鐘
WATCHDOG_TIMEOUT);
... 省略部分
// 读取安装相关的 SELinux 策略
SELinuxMMAC.readInstallPolicy();
// 读取并解析 /data/system 中的 xml 文件
//
// @ 分析 readLPw 方法 !!!!!
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,
... 省略部分
//真正new出物件的地方
// @追踪Settings建构方法
(i, pm) -> new Settings(Environment.getDataDirectory(), // /data 資料夾
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"); // mSystemDir 目錄指向 '/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
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
readSharedUserLPw(parser, users);
} ... 省略部分 else if
else {
... log
XmlUtils.skipCurrentTag(parser);
}
}
str.close();
} /* 省略 catch、finally */
... 省略部分
return true;
}Setting - 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);
// package name 是必须
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
// @ 分析 addPackageLPw
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 */
}Setting#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;
}AppIdSettingMap#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;
}Setting - 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); // "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 {
// @ 分析 addSharedUserLPw 函數
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;
}AppIdSettingMap#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;
}回到 Setting#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;
}
// 使用共享 ID,取得对应的安装物件
final Object idObj = getSettingLPr(sharedUserAppId);
if (idObj instanceof SharedUserSetting) {
final SharedUserSetting sharedUser = (SharedUserSetting) idObj;
// @ 查看 addPackageSettingLPw
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
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());
// 1. 扫描 /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阶段:OAT 升级后首次启动,要清除不必要的缓存数据、权限,更新 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();
}
}
... 省略部分
// 在打开应用 zip 后,确保他们都刷新,并进行 GC 回收
VMRuntime.getRuntime().requestConcurrentGC();
mInstaller.setWarnIfHeld(mLock);
... 省略部分
}