bindService是如何完成binder传递的?

让我为您深入剖析bindService的完整流程,特别是其核心------Binder对象的传递机制。这个过程堪称Android系统架构中跨进程通信(IPC) 的典范之作。

我们将遵循一个清晰的脉络进行分析:客户端发起请求 -> 系统服务处理 -> 目标服务响应 -> Binder对象返回 -> 客户端接收


核心脉络总览

bindService的本质是客户端(如Activity)向系统请求一个来自目标Service的Binder代理对象。整个流程涉及三次跨进程通信(IPC) ,最终将一个代表Service的Binder代理对象传递回客户端。

  1. IPC 1 : 客户端进程 -> system_server进程(AMS)。客户端向ActivityManagerService发起bindService请求。
  2. IPC 2 : system_server进程(AMS)-> 目标Service进程。如果Service未启动,AMS会先启动它,然后要求它返回一个Binder对象。
  3. IPC 3 : 目标Service进程 -> system_server进程(AMS)-> 客户端进程。Service将Binder对象通过AMS中转,最终传递回客户端的ServiceConnection中。

下面的序列图清晰地描绘了这一复杂过程的核心交互:


源码深度剖析

我们将沿着上图所示的流程,深入关键源码。

阶段一:客户端发起绑定请求 (IPC 1)

调用起点通常是Context.bindService(Intent, ServiceConnection, int)。具体的实现在ContextImpl中。

文件:frameworks/base/core/java/android/app/ContextImpl.java

java 复制代码
@Override
public boolean bindService(Intent service, ServiceConnection conn, int flags) {
    // ... 参数检查 ...
    return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, getUser());
}

private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, String instanceName,
        Handler handler, Executor executor, UserHandle user) {
    // 1. 将客户端的ServiceConnection包装成一个可跨进程传递的接口
    IServiceConnection sd;
    if (executor != null) {
        sd = new ServiceConnectionWrapper(conn, executor);
    } else {
        // 关键点:创建一个LoadedApk.ServiceDispatcher.InnerConnection对象
        // 它继承了IServiceConnection.Stub,是一个Binder对象,用于接收回调
        sd = mMainThread.getHandler().getLooper();
        if (sd == null) {
            throw new IllegalStateException(...);
        }
        // getServiceDispatcher() 会创建一个ServiceDispatcher,
        // 其内部类InnerConnection是IServiceConnection.Stub的实现。
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    }

    // 2. 解析Intent,为启动服务做准备
    validateServiceIntent(service);
    ResolveInfo rInfo = mPackageInfo.getPackageManager().resolveService(...);

    // 3. 调用ActivityManagerService的bindService方法
    try {
        // 获取AMS的Binder代理对象
        IBinder token = getActivityToken();
        if (token == null && ...) {
            token = mMainThread.getApplicationThread();
        }
        // 发起远程调用!这是第一次IPC。
        int res = ActivityManager.getService().bindIsolatedService(
            mMainThread.getApplicationThread(), // IApplicationThread,代表客户端进程
            getActivityToken(),                  // IBinder
            service,                            // Intent
            service.resolveTypeIfNeeded(getContentResolver()), // String
            sd,                                 // IServiceConnection,回调接口
            flags,                              // int
            instanceName,                       // String
            getOpPackageName(),                 // String
            user.getIdentifier());              // int
        // ... 处理返回值 ...
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
}

关键点 1: IServiceConnection sd

这是一个Binder接口,其具体实现是LoadedApk.ServiceDispatcher.InnerConnection。它被传递给AMS,这样AMS就拥有了一个可以回调到客户端进程的"遥控器"。当AMS拿到Service的Binder后,就会通过这个"遥控器"通知客户端。

关键点 2: ActivityManager.getService()

这是获取AMS(运行在system_server进程)的Binder代理对象。bindIsolatedService调用是一次从客户端到system_server进程的IPC。


阶段二:AMS处理并转发请求 (IPC 2)

请求现在到了system_server进程的AMS中。

文件:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

java 复制代码
public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service, ...) {
    // ... 权限检查等 ...
    synchronized(this) {
        // 调用ActiveServices的方法
        return mServices.bindServiceLocked(caller, token, service, ...);
    }
}

后续逻辑在ActiveServices中,我们关注requestServiceBindingLocked方法。

文件:frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

