前言
PMS 的创建过程分为两个部分进行讲解, 分别是 SyetemServer 处理部分和 PMS 构造方法. 其中 SyetemServer 处理部分和 AMS 和 WMS 的创建过程是类似的, 可以将它们进行对比, 这样可以更好的理解和记忆这一知识点.
1. SyetemServer 处理部分
PMS 是在 SyetemServer 进程中被创建的, SyetemServer 进程用来创建系统服务, 不了解它的可以查看 Android 系统启动流程 (三) 解析 SyetemServer 进程启动过程 http://liuwangshu.cn/framework/booting/3-syetemserver.html 这篇文章. 从 SyetemServer 的入口方法 main 方法开始讲起, 如下所示. frameworks/base/services/java/com/android/server/SystemServer.java
- public static void main(String[] args) {
- new SystemServer().run();
- }
复制代码
main 方法中只调用了 SystemServer 的 run 方法, 如下所示. frameworks/base/services/java/com/android/server/SystemServer.java
- 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. 从注释 3,4,5 的方法可以看出, 官方把系统服务分为了三种类型, 分别是引导服务, 核心服务和其他服务, 其中其他服务是一些非紧要和一些不需要立即启动的服务. 这些系统服务总共有 100 多个, 我们熟知的 AMS 属于引导服务, WMS 属于其他服务, 本文要讲的 PMS 属于引导服务, 因此这里列出引导服务以及它们的作用, 见下表.
引导服务 | 作用 |
---|---|
Installer | 系统安装 apk 时的一个服务类,启动完成 Installer 服务之后才能启动其他的系统服务 |
ActivityManagerService | 负责四大组件的启动、切换、调度。 |
PowerManagerService | 计算系统中和 Power 相关的计算,然后决策系统应该如何反应 |
LightsService | 管理和显示背光 LED |
DisplayManagerService | 用来管理所有显示设备 |
UserManagerService | 多用户模式管理 |
SensorService | 为系统提供各种感应器服务 |
PackageManagerService | 用来对 apk 进行安装、解析、删除、卸载等等操作 |
查看启动引导服务的注释 3 处的 startBootstrapServices 方法. frameworks/base/services/java/com/android/server/SystemServer.java
- 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 创建时所需要的参数, 从这里就可以看出系统服务之间是有依赖关系的, 它们的启动顺序不能随意被更改.
2. PMS 构造方法
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 系统的事件日志.
- BOOT_PROGRESS_PMS_START(开始阶段)
- BOOT_PROGRESS_PMS_SYSTEM_SCAN_START(扫描系统阶段)
- BOOT_PROGRESS_PMS_DATA_SCAN_START(扫描 Data 分区阶段)
- BOOT_PROGRESS_PMS_SCAN_END(扫描结束阶段)
- BOOT_PROGRESS_PMS_READY(准备阶段)
2.1 开始阶段
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 中的成员变量, 下面简单介绍这些成员变量.
mSettings : 用于保存所有包的动态设置. 注释 1 处将系统进程的 sharedUserId 添加到 Settings 中, sharedUserId 用于进程间共享数据, 比如两个 App 的之间的数据是不共享的, 如果它们有了共同的 sharedUserId, 就可以运行在同一个进程中共享数据.
mInstaller :Installer 继承自 SystemService, 和 PMS,AMS 一样是系统的服务(虽然名称不像是服务),PMS 很多的操作都是由 Installer 来完成的, 比如 APK 的安装和卸载. 在 Installer 内部, 通过 IInstalld 和 installd 进行 Binder 通信, 由位于 nativie 层的 installd 来完成具体的操作.
systemConfig: 用于得到全局系统配置信息. 比如系统的权限就可以通过 SystemConfig 来获取.
mPackageDexOptimizer : Dex 优化的工具类.
mHandler(PackageHandler 类型) :PackageHandler 继承自 Handler, 在注释 3 处它绑定了后台线程 ServiceThread 的消息队列. PMS 通过 PackageHandler 驱动 APK 的复制和安装工作, 具体的请看在 Android 包管理机制 (三)PMS 处理 APK 的安装 http://liuwangshu.cn/framework/pms/3-pms-install.html 这篇文章. PackageHandler 处理的消息队列如果过于繁忙, 有可能导致系统卡住, 因此在注释 4 处将它添加到 Watchdog 的监测集中. Watchdog 主要有两个用途, 一个是定时检测系统关键服务(AMS 和 WMS 等) 是否可能发生死锁, 还有一个是定时检测线程的消息队列是否长时间处于工作状态(可能阻塞等待了很长时间). 如果出现上述问题, Watchdog 会将日志保存起来, 必要时还会杀掉自己所在的进程, 也就是 SystemServer 进程.
sUserManager(UserManagerService 类型) : 多用户管理服务.
除了创建这些关键对象, 在开始阶段还有一些关键代码需要去讲解:
注释 1 处和注释 2 处加了两个锁, 其中 mInstallLock 是安装 APK 时需要的锁, 保护所有对 installd 的访问; mPackages 是更新 APK 时需要的锁, 保护内存中已经解析的包信息等内容.
注释 5 处后的代码创建了一些 Data 分区中的子目录, 比如 / data/app.
注释 6 处会解析 packages.xml 等文件的信息, 保存到 Settings 的对应字段中. packages.xml 中记录系统中所有安装的应用信息, 包括基本信息, 签名和权限. 如果 packages.xml 有安装的应用信息, 那么注释 6 处 Settings 的 readLPw 方法会返回 true,mFirstBoot 的值为 false, 说明 PMS 不是首次被启动.
2.2 扫描系统阶段
- ...
- 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 点:
创建 / system 的子目录, 比如 / system/framework,/system/priv-app 和 / system/app 等等
扫描系统文件, 比如 / vendor/overlay,/system/framework,/system/app 等等目录下的文件.
对扫描到的系统文件做后续处理.
主要来说第 3 点, 一次 OTA 升级对于一个系统 App 会有三种情况:
这个系统 APP 无更新.
这个系统 APP 有更新.
新的 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 分区后再做处理.
2.3 扫描 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 分区阶段主要做了以下几件事:
扫描 / data/app 和 / data/app-private 目录下的文件.
遍历 possiblyDeletedUpdatedSystemApps 列表, 注释 1 处如果这个系统 App 的包信息不在 PMS 的变量 mPackages 中, 说明是残留的 App 信息, 后续会删除它的数据. 注释 2 处如果这个系统 App 的包信息在 mPackages 中, 说明是存在于 Data 分区, 不属于系统 App, 那么移除其系统权限.
遍历 mExpectingBetter 列表, 注释 3 处根据系统 App 所在的目录设置扫描的解析参数, 注释 4 处的方法内部会将 packageName 对应的包设置数据 (PackageSetting) 添加到 mSettings 的 mPackages 中. 注释 5 处扫描系统 App 的升级包, 最后清除 mExpectingBetter 列表.
2.4 扫描结束阶段
- // 打印扫描结束阶段日志
- 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);
复制代码
扫描结束结束阶段主要做了以下几件事:
如果当前平台 SDK 版本和上次启动时的 SDK 版本不同, 重新更新 APK 的授权.
如果是第一次启动或者是 Android M 升级后的第一次启动, 需要初始化所有用户定义的默认首选 App.
OTA 升级后的第一次启动, 会清除代码缓存目录.
把 Settings 的内容保存到 packages.xml 中, 这样此后 PMS 再次创建时会读到此前保存的 Settings 的内容.
2.5 准备阶段
- 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 http://liuwangshu.cn/framework/pms/2-packageinstaller-apk.html 这篇文章中提到过 PackageInstallerService. 注释 2 处进行一次垃圾收集. 注释 3 处将 PackageManagerInternalImpl(PackageManager 的本地服务) 添加到 LocalServices 中, LocalServices 用于存储运行在当前的进程中的本地服务.
3. 总结
本篇文章介绍了 PMS 的创建过程, 分为两个部分, 分别是 SyetemServer 处理部分和 PMS 构造方法, PMS 构造方法又分为 5 个部分, 分别是开始阶段, 扫描系统阶段, 扫描 Data 分区阶段, 扫描结束阶段和准备阶段.
来源: https://juejin.im/post/5b605f28e51d4534b93f5251