Android Service 源码分析篇

在代码中用 startService()bindService() 时,系统内部究竟发生了什么魔法。核心在于理解 Binder IPC 机制ActivityManagerService (AMS) 的角色。

一、核心原理:Binder IPC 与 ActivityManagerService (AMS)

  1. Binder IPC (Inter-Process Communication)

    • 问题: App 进程是沙盒隔离的。你的 App (客户端进程) 如何与系统服务 (如 AMS,运行在 system_server 进程) 或其他 App 的服务 (另一个进程) 通信?

    • 答案: Binder!它是 Android 最核心的跨进程通信机制

    • 核心思想 (简化模型):

      • 每个进程有一块共享内核内存空间
      • 通信双方通过 Binder 驱动 (内核模块) 在这块共享内存上读写数据。
      • 代理模式: 客户端拿到一个对服务端对象的 Proxy (代理) 。客户端调用 Proxy 的方法 -> Proxy 将方法名、参数打包 (序列化) 成 Parcel -> 通过 Binder 驱动发送给服务端进程 -> 服务端收到后解包,调用真实对象的方法 -> 将结果打包回传 -> 客户端 Proxy 接收结果并返回。
      • 对客户端来说,调用 Proxy 就像在调用本地对象一样(透明)。
    • 在 Service 中的体现:

      • 当你在 App 内绑定服务 (同进程),Binder 对象是直接传递的(效率高)。
      • 当你绑定跨进程服务(包括系统服务 AMS),你拿到的是一个 Binder Proxy 对象。你调用它的方法,实际是通过 Binder 驱动请求远程进程的 Service 执行操作。
      • IBinder 接口: 是 Binder 对象的核心接口。Binder 类实现了它(用于本地对象),BinderProxy (内部类) 也实现了它(用于远程代理)。
  2. ActivityManagerService (AMS) - 系统服务的大管家

    • 角色: Android 系统最核心的服务之一 ,运行在 system_server 进程。它管理四大组件(Activity、Service、BroadcastReceiver、ContentProvider)的整个生命周期

    • 对 Service 的职责:

      • 接收 App 进程发来的 startService, bindService, stopService, unbindService 等请求。
      • 维护所有运行中 Service 的记录。
      • 根据系统状态(内存、电量、用户交互)决定 Service 的启动、停止、绑定、解绑。
      • 处理 Service 与客户端的绑定关系。
      • 强制执行后台限制策略。
    • 你的 App 与 AMS 的通信: 通过 Binder IPC。你的 App 持有 AMS 的一个 Binder Proxy (IActivityManager)。

二、源码调用链路分析 (以 startService() 为例)