java 复制代码
private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord ibr, ...) {
    // ... 各种状态检查 ...
    if ((!r.getAppInfo().isSystemApp() || isSideEffect) && !r.isBoundToCaller(...)) {
        // 计算时间等...
    }

    // 关键:向目标Service进程发送请求,要求其返回Binder对象
    if (r.connections.contains(ibr) && !ibr.requested) {
        try {
            // r.app: ProcessRecord,代表目标Service所在进程
            // r.app.getThread(): IApplicationThread,代表目标Service进程的Binder代理对象
            // 这里调用scheduleBindService,是第二次IPC。
            r.app.getThread().scheduleBindService(r, ibr.intent.getIntent(), rebind, r.app.getReportedProcState());
            ibr.requested = true;
        } catch (RemoteException e) {
            // ...
        }
    }
    return true;
}

关键点: r.app.getThread().scheduleBindService(...)
r.app.getThread()是目标Service所在进程的IApplicationThread代理对象。这行代码发起了一次从system_server进程到目标Service进程 的IPC,通知它执行bindService操作。


阶段三:目标Service创建并返回Binder (IPC 3的起点)

请求现在到了目标Service进程。IApplicationThread的实现是ActivityThread中的内部类ApplicationThread

文件:frameworks/base/core/java/android/app/ActivityThread.java

java 复制代码
// class ActivityThread
private class ApplicationThread extends IApplicationThread.Stub {
    public final void scheduleBindService(IBinder token, Intent intent, boolean rebind, int processState) {
        // 发送一个BIND_SERVICE消息到主线程Handler
        sendMessage(H.BIND_SERVICE, s);
    }
}

public void handleMessage(Message msg) {
    switch (msg.what) {
        case BIND_SERVICE:
            handleBindService((BindServiceData) msg.obj);
            break;
        // ...
    }
}

private void handleBindService(BindServiceData data) {
    // 1. 根据token获取之前已创建的Service
    Service s = mServices.get(data.token);
    if (s != null) {
        try {
            // 2. 调用Service的onBind方法!这是开发者实现返回IBinder对象的地方。
            data.intent.setExtrasClassLoader(s.getClassLoader());
            data.intent.prepareToEnterProcess();
            IBinder binder = s.onBind(data.intent);
            // 3. 关键:将onBind返回的IBinder对象通知给AMS
            ActivityManager.getService().publishService(
                    data.token,    // ServiceRecord的token
                    data.intent,   // Intent
                    binder);       // 真正的Binder对象!!!
            // ...
        } catch (RemoteException e) {
            // ...
        }
    }
}

关键点 1: IBinder binder = s.onBind(data.intent);

这里调用了开发者重写的onBind方法,返回了我们自定义的Binder对象。

关键点 2: ActivityManager.getService().publishService(...)

这行代码极其重要!它再次获取AMS的代理,并调用其publishService方法,将刚从onBind获取的原始Binder对象 作为参数传递过去。这是第三次IPC的起点,从目标Service进程 回到**system_server进程(AMS)** 。


阶段四:AMS将Binder传递回客户端 (IPC 3的终点)

现在我们回到AMS的publishService方法。

文件:frameworks/base/services/core/java/com/android/server/am/ActiveServices.java

java 复制代码
public void publishService(IBinder token, Intent intent, IBinder service) {
    synchronized(this) {
        // 1. 根据token找到对应的ServiceRecord和IntentBindRecord
        ServiceRecord r = (ServiceRecord) token;
        IntentBindRecord b = r.bindings.get(intent.getFilter());
        if (b != null && !b.received) {
            b.binder = service; // 保存Service返回的Binder对象
            b.requested = true;
            b.received = true;
            // 2. 遍历所有连接到这个Service的客户端
            for (int conni = b.connections.size() - 1; conni >= 0; conni--) {
                ConnectionRecord c = b.connections.get(conni);
                // 3. 关键:调用客户端的connected方法
                try {
                    // c.conn: 就是第一阶段传来的IServiceConnection代理对象
                    // 这里调用connected,发起第三次IPC的后续部分:system_server -> 客户端进程
                    c.conn.connected(r.name, service, false);
                } catch (RemoteException e) {
                    // ...
                }
            }
        }
        // ...
    }
}

关键点: c.conn.connected(r.name, service, false);
c.conn就是第一阶段由客户端创建并传递给AMS的IServiceConnection代理对象。此时,AMS通过调用它的connected方法,将从Service那里拿到的原始Binder对象作为参数传递回去。

