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 内部数据结构有助于理解状态管理。

相关推荐
GalaxyPokemon2 分钟前
RPC - Response模块
java·前端·javascript
网小鱼的学习笔记17 分钟前
CSS语法中的选择器与属性详解
前端·css
gnip24 分钟前
大屏适配-vm和vh
前端
晴殇i1 小时前
3 分钟掌握图片懒加载核心技术:面试攻略
前端·面试·trae
Running_C1 小时前
一文读懂vite和webpack,秒拿offer
前端
咸鱼青菜好好味1 小时前
node的项目实战相关
前端
hqsgdmn1 小时前
自动导入插件unplugin-auto-import/unplugin-vue-components
前端
不知火_caleb1 小时前
前端应用更新提示的优雅实现:如何让用户及时刷新页面?
前端
前端小巷子1 小时前
跨标签页通信(四):SharedWorker
前端·面试·浏览器
风铃喵游1 小时前
平地起高楼: 环境搭建
前端·架构