PMS启动时序
本文面向已经知道 system_server 是系统服务宿主、了解 Binder 服务注册含义的读者。建议先阅读 Bootstrap服务、Binder调用源码地图 和 PMS架构全景。本文解决的问题不是“PMS 有哪些类”,而是 PMS 从 SystemServer 的一个同步调用,如何逐步变成可查询、可安装、能与其他系统服务协作的运行期服务。
启动时最容易混淆三个时间点:PackageManagerService.main() 返回、PackageManagerService.systemReady() 返回、第三方应用获准启动。它们不是同一个“ready”。读完本文,应能从 SystemServer.startBootstrapServices() 追到包状态恢复、系统包与 /data/app 扫描、Binder/Local 接口发布,再解释为什么应用数据准备的异步任务必须在 PHASE_THIRD_PARTY_APPS_CAN_START 前被等待。
本文只展开足以解释启动时序的扫描骨架。分区扫描规则、冲突处理、并行解析和 Settings 文件格式分别属于后续专题,避免在这里把所有启动代码压缩成一篇无法验证的“大全”。
1. 三道屏障
PMS 启动不是一次构造函数调用,而是三道职责不同的屏障。
| 屏障 | 入口 | 已完成的状态 | 尚未保证 |
|---|---|---|---|
| 核心构造 | PackageManagerService.main() 返回 | Settings 与扫描结果进入内存,查询 snapshot 建立,package/package_native 已发布 | 运行期 observer、默认权限、安装会话恢复未全部完成 |
| 系统就绪 | PackageManagerService.systemReady() 返回 | Settings/User/Permission/Installer 等子系统接入运行期,staged session 开始恢复 | 启动时异步 app-data 修复可能仍在执行 |
| 应用放行 | waitForAppDataPrepared() 返回 | system user 的关键应用数据修复与准备任务结束 | 不代表所有开机后台优化都已完成 |
下面的状态图只表达真实的生命周期屏障,不把内部数百个初始化动作伪装成单一状态。
第一个屏障建立“PMS 自己的世界”,第二个屏障把它接入“系统已经可协作的世界”,第三个屏障保护即将运行的应用不碰到尚未准备好的数据目录。把三者都称为“PMS 启动完成”,会掩盖 Binder 可达性、运行期副作用和应用数据一致性的不同边界。
2. 前置依赖
2.1 SystemServer入口
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
// SystemServer 主线程按固定阶段同步启动服务。
t.traceBegin("StartServices");
try {
startBootstrapServices(t);
startCoreServices(t);
startOtherServices(t);
startApexServices(t);
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
} finally {
t.traceEnd();
}调用方是 SystemServer.run(),owner 是 system_server 主线程。四个阶段是同步顺序:Bootstrap 未返回,Core 不会开始;未被局部捕获的异常会到达这里,被记录后重新抛出。PMS 的构造发生在 Bootstrap,但 systemReady() 位于 Other 阶段,因此两个阶段之间仍会启动大量依赖 PMS 查询能力的服务。
2.2 PMS之前
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
// 以下代码按 Android 17 源码中的先后顺序摘录;中间无关服务已省略。
ArtModuleServiceInitializer.setArtModuleServiceManager(
new ArtModuleServiceManager());
final Watchdog watchdog = Watchdog.getInstance();
watchdog.start();
PlatformCompat platformCompat = new PlatformCompat(mSystemContext);
ServiceManager.addService(Context.PLATFORM_COMPAT_SERVICE, platformCompat);
mSystemServiceManager.startService(FileIntegrityService.class);
Installer installer = mSystemServiceManager.startService(Installer.class);
ActivityTaskManagerService atm = mSystemServiceManager.startService(
ActivityTaskManagerService.Lifecycle.class).getService();
mActivityManagerService = ActivityManagerService.Lifecycle.startService(
mSystemServiceManager, atm);
mDataLoaderManagerService = mSystemServiceManager.startService(
DataLoaderManagerService.class);
mIncrementalServiceHandle = startIncrementalService();
mPowerManagerService = mSystemServiceManager.startService(
PowerManagerService.class);
mSystemServiceManager.startService(RecoverySystemService.Lifecycle.class);这段顺序说明“在 PMS 之前已经启动”不等于“PMS 构造函数会直接调用每一个服务”。真正由 main() 显式消费的是 Context、Installer、DomainVerificationService;Injector 还会从 ServiceManager、LocalServices 或 Context.getSystemService() 获取 PlatformCompat、AppOps、IncrementalManager 等对象。PowerManager、AMS/ATMS 和 RecoverySystem 已经存在,但不能据此虚构 PMS 对它们的直接构造依赖。
ArtModuleServiceInitializer 被刻意放在 PMS 前。源码注释指出 PMS 初始化会分配大量对象并触发 GC,而 ART module 类来自另一个 dex;提前触发 class linker 可以避免它稍后与 GC 的互斥冲突。这里的消费者不是 PMS 构造函数本身,而是 PMS 返回后初始化的 DexUseManagerLocal 与 ART 本地管理接口。
2.3 Display屏障
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
// PMS 会读取默认显示的 metrics,因此 DisplayManager 先启动并等待默认显示。
mDisplayManagerService = mSystemServiceManager.startService(
DisplayManagerService.class);
mSystemServiceManager.startBootPhase(
t, SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);
DomainVerificationService domainVerificationService =
new DomainVerificationService(
mSystemContext, SystemConfig.getInstance(), platformCompat);
mSystemServiceManager.startService(domainVerificationService);构造函数稍后会执行 getDisplay(Display.DEFAULT_DISPLAY).getMetrics(mMetrics)。因此这里不是“显示服务大概应该先启动”,而是有明确消费者的前置屏障:默认显示不存在时,PMS 无法得到解析资源所需的 metrics。DomainVerificationService 随后创建,并作为真实参数传给 PackageManagerService.main()。
3. 主线程调用
3.1 同步入口
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
if (!mRuntimeRestart) {
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__
PACKAGE_MANAGER_INIT_START,
SystemClock.elapsedRealtime());
}
t.traceBegin("StartPackageManagerService");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("packagemanagermain");
mPackageManagerService = PackageManagerService.main(
mSystemContext, installer, domainVerificationService,
mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("packagemanagermain");
}
mFirstBoot = mPackageManagerService.isFirstBoot();
mPackageManager = mSystemContext.getPackageManager();
t.traceEnd();main() 没有被投递到后台线程,SystemServer 主线程会同步等待构造、Settings 恢复和启动扫描结束。Watchdog 暂停的也只是“当前线程”的监控,并不是停止整个 Watchdog。finally 保证构造成功或抛异常时都恢复监控,否则一次失败可能让主线程永久脱离死锁检测。
mFirstBoot 只能在 main() 返回后读取,因为它由 Settings.readLPw() 是否找到持久化文件决定。mSystemContext.getPackageManager() 此时获得 framework 客户端对象;真正的 Binder 服务已在 main() 返回前注册。
mRuntimeRestart 只控制两次 statsd elapsed-time 事件是否上报,不跳过 PMS 构造。工厂测试模式则被转换为布尔参数,进入 PMS 状态,供后续条件路径使用。
3.2 总体时序
时序图中最重要的间隔是 Binder 发布到 systemReady() 之间。接口已经能被发现,但某些方法的语义仍受 mSystemReady、子系统 ready 状态和系统启动顺序约束。发布不是“所有后处理已经完成”,而是“构造出的核心查询状态可以进入服务发现体系”。
4. main工厂
4.1 锁与线程
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public static PackageManagerService main(Context context,
Installer installer,
@NonNull DomainVerificationService domainVerificationService,
boolean factoryTest) {
final TimingsTraceAndSlog t = new TimingsTraceAndSlog(
TAG + "Timing", Trace.TRACE_TAG_PACKAGE_MANAGER);
t.traceBegin("create package manager");
final PackageManagerTracedLock lock =
new PackageManagerTracedLock("mLock");
final PackageManagerTracedLock installLock =
new PackageManagerTracedLock("mInstallLock");
HandlerThread backgroundThread = new ServiceThread(
"PackageManagerBg", Process.THREAD_PRIORITY_BACKGROUND,
true /* allowIo */);
backgroundThread.start();
Handler backgroundHandler = new Handler(
backgroundThread.getLooper(), BACKGROUND_HANDLER_CALLBACK);
// Injector 的 producer 参数在下一段按职责展开。两把锁与后台线程由 main() 创建,再通过 Injector 交给 PMS 和子组件,因此它们的生命周期与 system_server 进程一致。mLock 保护包内存状态,mInstallLock 序列化 installd 与慢磁盘操作;PackageManagerBg 负责可异步执行的写入或清理。构造扫描本身仍由 SystemServer 主线程发起,并不会因为创建了 background thread 就自动并行化。
4.2 Injector装配
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
PackageManagerServiceInjector injector = new PackageManagerServiceInjector(
context, lock, installer, installLock, new PackageAbiHelperImpl(),
backgroundHandler, SYSTEM_PARTITIONS,
(i, pm) -> new ComponentResolver(
i.getUserManagerService(), pm.mUserNeedsBadging),
(i, pm) -> PermissionManagerService.create(context,
i.getSystemConfig().getAvailableFeatures()),
(i, pm) -> LocalServices.getService(AppOpsManagerInternal.class),
(i, pm) -> new UserManagerService(context, pm,
new UserDataPreparer(installer, installLock, context), lock),
(i, pm) -> new Settings(Environment.getDataDirectory(),
RuntimePermissionsPersistence.createInstance(),
i.getPermissionManagerServiceInternal(),
domainVerificationService, backgroundHandler, lock),
(i, pm) -> AppsFilterImpl.create(i,
i.getLocalService(PackageManagerInternal.class)),
(i, pm) -> (PlatformCompat) ServiceManager.getService("platform_compat"),
(i, pm) -> SystemConfig.getInstance(),
(i, pm) -> new DynamicCodeLogger(i.getInstaller()),
(i, pm) -> new ArtManagerService(i.getContext()),
(i, pm) -> ApexManager.getInstance(),
(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,
i.getDisplayMetrics(),
new PackageCacher(pm.mCacheDir, pm.mPackageParserCallback),
pm.mPackageParserCallback),
(i, pm) -> new PackageParser2(pm.mSeparateProcesses,
i.getDisplayMetrics(), null, pm.mPackageParserCallback),
(i, pm) -> new PackageParser2(pm.mSeparateProcesses,
i.getDisplayMetrics(), null, pm.mPackageParserCallback),
(i, pm, developerVerifierPackage) -> new PackageInstallerService(
i.getContext(), pm, i::getScanningPackageParser,
developerVerifierPackage),
(i, pm, cn) -> new InstantAppResolverConnection(
i.getContext(), cn,
Intent.ACTION_RESOLVE_INSTANT_APP_PACKAGE),
(i, pm) -> new ModuleInfoProvider(i.getContext()),
(i, pm) -> LegacyPermissionManagerService.create(i.getContext()),
(i, pm) -> domainVerificationService,
(i, pm) -> {
HandlerThread thread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_DEFAULT, true /* allowIo */);
thread.start();
return new PackageHandler(thread.getLooper(), pm);
},
new DefaultSystemWrapper(),
LocalServices::getService,
context::getSystemService,
(i, pm) -> IBackupManager.Stub.asInterface(
ServiceManager.getService(Context.BACKUP_SERVICE)),
(i, pm) -> new SharedLibrariesImpl(pm, i),
(i, pm) -> new CrossProfileIntentFilterHelper(
i.getSettings(), i.getUserManagerService(), i.getLock(),
i.getUserManagerInternal(), context),
(i, pm) -> new UpdateOwnershipHelper(),
(i, pm) -> new PackageMonitorCallbackHelper());Injector 保存依赖来源与 producer,构造函数通过 bootstrap(this) 把当前 PMS 设为 producer 参数,再按需取得对象。它解决的是创建顺序和可测试替换问题,不意味着所有对象都“懒到第一次 Binder 调用才创建”。例如 UserManager、ComponentResolver、PermissionManager、Settings 在构造早期立即被取出;PackageInstallerService 则要等扫描完成并确定 developer verifier 后才创建。
4.3 构造与发布
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
PackageManagerService m = new PackageManagerService(
injector, factoryTest, PackagePartitions.FINGERPRINT,
Build.IS_ENG, Build.IS_USERDEBUG, Build.VERSION.SDK_INT,
Build.VERSION.INCREMENTAL, Build.VERSION.SDK_INT_FULL);
// 构造完成后才注册兼容性监听器和用户类型 allowlist。
injector.getCompatibility().registerListener(
SELinuxMMAC.SELINUX_LATEST_CHANGES, selinuxChangeListener);
injector.getCompatibility().registerListener(
SELinuxMMAC.SELINUX_R_CHANGES, selinuxChangeListener);
m.installAllowlistedSystemPackages();
IPackageManagerImpl iPackageManager = m.new IPackageManagerImpl();
ServiceManager.addService("package", iPackageManager);
final PackageManagerNative pmn = new PackageManagerNative(m);
ServiceManager.addService("package_native", pmn);
return m;这里给出了发布不变量:构造函数正常返回之前,package 和 package_native 都不会加入 ServiceManager。远程调用者因此不会看到一个只装了一半 Settings 或尚未建立 snapshot 的 PMS。IPackageManagerImpl 是 Java Binder owner,PMS 本身不是 IPackageManager.Stub;PackageManagerNative 则为 native 客户端提供受限查询接口。
installAllowlistedSystemPackages() 可能修改各用户的系统包安装状态;若发生变化,它调度 package restrictions 和 Settings 写入。这个动作位于 Binder 发布前,避免首个远程查询观察到尚未应用用户类型 allowlist 的状态。
5. 构造阶段
5.1 状态owner
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
mInjector.bootstrap(this);
mLock = injector.getLock();
mPackageStateWriteLock = mLock;
mInstallLock = injector.getInstallLock();
LockGuard.installLock(mLock, LockGuard.INDEX_PACKAGES);
EventLog.writeEvent(
EventLogTags.BOOT_PROGRESS_PMS_START,
SystemClock.uptimeMillis());
// 先发布进程内接口,再让依赖它们的 producer 创建子系统。
LocalServices.addService(
PackageManagerInternal.class, new PackageManagerInternalImpl());
LocalManagerRegistry.addManager(
PackageManagerLocal.class, new PackageManagerLocalImpl(this));
LocalServices.addService(TestUtilityService.class, this);
mUserManager = injector.getUserManagerService();
mComponentResolver = injector.getComponentResolver();
mPermissionManager = injector.getPermissionManagerServiceInternal();
mSettings = injector.getSettings();Local 接口在构造函数早期注册,因为 AppsFilter 等同进程组件的 producer 会查询 PackageManagerInternal。这是一种受控的构造期可见性:LocalServices 已有对象引用,但外部 Binder 尚未发布;调用者范围被限制在 system_server 内部,且构造顺序由 Injector 控制。
随后 PMS 创建 BroadcastHelper、AppDataHelper、RemovePackageHelper、DeletePackageHelper、InstallPackageHelper、ResolveIntentHelper、DexOptHelper、StorageEventHelper 等编排组件。它们共享 PMS 的状态 owner,却各自承担不同写路径,后续安装、删除和解析文章会进入这些 helper。
5.2 Snapshot起点
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
synchronized (mLock) {
// 状态对象安装后立刻建立 live Computer,供构造期查询使用。
mSnapshotStatistics = new SnapshotStatistics();
sSnapshotPendingVersion.incrementAndGet();
mLiveComputer = createLiveComputer();
registerObservers(true);
}
Computer computer = mLiveComputer;
try (PackageManagerTracedLock installLock = mInstallLock.acquireLock()) {
synchronized (mLock) {
mHandler = injector.getHandler();
Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT);
// Settings 恢复与扫描在两把锁保护下继续。第一个 mLiveComputer 是构造期查询视图。Settings、resolver、包集合等 Watchable owner 已安装后,PMS 注册 observer;后续状态变化会使 snapshot 失效。构造尾部还会再建一次 live Computer,因为扫描和解析会补齐大量字段。
扫描期间同时持有 mInstallLock 与 mLock 是启动期特例:此时没有正常业务并发,代码优先保证 Settings、磁盘与内存索引的一致提交。构造结束后,mInstaller.setWarnIfHeld(mLock) 开始警告运行期在持有包锁时调用 installd 的慢路径,说明启动期锁策略不能照搬到正常运行期。
5.3 阶段图
这张图刻意把“读取旧状态”和“扫描磁盘事实”放在同一临界区:启动要把两类事实 reconcile 成新的 Settings、组件索引与包集合。它也解释了为什么 BOOT_PROGRESS_PMS_READY 不能简单理解为 systemReady():该事件发生在构造临界区内,表示启动扫描和 Settings 写回完成。
6. 恢复与扫描
6.1 Settings恢复
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
if (!SELinuxMMAC.readInstallPolicy()) {
throw new RuntimeException("Unable to load SELinux MMAC policy");
}
mFirstBoot = !mSettings.readLPw(
computer,
mInjector.getUserManagerInternal().getUsers(
false /* excludeDying */));
if (mFirstBoot) {
try {
mInstaller.setFirstBoot();
} catch (InstallerException e) {
// installd 通知失败会降级记录,不推翻 Settings 的 first-boot 判断。
Slog.w(TAG, "Could not set First Boot: ", e);
}
DexOptHelper.requestCopyPreoptedFiles();
}SELinux install policy 是硬前置:加载失败直接抛出,构造不能继续。Settings 则用返回值区分“没有文件的首次启动”和“读取到已有状态”。Installer.setFirstBoot() 失败被降级为 warning,说明 first-boot 状态 owner 仍是 PMS/Settings;通知 installd 失败不会把启动自动改判为非首次启动。
源码文件:frameworks/base/services/core/java/com/android/server/pm/Settings.java
try {
if (!readSettingsLPw(computer, users, originalFirstInstallTimes)) {
return false; // 没有 Settings 文件,调用方据此认定 first boot。
}
} finally {
if (!mVersion.containsKey(StorageManager.UUID_PRIVATE_INTERNAL)) {
Slog.wtf(PackageManagerService.TAG,
"No internal VersionInfo found in settings, using current.");
findOrCreateVersion(
StorageManager.UUID_PRIVATE_INTERNAL).forceCurrent();
}
}readLPw() 的 finally 会补齐缺失的 volume 版本信息,因此部分字段缺失不是立即终止启动。更底层的 ResilientAtomicFile 依次尝试 temporary backup、主文件和 reserve copy;XML 解析异常会删除损坏的当前副本并递归重试下一副本。这里存在“缺文件”“主文件损坏但可恢复”“所有副本都不可用”等不同语义,不能统称为 packages.xml 读取失败。
6.2 两段扫描
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
EventLog.writeEvent(
EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START,
startTime);
final VersionInfo ver = mSettings.getInternalVersion();
mIsUpgrade = !partitionsFingerprint.equals(ver.fingerprint);
mPriorSdkVersion = mIsUpgrade ? ver.sdkVersion : -1;
mInitAppsHelper = new InitAppsHelper(
this, mApexManager, mInstallPackageHelper,
mInjector.getSystemPartitions());
PackageParser2 packageParser =
mInjector.getScanningCachingPackageParser();
mOverlayConfig = mInitAppsHelper.initSystemApps(
packageParser, packageSettings, userIds, startTime);
mInitAppsHelper.initNonSystemApps(
packageParser, userIds, startTime);
packageParser.close();第一段扫描系统分区,第二段扫描非系统应用。升级由“当前分区 fingerprint 与 Settings 中记录值不同”决定,它影响旧包集合保存、权限重新授予、code cache 清理和默认 preferred app 等路径。PackageParser2.close() 位于两段扫描之后,表示这个扫描期 parser 的资源在进入 required-package 解析前已经释放。
源码文件:frameworks/base/services/core/java/com/android/server/pm/InitAppsHelper.java
EventLog.writeEvent(
EventLogTags.BOOT_PROGRESS_PMS_DATA_SCAN_START,
SystemClock.uptimeMillis());
if ((mScanFlags & SCAN_FIRST_BOOT_OR_UPGRADE)
== SCAN_FIRST_BOOT_OR_UPGRADE) {
fixInstalledAppDirMode();
}
scanDirTracedLI(
mPm.getAppInstallDir(), 0,
mScanFlags | SCAN_REQUIRE_KNOWN,
packageParser, mExecutorService, null);
List<Runnable> unfinishedTasks = mExecutorService.shutdownNow();
if (!unfinishedTasks.isEmpty()) {
throw new IllegalStateException(
"Not all tasks finished before calling close: "
+ unfinishedTasks);
}/data/app 扫描允许内部 executor 并行解析,但 initNonSystemApps() 返回前必须关闭 executor,并要求没有遗留任务。也就是说并行只优化阶段内部,不能越过 PMS 构造屏障。首次启动或升级时还会修正安装目录 mode;普通启动不会无条件执行该修复。
6.3 写回与异步任务
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
EventLog.writeEvent(
EventLogTags.BOOT_PROGRESS_PMS_SCAN_END,
SystemClock.uptimeMillis());
// OTA 路径清理 code cache 后,再异步修复 system user 的应用数据。
mPrepareAppDataFuture = mAppDataHelper.fixAppsDataOnBoot();
writeSettingsLPrTEMP();
EventLog.writeEvent(
EventLogTags.BOOT_PROGRESS_PMS_READY,
SystemClock.uptimeMillis());
// 扫描后才能确定 installer/verifier 等系统包并创建 installer service。
mInstallerService = mInjector.getPackageInstallerService(
mDeveloperVerificationServiceProvider);
// 扫描补齐了状态,重建 live 查询视图。
mLiveComputer = createLiveComputer();fixAppsDataOnBoot() 返回 Future,构造函数不在这里等待。这样 SystemServer 可以继续启动其他服务,同时后台线程处理 app-data fixup;真正的消费屏障被推迟到第三方应用启动前。BOOT_PROGRESS_PMS_READY 因而只覆盖扫描与 Settings 写回,不覆盖该 Future 的完成时间,也不覆盖稍后的 systemReady()。
7. 发布后阶段
7.1 Local消费者
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
t.traceBegin("DexUseManagerLocal");
// PackageManagerLocal 已在 PMS 构造早期注册;这里创建它的首个重要消费者。
LocalManagerRegistry.addManager(
DexUseManagerLocal.class,
DexUseManagerLocal.createInstance(mSystemContext));
t.traceEnd();
if (!mRuntimeRestart && !isFirstBootOrUpgrade()) {
FrameworkStatsLog.write(
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME_REPORTED,
FrameworkStatsLog.BOOT_TIME_EVENT_ELAPSED_TIME__EVENT__
PACKAGE_MANAGER_INIT_READY,
SystemClock.elapsedRealtime());
}源码注释要求 DexUseManagerLocal 在 PackageManagerLocal 注册后、PMS 开始处理 notifyDexLoad Binder 调用前初始化。它揭示了一个细粒度顺序:Binder 服务虽已发布,但 SystemServer 紧接着补齐一个 Binder 调用会依赖的 local consumer。statsd 的 PACKAGE_MANAGER_INIT_READY 也在这个动作之后,并且仅在非 runtime restart、非 first boot、非 upgrade 时记录。
7.2 DexOpt与维护
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
t.traceBegin("ArtManagerLocal");
DexOptHelper.initializeArtManagerLocal(
context, mPackageManagerService);
t.traceEnd();
t.traceBegin("UpdatePackagesIfNeeded");
try {
Watchdog.getInstance().pauseWatchingCurrentThread("dexopt");
mPackageManagerService.updatePackagesIfNeeded();
} catch (Throwable e) {
reportWtf("update packages", e);
} finally {
Watchdog.getInstance().resumeWatchingCurrentThread("dexopt");
}
t.traceEnd();
mPackageManagerService.updateMetricsIfNeeded();
try {
mPackageManagerService.performFstrimIfNeeded();
} catch (Throwable e) {
reportWtf("performing fstrim", e);
}这些动作发生在 startOtherServices(),不是 PMS 构造函数的一部分。dexopt upgrade 可能很慢,所以再次暂停当前线程 Watchdog;异常被 reportWtf 记录后继续启动。fstrim 同样是可降级维护动作。与之对比,构造函数的不变量失败没有局部 catch,会阻止 main() 返回和 Binder 发布。
8. systemReady屏障
8.1 调用位置
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
mSystemServiceManager.startService(PermissionPolicyService.class);
t.traceBegin("MakePackageManagerServiceReady");
mPackageManagerService.systemReady();
t.traceEnd();
// PMS ready 后才继续 CrashRecovery、DisplayManager 等服务的 ready 阶段。
mSystemServiceManager.startService(
CRASHRECOVERY_MODULE_LIFECYCLE_CLASS);PMS systemReady() 前,PermissionPolicyService 已启动;调用本身没有像 DisplayManager systemReady() 那样用局部 try/catch 包住。因此该方法抛出的异常会离开当前启动阶段,并最终进入 SystemServer.run() 的服务启动失败处理。这里要求 PMS 完成一组不可随意跳过的运行期接线。
8.2 状态切换
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public void systemReady() {
PackageManagerServiceUtils.enforceSystemOrRoot(
"Only the system can claim the system is ready");
final ContentResolver resolver = mContext.getContentResolver();
if (mReleaseOnSystemReady != null) {
for (int i = mReleaseOnSystemReady.size() - 1; i >= 0; --i) {
final File dstCodePath = mReleaseOnSystemReady.get(i);
F2fsUtils.releaseCompressedBlocks(resolver, dstCodePath);
}
mReleaseOnSystemReady = null;
}
mSystemReady = true;
// 后续 observer 与子系统回调消费这个生命周期状态。调用者必须是 system 或 root。切换状态前,PMS 释放延迟到 system-ready 的压缩块资源,并把列表置空,防止重复释放。mSystemReady = true 是运行期行为的开关,但不是方法终点;后面还有同步 I/O、user/app reconcile、权限授予与安装会话恢复。
8.3 子系统接线
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
ContentObserver co = new ContentObserver(mHandler) {
@Override
public void onChange(boolean selfChange) {
final boolean ephemeralFeatureDisabled =
Global.getInt(resolver, Global.ENABLE_EPHEMERAL_FEATURE, 1) == 0;
for (int userId : UserManagerService.getInstance().getUserIds()) {
final boolean instantAppsDisabledForUser =
ephemeralFeatureDisabled || Secure.getIntForUser(
resolver, Secure.INSTANT_APPS_ENABLED, 1, userId) == 0;
mWebInstantAppsDisabled.put(userId, instantAppsDisabledForUser);
}
}
};
mContext.getContentResolver().registerContentObserver(
android.provider.Settings.Global.getUriFor(
Global.ENABLE_EPHEMERAL_FEATURE),
false, co, USER_ALL);
mContext.getContentResolver().registerContentObserver(
android.provider.Settings.Secure.getUriFor(
Secure.INSTANT_APPS_ENABLED),
false, co, USER_ALL);
co.onChange(true);
mAppsFilter.onSystemReady(
LocalServices.getService(PackageManagerInternal.class));
CarrierAppUtils.disableCarrierAppsUntilPrivileged(
mContext.getOpPackageName(), UserHandle.USER_SYSTEM, mContext);
synchronized (mLock) {
ArrayList<Integer> changed =
mSettings.systemReady(mComponentResolver);
for (int userId : changed) {
mSettings.writePackageRestrictionsLPr(userId);
}
}
mUserManager.systemReady();
final StorageManager storage =
mInjector.getSystemService(StorageManager.class);
storage.registerListener(mStorageEventHelper);
mInstallerService.systemReady();
mUserManager.reconcileUsers(
StorageManager.UUID_PRIVATE_INTERNAL);
mStorageEventHelper.reconcileApps(
snapshotComputer(), StorageManager.UUID_PRIVATE_INTERNAL);
mPermissionManager.onSystemReady();这一段把构造期 owner 转入运行期:Settings 清理或修正组件引用并写回 per-user restrictions;UserManager 与 StorageManager 建立用户和卷的变化通道;PackageInstallerService 读取会话、过期旧会话、清理孤立 stage/icon;PermissionManager 开启系统就绪后的策略。
mSettings.systemReady() 在 mLock 内返回发生变化的 userId,PMS 随即同步写回对应 restrictions。消费者不是一个抽象的“系统”,而是后续组件解析、启动决策和用户查询。Storage listener 则让启动后挂载/卸载卷的事件进入 StorageEventHelper。
8.4 权限与会话
源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
for (int i = 0; i < livingUserCount; i++) {
final int userId = livingUsers.get(i).id;
final boolean isPermissionUpgradeNeeded = !Objects.equals(
mPermissionManager.getDefaultPermissionGrantFingerprint(userId),
Build.FINGERPRINT);
if (isPermissionUpgradeNeeded) {
grantPermissionsUserIds = ArrayUtils.appendInt(
grantPermissionsUserIds, userId);
}
}
for (int userId : grantPermissionsUserIds) {
mLegacyPermissionManager.grantDefaultPermissions(userId);
mPermissionManager.setDefaultPermissionGrantFingerprint(
Build.FINGERPRINT, userId);
}
if (grantPermissionsUserIds == EMPTY_INT_ARRAY) {
mLegacyPermissionManager
.scheduleReadDefaultPermissionExceptions();
}
// 放在最后,因为恢复 staged install 可能再次触发安装链路。
mInstallerService.restoreAndApplyStagedSessionIfNeeded();
mExistingPackages = null;默认权限不是每次启动都重授:只有某用户保存的 grant fingerprint 与当前 build fingerprint 不同才进入同步授予;没有用户需要升级时,系统改为异步预读 default-permission exceptions。这里既有条件路径,也有不同生效时机。
staged session 恢复被源码明确要求放在最后,因为它可能触发原子 APK 安装,并反向依赖其他组件已 ready。mExistingPackages 只服务升级期比较,恢复完成后被清空,结束其启动期生命周期。
9. AppData屏障
9.1 后台修复
源码文件:frameworks/base/services/core/java/com/android/server/pm/AppDataHelper.java
public Future<?> fixAppsDataOnBoot() {
final @StorageManager.StorageFlags int storageFlags;
if (StorageManager.isFileEncrypted()) {
storageFlags = StorageManager.FLAG_STORAGE_DE;
} else {
storageFlags = StorageManager.FLAG_STORAGE_DE
| StorageManager.FLAG_STORAGE_CE;
}
final List<String> deferPackages;
try (PackageManagerTracedLock installLock =
mPm.mInstallLock.acquireLock()) {
deferPackages = reconcileAppsDataLI(
StorageManager.UUID_PRIVATE_INTERNAL,
UserHandle.USER_SYSTEM, storageFlags,
true /* migrateAppData */,
true /* onlyCoreApps */);
}
Future<?> prepareAppDataFuture = SystemServerInitThreadPool.submit(() -> {
try {
mInstaller.fixupAppData(
StorageManager.UUID_PRIVATE_INTERNAL,
StorageManager.FLAG_STORAGE_DE
| StorageManager.FLAG_STORAGE_CE);
} catch (Installer.InstallerException e) {
Slog.w(TAG, "Trouble fixing GIDs", e);
}
// 省略:对 deferPackages 建批次,并在 mInstallLock 下执行。
}, "prepareAppData");
return prepareAppDataFuture;
}FBE 设备在早期只能保证 device-encrypted 数据,非 FBE 设备同时处理 DE/CE。同步部分先 reconcile system user 的 core apps,慢的全量 fixup 和 deferred batch 进入 SystemServerInitThreadPool。Installer 失败在任务内记录 warning;任务仍会走到结束,从而允许上层屏障获得确定的完成状态,而不是无限等待。
9.2 第三方放行
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
// 网络等服务完成 ready 后,等待 PMS 构造期创建的 Future。
mPackageManagerService.waitForAppDataPrepared();
t.traceBegin("PhaseThirdPartyAppsCanStart");
if (webviewPrep != null) {
ConcurrentUtils.waitForFutureNoInterrupt(
webviewPrep, WEBVIEW_PREPARATION);
}
mSystemServiceManager.startBootPhase(
t, SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);
t.traceEnd();源码文件:frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
public void waitForAppDataPrepared() {
if (mPrepareAppDataFuture == null) {
return;
}
ConcurrentUtils.waitForFutureNoInterrupt(
mPrepareAppDataFuture, "wait for prepareAppData");
mPrepareAppDataFuture = null;
}Future 的 owner 是 PMS,消费者是 SystemServer 的第三方应用启动屏障。等待完成后字段置空:既释放引用,也使重复调用成为快速返回。这个细节说明“PMS systemReady 已完成”仍不足以放行第三方代码,应用数据目录的一致性还有独立异步生命周期。
10. 失败与清理
启动代码有四类不同的失败语义。
硬不变量失败时,构造函数不返回,main() 后面的 ServiceManager 注册不会执行。Watchdog 仍由 SystemServer 的 finally 恢复。此时不能描述为“PMS 注册后不可用”,因为服务根本没有发布。
Settings 损坏优先恢复,而不是直接当作首次启动。ResilientAtomicFile.openRead() 先看 temporary backup,再看主文件,最后看 reserve copy;解析异常通过 failRead() 删除当前坏副本后重试。这里有一个重要边界:异常分支故意忽略递归重试的返回值,避免把“启动时原本存在但损坏”的 Settings 标成 first boot;初次打开就没有文件,或解析入口直接返回“无 start tag”时,才会把 false 传回 PMS。
Installer 的 first-boot 通知、app-data GID fixup、单包 app-data 创建、dexopt upgrade、fstrim 各自有局部降级逻辑。它们不能合并成“任何启动错误都会重启 system_server”,也不能反过来声称都不会影响启动。判断方法是看异常是否被当前 owner 捕获、是否有替代副本或重试、以及上层是否还有同步屏障。
11. 观测与测试
11.1 时间埋点
PMS 启动同时使用三类时间证据。
| 证据 | 起点与终点 | 适合回答的问题 |
|---|---|---|
| Perfetto trace | StartPackageManagerService、create package manager、各内部 trace | 哪个同步阶段占用 SystemServer 主线程 |
| EventLog boot progress | PMS_START、SYSTEM_SCAN_START、DATA_SCAN_START、SCAN_END、PMS_READY | Settings/扫描各阶段的墙钟顺序与耗时 |
| statsd boot event | PACKAGE_MANAGER_INIT_START/READY | 普通非升级启动的整体 PMS 初始化时间 |
statsd 的 READY 有条件过滤,EventLog 的 PMS_READY 又早于 systemReady(),所以分析日志时必须先确认事件语义,不能只按名字比较时间。首次启动和 OTA 应优先看 EventLog/trace,因为 SystemServer 明确不写普通启动的 PACKAGE_MANAGER_INIT_READY 事件。
下面的命令只读设备日志。输入是本次开机的 log buffer,输出是 PMS 五个阶段的时间戳;如果 buffer 已轮转,缺失事件不能反推代码没有执行。
# 输入:当前设备的 events buffer。
# 输出:PMS 构造、system/data 扫描与构造 ready 的 EventLog 时间线。
adb logcat -b events -d \
| rg 'boot_progress_pms_(start|system_scan_start|data_scan_start|scan_end|ready)'
# 输入:当前设备可用的服务名表。
# 输出:main() 返回后应出现的 Java 与 native Binder 服务。
adb shell service list \
| rg '(^|[[:space:]])package(_native)?:'11.2 Settings恢复测试
源码文件:frameworks/base/services/tests/PackageManagerServiceTests/server/src/com/android/server/pm/PackageManagerSettingsTests.java
@Test
public void testReadMalformedPackagesXmlKeySetSettings() throws Exception {
writeReserveCopyOldFiles();
writeCorruptedPackagesXml();
Settings settings = makeSettings();
assertThat(settings.readLPw(
computer, createFakeUsers()), is(true));
verifyKeySetMetaData(settings);
}测试输入是“有效 reserve copy + 损坏的主 packages.xml”。动作是调用启动期同一个 Settings.readLPw();断言不仅要求返回 true,还核对 keyset metadata,防止只恢复了空壳。它支持“主副本损坏时会回退并恢复状态”的结论,但没有覆盖整个 SystemServer 启动顺序,也没有证明任意磁盘损坏都可恢复。
更接近真实 I/O 的 host test 会先写出大于一页的 packages.xml,启用 fs-verity,再直接损坏块设备上的第一页或第二页,最后运行设备侧 testReadSettings。它分别覆盖 header 解析失败和 XML 中段解析失败,反向验证 reserve copy 不只是单元测试 mock 路径。
11.3 Installer测试
源码文件:frameworks/base/services/tests/mockingservicestests/src/com/android/server/pm/PackageInstallerServiceTest.java
@Test
public void testWriteAndReadVerificationPolicyPerUser() {
doReturn(new int[] {
UserHandle.USER_SYSTEM, TEST_USER_ID, TEST_USER_ID_2
}).when(mPms.mUserManager).getUserIds();
final PackageInstallerService service = new PackageInstallerService(
rule.mocks().getContext(), mPms, null,
new ComponentName(mPackageName, this.getClass().getName()));
service.systemReady();
// 省略:为三个用户写入不同 policy。
final PackageInstallerService service2 = new PackageInstallerService(
rule.mocks().getContext(), mPms, null,
new ComponentName(mPackageName, this.getClass().getName()));
service2.systemReady();
assertThat(service2.getDeveloperVerificationPolicy(
UserHandle.USER_SYSTEM)).isEqualTo(policyForSystemUser);
assertThat(service2.getDeveloperVerificationPolicy(
TEST_USER_ID)).isEqualTo(policyForTestUser);
}测试把第二个实例当作重启后的服务:第一次 systemReady() 建立 per-user 默认值并持久化修改,第二次 systemReady() 重新读取文件,断言各用户策略被保留。它支持“PackageInstallerService 的持久化会话/策略恢复属于 systemReady 阶段”这一生命周期判断;它没有覆盖 PMS 外层 systemReady() 的全部顺序,也不证明 staged APK 恢复成功。
当前源码测试更擅长分别验证 Settings 恢复、PackageInstallerService ready 行为和 PMS 子组件,不存在一个单元测试可以替代 SystemServer 真实启动时序。完整顺序仍要由调用方源码、trace/EventLog 与设备启动实验共同判断。
12. 源码复盘
可以用下面三条路径检查自己是否真正掌握了启动主线。
第一,从 SystemServer.startBootstrapServices() 的 StartPackageManagerService 开始,指出默认显示、DomainVerificationService 和 Watchdog 各自提供什么边界,再追到 ServiceManager.addService("package", ...)。如果中间跳过 Settings 恢复和两段扫描,就还没有解释 Binder 发布前为何已有一致查询状态。
第二,给定“boot_progress_pms_ready 已出现,但第三方应用仍未启动”的现象,应继续检查 MakePackageManagerServiceReady、prepareAppData Future、WebView preparation 和 PHASE_THIRD_PARTY_APPS_CAN_START,而不是把 PMS_READY 当作系统可启动应用的最终事件。
第三,给定“主 packages.xml 损坏”的故障,应沿 Settings.readLPw()、readSettingsLPw()、ResilientAtomicFile.openRead()/failRead() 判断当前读取的是 temporary backup、主文件还是 reserve copy,并区分“初次就没有文件”与“已有文件解析异常后重试”。后者即使最终没有可用副本,外层也会保留非 first-boot 语义,避免把损坏恢复错误地当成新设备初始化。
后续“PMS构造函数”专题将按字段与 helper 展开构造内部阶段;系统包和 /data/app 的目录扫描、并行解析及冲突处理则由包扫描专题继续追踪。本文的边界是解释这些动作为什么必须发生在 Binder 发布和第三方应用放行之前。