这发起了第三次IPC的后半部分:从system_server进程到最初的客户端进程


阶段五:客户端在回调中接收Binder对象

现在我们回到客户端进程。还记得第一阶段创建的IServiceConnection实现吗?它叫LoadedApk.ServiceDispatcher.InnerConnection

文件:frameworks/base/core/java/android/app/LoadedApk.java

java 复制代码
private static final class ServiceDispatcher {
    // 这个内部类继承了IServiceConnection.Stub
    private final class InnerConnection extends IServiceConnection.Stub {
        @Override
        public void connected(ComponentName name, IBinder service, boolean dead) {
            // 将调用转发给外部的ServiceDispatcher
            mDispatcher.connected(name, service, dead);
        }
    }

    // ServiceDispatcher的方法
    public void connected(ComponentName name, IBinder service, boolean dead) {
        // 1. 通过Handler抛到主线程执行
        if (mActivityThread != null) {
            mActivityThread.post(new RunConnection(name, service, dead, 0));
        } else {
            // ...
        }
    }

    private final class RunConnection implements Runnable {
        public void run() {
            // 2. 最终在这里调用到开发者传入的ServiceConnection对象的onServiceConnected方法!
            if (mCommand == 0) {
                doConnected(mName, mService, mDead);
            } else if (mCommand == 1) {
                doDeath(mName, mService);
            }
        }
    }

    public void doConnected(ComponentName name, IBinder service, boolean dead) {
        // ... 旧的连接处理 ...
        if (service != null) {
            // 3. 最终回调!将AMS传过来的原始Binder对象交给开发者
            mConnection.onServiceConnected(name, service);
        }
    }
}

关键点: mConnection.onServiceConnected(name, service);

这个mConnection就是开发者最初在bindService时传入的ServiceConnection对象。参数service就是来自目标Service的原始Binder对象 。对于客户端来说,如果Service在另一个进程,这个service实际上是一个Binder代理对象;如果在同一进程,则是直接的对象引用。

至此,整个Binder传递流程圆满结束。

总结与核心要点

  1. 三次IPC:流程清晰地分为三次跨进程调用,环环相扣。
  2. Binder对象传递 :Service的onBind返回的IBinder对象,通过AMS中转,最终原封不动地传递给了客户端的onServiceConnectedAMS并不关心这个Binder对象的具体内容,它只负责传递
  3. 回调桥梁 :客户端在第一步构造的IServiceConnectionInnerConnection)是整个回调机制的关键。它是一个Binder对象,让AMS拥有了"呼叫"客户端的能力。
  4. 代理与Stub :如果Service在远程,客户端在onServiceConnected中拿到的是Binder代理对象(Proxy),开发者需要将其转换为自定义的AIDL接口,后续的方法调用将直接与远程Service通信,不再经过AMS。如果在同一进程,则是直接的对象调用。
  5. 线程切换 :所有从Binder线程(IPC调用到达的线程)到主线程的切换,都是由ActivityThreadHandlerServiceDispatcher完成的,确保了开发者的回调发生在主线程。

通过这次源码之旅,我们可以看到Android系统如何通过Binder这一核心机制,精巧地实现了组件间的解耦和通信。希望这份分析能让你对bindService的理解提升到一个新的高度。

相关推荐
一条上岸小咸鱼13 分钟前
Kotlin 类型检查与转换
android·kotlin
闲暇部落1 小时前
android studio配置 build
android·android studio·build
_祝你今天愉快2 小时前
Android FrameWork - Zygote 启动流程分析
android
龙之叶3 小时前
Android系统模块编译调试与Ninja使用指南
android
源码哥_博纳软云4 小时前
JAVA国际版多商户运营版商城系统源码多商户社交电商系统源码支持Android+IOS+H5
android·java·ios·微信·微信小程序·小程序·uni-app
洞见不一样的自己4 小时前
Android 小知识点
android
tangweiguo030519876 小时前
Flutter性能优化完全指南:构建流畅应用的实用策略
android·flutter
AI大法师13 小时前
Android应用性能监测与调优:掌握Profiler和LeakCanary等关键工具
android
2501_9151063217 小时前
iOS混淆工具实战 金融支付类 App 的安全防护与合规落地
android·ios·小程序·https·uni-app·iphone·webview