让我们追踪一次 startService() 的旅程。假设在 MyActivity 中调用 startService(new Intent(this, MyService.class))

  1. ContextWrapper.startService(Intent)

    (在你的 MyActivity 中调用)

    typescript 复制代码
    // ContextWrapper.java
    @Override
    public ComponentName startService(Intent service) {
        return mBase.startService(service); // mBase 是 ContextImpl 实例
    }
  2. ContextImpl.startService(Intent)

    (ContextImplContext 接口的真正实现者)

    scss 复制代码
    // ContextImpl.java
    @Override
    public ComponentName startService(Intent service) {
        ... // 一些权限、用户ID检查
        String resolvedType = service.resolveTypeIfNeeded(getContentResolver());
        try {
            // 关键!调用 ActivityManagerService (AMS) 的方法
            ComponentName cn = ActivityManager.getService().startService(
                mMainThread.getApplicationThread(), // 传入 ApplicationThread (Binder对象,代表App进程)
                service, resolvedType, getOpPackageName(), getAttributionTag(), getUser().getIdentifier());
            ... // 处理返回值
            return cn;
        } catch (RemoteException e) { ... }
    }
    • ActivityManager.getService():获取到 AMS 的 Binder Proxy (IActivityManager)。
    • mMainThread.getApplicationThread():获取代表当前 App 进程的 ApplicationThread 对象(它是一个 Binder 对象,实现了 IApplicationThread 接口)。这是 App 进程与 AMS 通信的另一条关键通道(回调通道)。
  3. 跨进程调用到 ActivityManagerService.startService()

    • 请求通过 Binder 驱动,从你的 App 进程传递到 system_server 进程。
    • AMS 收到请求:IActivityManager.startService(IApplicationThread caller, Intent service, ...)
    scss 复制代码
    // ActivityManagerService.java
    @Override
    public ComponentName startService(IApplicationThread caller, Intent service, ...) {
        ... // 大量安全检查 (权限、Intent 匹配、目标 Service 是否存在等)
        // 解析 Intent,找到目标 Service 的信息 (ResolveInfo)
        // 获取调用者进程记录 (ProcessRecord)
        // 获取或创建目标 Service 的记录 (ServiceRecord)
        synchronized(this) {
            // 核心方法:启动服务
            return startServiceLocked(caller, service, ...);
        }
    }
    
    ComponentName startServiceLocked(IApplicationThread caller, ...) {
        ... // 更多检查 (后台启动限制、前台权限等)
        // 将启动请求封装成 ServiceRecord.StartItem 并加入队列
        // 关键:调用 bringUpServiceLocked()
        return startServiceInnerLocked(...);
    }
    
    ComponentName startServiceInnerLocked(...) {
        ... // 处理 pending 状态等
        // 最终调用 bringUpServiceLocked()
        String error = bringUpServiceLocked(s, ...);
        ...
    }
    
    private String bringUpServiceLocked(ServiceRecord r, ...) {
        ... // 检查 Service 所在进程是否已启动
        if (app != null && app.thread != null) { // 进程已存在
            try {
                // 关键!通过 ApplicationThread (Binder) 回调到 App 进程,让 App 进程创建并启动 Service
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (RemoteException e) { ... }
        } else { // 进程不存在
            // 先启动 Service 所属的 App 进程 (另一个复杂过程)
            startProcessLocked(...);
        }
        ...
    }
    
    private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
        ... // 设置各种状态
        // 调用 App 进程 ApplicationThread 的 scheduleCreateService() 创建 Service
        app.thread.scheduleCreateService(r, ...);
        // 调用 App 进程 ApplicationThread 的 scheduleServiceArgs() 触发 onStartCommand
        requestServiceBindingsLocked(r, execInFg); // 如果有 pending 的绑定也一并处理
        sendServiceArgsLocked(r, execInFg, true); // 触发 onStartCommand
    }
  4. 回调到 App 进程 (ApplicationThread.scheduleCreateService())

    • 请求再次通过 Binder 驱动,从 system_server 进程回到你的 App 进程。
    • 你的 App 进程的 ActivityThread 内部的 ApplicationThread 对象收到请求:
    arduino 复制代码
    // ActivityThread.java (内部类 ApplicationThread)
    public final void scheduleCreateService(IBinder token, ...) {
        ... // 封装消息
        sendMessage(H.CREATE_SERVICE, s);
    }
    • ActivityThreadH (一个 Handler) 处理消息:
    scala 复制代码
    // ActivityThread.java
    private class H extends Handler {
        ...
        case CREATE_SERVICE:
            handleCreateService((CreateServiceData) msg.obj); // 处理创建服务
            break;
        ...
    }
    
    private void handleCreateService(CreateServiceData data) {
        // 1. 获取类加载器
        LoadedApk packageInfo = getPackageInfoNoCheck(...);
        // 2. 通过反射创建 Service 实例 !!
        Service service = packageInfo.getAppFactory().instantiateService(cl, data.info.name, data.intent);
        // 3. 创建 Context 上下文
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        // 4. 将 Context 附加到 Service (service.attach(context, ...))
        // 5. 调用 Service.onCreate() !!!
        service.onCreate();
        // 6. 将创建好的 Service 记录到 ActivityThread 的 mServices (一个 Map<IBinder, Service>) 中
    }
  5. 回调到 App 进程 (ApplicationThread.scheduleServiceArgs())

    • 紧接着(或在 realStartServiceLocked 中稍后),AMS 会调用 scheduleServiceArgs 触发 onStartCommand
    java 复制代码
    // ActivityThread.java (ApplicationThread)
    public final void scheduleServiceArgs(IBinder token, ...) {
        ... // 封装数据
        sendMessage(H.SERVICE_ARGS, s);
    }
    
    // ActivityThread.H
    case SERVICE_ARGS:
        handleServiceArgs((ServiceArgsData) msg.obj);
        break;
    
    private void handleServiceArgs(ServiceArgsData data) {
        // 从 mServices Map 中根据 token 找到之前创建的 Service 对象
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                ... // 处理参数
                // 调用 Service.onStartCommand() !!!
                int res = s.onStartCommand(data.args, data.flags, data.startId);
                // 通知 AMS 服务启动完成 (通过 AMS 的 serviceDoneExecuting)
                ActivityManager.getService().serviceDoneExecuting(...);
            } catch (Exception e) { ... }
        }
    }

