今天看啥  ›  专栏  ›  jkwen

从 Binder 通信机制角度谈 bindService 的启动流程

jkwen  · 简书  ·  · 2021-02-07 15:37

前面按照书本内容走了一遍 bindService 启动梳理, Android 进阶解密阅读笔记5 那时的重点在于流程是怎么走的,这篇我准备从参与 Binder 机制的过程重新梳理下,侧重点在于客户端(也就是调用 bindService 方法的一方)是如何与服务端(提供服务功能的一方)建立通信连接的。

//从 ContextImpl 的 bindService 方法开始
IServiceConnection sd;
if(mPackageInfo != null) {
    if(executor != null) {
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags);
    } else {
        //这里会走这句代码创建 sd
        sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
    }
}
//LoadedApk
private IServiceConnection getServiceDispatcherCommon(ServiceConnection c, Context context, Handler handler, Executor executor, int flags) {
    synchronized (mServices) {
        LoadedApk.ServiceDispatcher sd = null;
        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
        //通过带参构造方法创建 sd,其中下面 return 的 IServiceContention 就是内部类的对象实例
        //即 InnerConnection 的对象
        sd = new ServiceDispatcher(c, context, handler, flags);
        map.put(c, sd);
    }
   return sd.getIServiceConnection();
}

可见,当我们通过调用 bindService 方法进行 Service 绑定时,入参的 ServiceConnection 对象和 flags 标志被用来创建了 ServiceDispatcher 对象,Intent 对象被用在了创建 Service。

再按之前梳理的走下去,会触发 Service 的 onBind 方法。该方法要求返回一个 IBinder 类型的值,这个返回值其实就是服务方的 Binder 实体。也就是服务端中那个继承自 Binder 且实现服务功能接口的类的实体。

//AMS
//token 实际是 ServiceRecord 类型
//service 就是服务端提供的 Binder 实体
public void publishService(IBinder token, Intent intent, IBinder service) {
    mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
    if (b != null && !b.received) {
        b.binder = service;
        b.requested = true;
        b.received = true;
        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
        for (int conni = connections.size() - 1; conni >= 0; conni--) {
            ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
            for (int i=0; i<clist.size(); i++) {
                ConnectionRecord c = clist.get(i);
                try {
                    //c.conn 就是前面我们提到的 InnerConnection 对象
                    //service 就是服务端的 Binder 实体
                    c.conn.connected(r.name, service, false);
                }
            }
        }
    }
}
//InnerConnection
public void connected(ComponentName name, IBinder service, boolean dead) {
    //这里取到的就是一开始用 ServiceConnection 和 flags 创建的 ServiceDispatcher 对象
    LoadedApk.ServiceDispatcher sd = mDispatcher.get();
    if (sd != null) {
        sd.connected(name, service, dead);
    }
}
//ServiceDispatcher
public void connected(ComponentName name, IBinder service, boolean dead) {
    if (mActivityExecutor != null) {
        mActivityExecutor.execute(new RunConnection(name, service, 0, dead));
    } else if (mActivityThread != null) {
        //接下去会执行这句代码,
        mActivityThread.post(new RunConnection(name, service, 0, dead));
    } else {
        doConnected(name, service, dead);
    }
}
//RunConnection
public void run() {
    if (mCommand == 0) {
        doConnected(mName, mService, mDead);
    } else if(mCommand == 1) {
        
    }     
}
//ServiceDispatcher
public void doConnected(ComponentName name, IBinder service, boolean dead) {
    if (service != null) {
        //service 是服务端的 Binder 实体
        //mConnection 是一开始的入参 ServiceConnection 对象
        mConnection.onServiceConnected(name, service);
    } else {
        mConnection.onNullBinding(name);
    }  
}

所以,作为客户端是通过 ServiceConnection 的 onServiceConnected 方法与服务端建立了通信,通信的介质可以认为是 IBinder 对象。

那么客户端拿到这个 IBinder 对象后又该怎么用呢?肯定不能直接用,也没法强制类型转换,具体要怎么去用呢,可以看下这篇 Binder 机制入门




原文地址:访问原文地址
快照地址: 访问文章快照