APEX服务
startApexServices() 位于 SystemServer 服务启动链的最后。它不扫描任意 /apex 目录,而是消费 ApexManager 已经根据 active APEX 包整理出的 ApexSystemServiceInfo 列表;每个条目包含服务类名、可选 jar 路径和 init order。SystemServer 再按“类名 + 当前 classpath”或“类名 + standalone jar”两条分支启动,最后调用 sealStartedServices(),把“不能再启动新系统服务”变成 SystemServiceManager 的状态不变量。
1. 入口与调试开关
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java
private void startApexServices(
@NonNull TimingsTraceAndSlog t) {
// 仅用于 debug 构建中的 RescueParty 故障注入。
if (Build.IS_DEBUGGABLE
&& SystemProperties.getBoolean(
"debug.crash_system", false)) {
throw new RuntimeException();
}
t.traceBegin("startApexServices");
List<ApexSystemServiceInfo> services =
ApexManager.getInstance().getApexSystemServices();debug.crash_system 只在 debuggable 构建生效,用于验证 SystemServer 故障恢复;它不是 APEX 服务启动失败。正常路径从 ApexManager 获取已排序列表,并为每个服务建立独立 trace section。
2. APEX清单
源码文件:frameworks/base/services/core/java/com/android/server/pm/ApexManager.java
for (ParsedApexSystemService service
: scanResult.pkg.getApexSystemServices()) {
String minSdkVersion = service.getMinSdkVersion();
if (minSdkVersion != null
&& !UnboundedSdkLevel.isAtLeast(minSdkVersion)) {
continue;
}
String maxSdkVersion = service.getMaxSdkVersion();
if (maxSdkVersion != null
&& !UnboundedSdkLevel.isAtMost(maxSdkVersion)) {
continue;
}
if (scanResult.apexInfo.isActive) {
mApexSystemServices.add(new ApexSystemServiceInfo(
service.getName(), service.getJarPath(),
service.getInitOrder()));
}
}
Collections.sort(mApexSystemServices);清单只接受 active APEX 的服务,并先过滤 min_sdk_version/max_sdk_version。相同服务名会抛 duplicate 错误;同一 module 出现两个 active package 也会失败。initOrder 决定排序,SystemServer 不重新解释排序规则。
3. Classloader分支
源码文件:frameworks/base/services/java/com/android/server/SystemServer.java、frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
for (ApexSystemServiceInfo info : services) {
String name = info.getName();
String jarPath = info.getJarPath();
t.traceBegin("starting " + name);
if (TextUtils.isEmpty(jarPath)) {
mSystemServiceManager.startService(name);
} else {
mSystemServiceManager.startServiceFromJar(
name, jarPath);
}
t.traceEnd();
}无 jar path 的服务从 SystemServer 当前 classloader 加载;有 jar path 的服务使用 SystemServerClassLoaderFactory 创建/复用 PathClassLoader,再反射加载类。startServiceFromJar() 适用于 PRODUCT_STANDALONE_SYSTEM_SERVER_JARS 或 APEX standalone jar,不应替代编译期可见的显式 startService(Class)。
4. 启动语义
public SystemService startServiceFromJar(
String className, String path) {
PathClassLoader loader =
SystemServerClassLoaderFactory.getOrCreateClassLoader(
path, this.getClass().getClassLoader(),
isJarInTestApex(path));
Class<SystemService> serviceClass =
loadClassFromLoader(className, loader);
return startService(serviceClass);
}
private void startService(@NonNull SystemService service) {
String className = service.getClass().getName();
if (mServiceClassnames.contains(className)) {
Slog.i(TAG, "Not starting an already started service "
+ className);
return;
}
mServiceClassnames.add(className);
mServices.add(service);
service.onStart();
}SystemServiceManager 先按 class name 去重,再把实例加入 mServices,最后调用 onStart()。类找不到会抛出带 classloader/path 的 RuntimeException;onStart() 抛异常会被包装为“Failed to start service”。因此 APEX 服务的构造、注册和生命周期失败都发生在 seal 之前,可阻止整个 StartServices 阶段。
5. 服务封口
源码文件:frameworks/base/services/core/java/com/android/server/SystemServiceManager.java
public void sealStartedServices() {
mServiceClassnames = Collections.emptySet();
mServices = Collections.unmodifiableList(mServices);
}封口后,已启动服务列表变为不可修改列表,class name 集合变成空集合。这个设计不是删除服务,而是禁止后续 startService() 再把新服务加入启动集合;boot phase、用户回调和 dump 仍可遍历已有 mServices。源码注释把封口放在 APEX 之后,避免 APEX 更新引入的新依赖破坏平台服务稳定性。
6. 失败与生效时机
- debug crash property:在 debug 构建中于列表读取前主动抛异常;
- SDK 条件不满足:ApexManager 跳过条目,不进入 SystemServer 启动;
- duplicate service/module:清单形成阶段抛异常;
- classloader/class not found:
startService阶段失败; onStart()异常:SystemServiceManager 包装后抛出,StartServices 中止;- seal 后尝试新服务:违反启动编排不变量,应视为调用方错误。
7. 导航与后续
# 输入 SystemServer APEX 启动方法,输出清单消费、jar 分支和封口。
rg -n "startApexServices|getApexSystemServices|startServiceFromJar|sealStartedServices|debug.crash_system" \
frameworks/base/services/java/com/android/server/SystemServer.java
# 输入 ApexManager,输出 active、SDK 过滤、重复检查和排序。
rg -n "getApexSystemServices|minSdkVersion|maxSdkVersion|Duplicate apex-system-service|Collections.sort" \
frameworks/base/services/core/java/com/android/server/pm/ApexManager.java
# 输入生命周期管理器,输出 classloader、去重、onStart 和封口实现。
rg -n "startServiceFromJar|loadClassFromLoader|mServiceClassnames|onStart|sealStartedServices" \
frameworks/base/services/core/java/com/android/server/SystemServiceManager.java下一篇将进入 SystemServer 的 boot phase 顺序,解释 startBootPhase() 如何遍历已封口服务并触发 onBootPhase();不会重复 APEX 清单和 classloader 分支。