总结 startService() 链路:
MyActivity.startService() -> ContextImpl.startService() -> (Binder IPC) -> AMS.startService() -> AMS.startServiceLocked()/bringUpServiceLocked()/realStartServiceLocked() -> (Binder IPC) -> ApplicationThread.scheduleCreateService() -> ActivityThread.handleCreateService() (反射创建 Service, 调用 onCreate()) -> ApplicationThread.scheduleServiceArgs() -> ActivityThread.handleServiceArgs() (调用 onStartCommand())。

三、源码调用链路分析 (bindService() 核心部分)

bindService() 的流程比 startService() 更复杂,因为它涉及到建立双向通信通道 (Binder)。核心在于 onBind()ServiceConnection

  1. ContextImpl.bindService() -> AMS.bindService()

    (类似 startService,App 进程请求 AMS)

  2. AMS 处理绑定请求 (bindServiceLocked)

    • 检查权限、目标服务、调用者进程等。
    • 如果服务未运行,先启动它(类似 startService 流程)。
    • 创建 ConnectionRecord 记录这次绑定。
    • 调用 requestServiceBindingLocked()
  3. AMS 请求服务端进程进行绑定 (realStartServiceLocked 或后续流程)

    arduino 复制代码
    // AMS
    private final boolean requestServiceBindingLocked(ServiceRecord r, ...) {
        ...
        // 通过 ApplicationThread 回调到服务端 App 进程
        r.app.thread.scheduleBindService(r, ...);
        ...
    }
  4. 服务端进程处理绑定请求 (ApplicationThread.scheduleBindService())

    java 复制代码
    // ActivityThread.ApplicationThread
    public final void scheduleBindService(IBinder token, ...) {
        sendMessage(H.BIND_SERVICE, s);
    }
    
    // ActivityThread.H
    case BIND_SERVICE:
        handleBindService((BindServiceData) msg.obj);
        break;
    
    private void handleBindService(BindServiceData data) {
        // 从 mServices Map 中找到目标 Service
        Service s = mServices.get(data.token);
        if (s != null) {
            try {
                // 调用 Service.onBind(Intent) !!!
                IBinder binder = s.onBind(data.intent);
                // 关键!将 Service 返回的 IBinder 对象 (可能是 Binder 本地对象或 Stub) 告诉 AMS
                ActivityManager.getService().publishService(data.token, data.intent, binder);
            } catch (Exception e) { ... }
        }
    }
  5. AMS 处理发布的 Binder (publishService())

    • AMS 收到服务端进程发来的 IBinder 对象。
    • 根据 ConnectionRecord 找到所有等待绑定的客户端。
    • 对于每个客户端,通过客户端的 IServiceConnection 接口(也是一个 Binder 对象,由客户端在 bindService() 时提供) ,调用 connected(ComponentName name, IBinder service) 方法。这里的 service 参数就是服务端 onBind() 返回的 IBinder
  6. 客户端进程收到连接 (IServiceConnection.connected())

    • 这个 IServiceConnection 的实现通常在 LoadedApk 内部 (ServiceDispatcher.InnerConnection),它会将调用转发给开发者注册的 ServiceConnection 对象:
    java 复制代码
    // LoadedApk.java (内部类 ServiceDispatcher.InnerConnection)
    public void connected(ComponentName name, IBinder service) throws RemoteException {
        // 转发给外部的 ServiceDispatcher
        sd.connected(name, service);
    }
    
    // ServiceDispatcher
    public void connected(ComponentName name, IBinder service) {
        // 回调给开发者写的 mConnection.onServiceConnected(name, service) !!!
        mActivityThread.post(new RunConnection(name, service, 0));
    }
    • 这样,在开发者的 ServiceConnection.onServiceConnected() 中,就拿到了服务端 onBind() 返回的 IBinder 对象。开发者可以将其转换成需要的接口类型(如自定义的 Binder 子类、MessengerAIDL 接口),开始与服务端通信。

总结 bindService() 核心链路:

