九、系统服务开发:SystemServer 启动流程、添加自定义系统服务

系统服务,说白了就是 Android 系统的“内脏”。没有它们,你的手机连亮屏都做不到。我刚开始接触 AOSP 时,总觉得 SystemServer 启动流程特别神秘——一个 Java 进程怎么就把整个 Android 世界给撑起来了?后来啃了几个月源码,才慢慢摸清门道。

今天咱们就把它拆开揉碎了讲。你不仅能看懂 SystemServer 怎么启动的,还能亲手往里面塞一个自定义服务。

9.1 SystemServer 启动流程:从 init 到服务管家

先看整体脉络。我画了一张图,帮你快速建立全局认知:

SystemServer 启动流程概览 init 进程 fork Zygote 进程 fork SystemServer 进程 main() 入口 run() 方法 启动各类系统服务 • 引导服务(Installer, DeviceIdentifiers) • 核心服务(ActivityManager, PackageManager) • 其他服务(Wifi, Bluetooth, Camera 等) Looper.loop()

嗯,这张图你得存着。每次看源码时对照着它,思路会清晰很多。

9.2 启动流程源码级拆解

咱们从 SystemServer.main() 开始看。这是整个服务的入口:

// frameworks/base/services/java/com/android/server/SystemServer.java
public static void main(String[] args) {
    new SystemServer().run();
}

代码就这么两行。但 run() 方法里,藏着整个 Android 系统的启动秘密。

9.2.1 run() 方法做了什么?

我把它拆成三个阶段:

  1. 准备阶段:设置系统属性、加载库、创建主线程 Looper
  2. 启动引导服务:Installer、DeviceIdentifiers 等
  3. 启动核心服务:ActivityManagerService、PackageManagerService 等

看一段关键代码:

private void run() {
    // 1. 准备阶段
    Looper.prepareMainLooper();
    System.loadLibrary("android_servers");
    
    // 2. 创建系统上下文
    createSystemContext();
    
    // 3. 启动引导服务
    startBootstrapServices();
    
    // 4. 启动核心服务
    startCoreServices();
    
    // 5. 启动其他服务
    startOtherServices();
    
    // 6. 进入消息循环
    Looper.loop();
}

关键点Looper.loop() 是最后一步。一旦调用,主线程就卡在这里了。所有后续工作都通过消息驱动。这也是为什么系统服务不会“退出”的原因。

9.3 添加自定义系统服务:手把手教程

好,理论讲完了。咱们来点实战。我带你写一个 DemoService,功能很简单——返回当前系统运行时间。

9.3.1 第一步:定义 AIDL 接口

frameworks/base/core/java/android/os/ 下创建 IDemoService.aidl

// frameworks/base/core/java/android/os/IDemoService.aidl
package android.os;

interface IDemoService {
    long getUptimeMillis();
}

我的习惯:AIDL 文件命名一定要加 "I" 前缀。这是 Android 源码的约定,别打破它。我曾经见过有人用 "DemoService.aidl",结果编译时各种报错,排查了半天。

9.3.2 第二步:实现服务端

frameworks/base/services/core/java/com/android/server/ 下创建 DemoService.java

// frameworks/base/services/core/java/com/android/server/DemoService.java
package com.android.server;

import android.content.Context;
import android.os.IDemoService;
import android.util.Slog;

public class DemoService extends IDemoService.Stub {
    private static final String TAG = "DemoService";
    private final Context mContext;
    
    public DemoService(Context context) {
        mContext = context;
        Slog.i(TAG, "DemoService created");
    }
    
    @Override
    public long getUptimeMillis() {
        return SystemClock.uptimeMillis();
    }
}

9.3.3 第三步:注册到 SystemServer

打开 SystemServer.java,在 startOtherServices() 方法中添加:

private void startOtherServices() {
    // ... 原有代码 ...
    
    try {
        Slog.i(TAG, "Starting DemoService");
        DemoService demo = new DemoService(mSystemContext);
        ServiceManager.addService("demo", demo);
    } catch (Throwable e) {
        Slog.e(TAG, "Failed to start DemoService", e);
    }
    
    // ... 原有代码 ...
}

注意:添加位置有讲究。我建议放在 startOtherServices() 的靠前位置,但要在 WindowManagerService 之后。因为你的服务可能依赖窗口管理。嗯,这个坑我踩过——服务启动太早,拿不到 Display 信息。

9.3.4 第四步:客户端调用

在 App 中调用你的服务:

IDemoService demoService = IDemoService.Stub.asInterface(
    ServiceManager.getService("demo"));
if (demoService != null) {
    long uptime = demoService.getUptimeMillis();
    Log.d(TAG, "System uptime: " + uptime);
}

9.4 避坑指南:我踩过的三个坑

现象 原因 解决方案
服务启动时序 服务注册成功但调用时崩溃 依赖的服务还没启动 使用 waitForService() 或调整启动顺序
权限问题 客户端调用时抛 SecurityException 未声明系统权限 在 AndroidManifest 中添加 android.permission.CONFIGURE_INPUT_DISPLAY
编译失败 找不到 AIDL 生成的 Stub 类 AIDL 文件未加入编译 检查 Android.bp 中是否包含 aidl 文件路径

9.5 服务注册的两种方式

我个人更推荐第二种,但第一种更常见:

  1. 直接注册ServiceManager.addService("demo", service) —— 简单粗暴,适合快速验证
  2. 通过 SystemService 基类:继承 SystemService,实现生命周期回调 —— 更规范,适合生产环境

第二种方式的示例:

public class DemoService extends SystemService {
    private final DemoServiceImpl mImpl;
    
    public DemoService(Context context) {
        super(context);
        mImpl = new DemoServiceImpl(context);
    }
    
    @Override
    public void onStart() {
        publishBinderService("demo", mImpl);
    }
    
    @Override
    public void onBootPhase(int phase) {
        if (phase == PHASE_SYSTEM_SERVICES_READY) {
            // 系统服务就绪,可以初始化了
        }
    }
}

为什么推荐第二种? 因为 SystemService 提供了 onBootPhase() 回调。你可以精确控制服务在不同启动阶段的行为。比如,有些初始化必须在 PHASE_ACTIVITY_MANAGER_READY 之后才能做。

9.6 验证你的服务

编译刷机后,用 adb 验证:

# 查看服务是否注册成功
adb shell service list | grep demo

# 直接调用服务方法
adb shell service call demo 1

如果看到输出 Result: Parcel(00000000 00000000 ...),说明服务跑起来了。那个 1 是方法编号——AIDL 中第一个方法对应编号 1。

嗯,到这里,你已经掌握了 SystemServer 的启动流程,也亲手添加了一个自定义系统服务。剩下的就是多练、多踩坑。我曾经为了一个服务注册失败的问题折腾了两天,最后发现是 AIDL 文件路径写错了。这种经历,你迟早也会有的。