客户端 bindService() -> AMS.bindService() -> (服务端进程可能启动) -> AMS.requestServiceBindingLocked() -> (Binder IPC) -> ApplicationThread.scheduleBindService() -> ActivityThread.handleBindService() (调用 Service.onBind()) -> (Binder IPC) AMS.publishService() -> (Binder IPC) 调用客户端的 IServiceConnection.connected() -> 客户端内部调用 ServiceConnection.onServiceConnected()

四、关键源码类总结

  1. Context / ContextImpl: App 组件访问系统服务的入口。startService(), bindService() 的起点。
  2. ActivityManagerService (AMS): 系统核心服务,管理 Service 生命周期、绑定关系的中央枢纽。运行在 system_server 进程。
  3. IActivityManager: AMS 的 Binder AIDL 接口定义。App 进程持有其 Proxy 与 AMS 通信。
  4. ActivityThread: App 进程的主线程类。负责调度四大组件的创建、生命周期回调。
  5. ApplicationThread: ActivityThread 的内部类,实现了 IApplicationThread AIDL 接口。它是 AMS 与 App 进程通信的回调通道 。AMS 通过调用它的方法 (如 scheduleCreateService, scheduleBindService) 来通知 App 进程执行组件操作。
  6. Service: 开发者继承的基类。onCreate(), onStartCommand(), onBind(), onUnbind(), onDestroy() 是其核心生命周期方法。
  7. IBinder: Binder 对象的根接口。Binder (本地对象), BinderProxy (远程代理), IInterface (AIDL 接口基类) 都与之相关。是跨进程通信的基石。
  8. ServiceRecord (AMS 内部): AMS 中代表一个运行中 Service 的数据结构。包含 Service 的所有关键信息(Intent、进程、绑定者列表、状态等)。
  9. ServiceConnection (客户端): 开发者实现的接口,用于接收绑定成功/失败的回调 (onServiceConnected, onServiceDisconnected)。其内部包装了 IServiceConnection Binder 对象用于 AMS 回调。
  10. IServiceConnection: ServiceConnection 内部通信通道的 AIDL 接口定义。AMS 通过它回调客户端。

五、总结

  • Service 的启动和绑定是 App 进程与系统服务 AMS (system_server 进程) 以及目标服务进程之间通过 Binder IPC 协作完成的。

  • AMS 是 Service 管理的中央控制器,负责生命周期调度、权限检查、后台策略执行。

  • ApplicationThread 是 AMS 控制 App 进程的"遥控器" 。AMS 通过调用其方法 (如 scheduleCreateService, scheduleBindService) 让 App 进程在正确时机执行 Service 的生命周期方法。

  • Binder IPC 是贯穿始终的通信基础,用于:

    • App -> AMS (IActivityManager)
    • AMS -> App (IApplicationThread)
    • 服务端 Service -> 客户端 (onBind() 返回的 IBinder 及其代理)
    • AMS -> 客户端 (IServiceConnection 通知绑定结果)
  • 绑定服务的核心在于服务端 onBind() 返回 IBinder,AMS 将其传递给客户端,最终回调到客户端的 ServiceConnection.onServiceConnected()

  • 理解 ServiceRecord, ConnectionRecord 等 AMS 内部数据结构有助于理解状态管理。

相关推荐
Mintopia27 分钟前
像素的进化史诗:计算机图形学与屏幕的千年之恋
前端·javascript·计算机图形学
Mintopia29 分钟前
Three.js 中三角形到四边形的顶点变换:一场几何的华丽变身
前端·javascript·three.js
归于尽44 分钟前
async/await 从入门到精通,解锁异步编程的优雅密码
前端·javascript
陈随易1 小时前
Kimi k2不行?一个小技巧,大幅提高一次成型的概率
前端·后端·程序员
猩猩程序员1 小时前
Rust 动态类型与类型反射详解
前端
杨进军1 小时前
React 实现节点删除
前端·react.js·前端框架
yanlele1 小时前
【实践篇】【01】我用做了一个插件, 点击复制, 获取当前文章为 Markdown 文档
前端·javascript·浏览器
爱编程的喵1 小时前
React useContext 深度解析:告别组件间通信的噩梦
前端·react.js
望获linux2 小时前
【实时Linux实战系列】多核同步与锁相(Clock Sync)技术
linux·前端·javascript·chrome·操作系统·嵌入式软件·软件