写给Android开发者的Binder

       Binder是一个很大的话题,里面涉及到java、c/c++、linux等知识,并且核心是位于native层的c/c++编写的代码,想要弄清楚整个Binder机制的来龙去脉不看native层的代码是不可能的。而对于一个看不懂c/c++的Android开发者而言,要理清Binder的机制更是难上加难。幸好网上关于Binder的资料还是挺多的,这里推荐老罗的Android之旅的Binder系列、书籍【深入理解Android内核的设计思想】、Android Binder设计与实现 - 设计篇。Binder设计与实现全程没有一行代码但讲解非常通透,不过要清楚的知道Binder整个执行流程避免不了要看代码;老罗的Binder系列讲解和源码分析面面俱到,但是细节太多太详细,没有一定的c/c++功底很难啃的下去;相对而言,【深入理解Android内核的设计思想】的Binder章节更友好(至少对我),从设计者的角度出发去思考问题并辅于源码的分析,让人很容易进入感觉,有自己的节奏。

       本文将从Android开发者的角度出发,只为弄清楚从Client端发起请求到Server响应请求整个执行流程,不会对c/c++的细节作细究。c/c++代码实在看不懂的,多看几遍,混个熟脸,再看就会比较有感觉了。

       下面将会从以下四点展开分析

1.获取ServiceMananger远程接口的过程

2.调用ServiceMananger.addService过程

3.调用ServiceMananger.getService过程

4.Server的onTransact响应过程  

 读完本文,你应该会得到以下的收获:

.对Binder机制它的整体流程应该有了比较清晰的了解

.Binder对象可以跨进程传输到底是什么意思

.Parcel在其中扮演的角色

.最简单的APP进程也至少包含Binder_1、Binder_2线程,这两个线程是怎么来的

先来看一下Binder的通讯模型,对Binder机制的几个角色有个大概的了解。

Binder的通讯模型:Server、Client、ServiceManager、Binder驱动。

Server:提供服务的一方,这个是我们自己要实现的,但系统中也存在了一些已经实现了的Server,例如AMS、WMS等等。

Client:使用服务的一方

ServiceManager:服务的管理者,提供注册和查询等功能。Server启动后向ServiceManager注册,ServiceManager保存着【名称字符串,Server引用】的对应关系,Client通过该字符串查询得到Server的引用,从而使用Server的服务。注意,这里说的ServiceManager是用c实现的,和ServiceManager.java不是一个概念,ServiceManager.java只是一个封装类。

Binder驱动:通常Server和Client是位于不同的进程中,由于进程的隔离,Client和Server是无法直接访问到对方的虚拟内存地址的。什么意思呢?每个进程都有自己的一套虚拟地址空间,一个虚拟地址在进程A中映射到一块内存,而同一个虚拟地址在进程B中映射的是另外一个内存,同一个虚拟地址在不同进程中代表的是不同的内存,因而进程A和进程B是无法直接通信的。想要通信,得借助Binder驱动。虽然每个进程都有自己的一套虚拟地址空间,但有那么一段是大家共用的,这段地址映射的到是同一段内存,这段虚拟地址是留给内核使用的,而Binder驱动就是实现在内核中的。因此Binder驱动既可以访问到Client进程,也可以访问到Server进程,那么使用Binder当做Client和Server的传话筒就最合适不过了。

       本文不打算分析Binder驱动和ServiceMananger的源码,一来是篇幅收不住;二来是这两者对于Android开发者是不可见的。当然我们也不能打无准备的仗,下面总结一下Binder驱动和ServiceMananger在Binder机制中的职责所在。

.Client、Server、ServiceMananger之间的通信需要借助Binder驱动

.Server向ServiceMananger注册(addService),传递给Binder驱动的是Server的内存地址(当然也包括字符串name等),Binder驱动会为这个Server(Binder实体)生成一个句柄值,并维护这个句柄值与该Server之间的关系,并把这个句柄值传递给ServiceMananger,而ServiceMananger维护的是字符串name与这个句柄值之间的关系

.Client获取Server的远程接口(getService),传递字符串name给Binder驱动,Binder驱动传递name给ServiceMananger,ServiceMananger查询name对应的句柄值返回给Binder驱动,Binder驱动根据根据这个句柄找到对应的Server,然后重新生成一个句柄值返回个Client,当然Binder驱动也会维护这个新的句柄值与Server之间的关系,因此Client得到的其实只是一个32位的句柄值。

.Client使用Server的服务,传递句柄和方法编号给Binder驱动,由Binder驱动唤醒句柄对应的Server并传递方法编号给Server,Server执行相应的方法并返回结果。

.进程是通过ioctl(fd, cmd, arg)函数实现与Binder驱动的交互,其中cmd是命令,arg是数据。其中最常用的命令为BINDER_WRITE_READ,该命令向Binder写入或读取数据,参数arg为结构体binder_write_read。

       明白了ServiceMananger和Binder驱动的职责,我们就可以不用过多的关注Binder驱动和ServiceMananger的源码,我们重点放在Client端的请求发起的流程和Server端的响应流程就可以了。

       先来看一段service_manager的源码,了解一下作为一个Server(ServiceMananger也是一个Server)它应该是怎样子的。ServiceManager是独立运行在一个进程中的,Server要向ServiceManager注册,这其中也是进程间的通信,也是要用到Binder驱动的

service_manager.c

int main(int argc, char **argv)
{
    struct binder_state *bs;
    bs = binder_open(128*1024);
    ...
    binder_loop(bs, svcmgr_handler);
    return 0;
}

binder.c

void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...

    for (;;) {
        ...
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        ...
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
}

        ServiceManager启动后会执行main方法,在main方法中会执行binder_open打开binder驱动,然后调用binder_loop进入循环;在binder_loop中,有一个for的死循环,在循环中调用ioctl从binder驱动中获取消息,如果没有消息会进入睡眠;如果有请求消息到来,就会被Binder驱动唤醒,然后调用binder_parse进行处理。

         嗯,作为一个Server应该就是这样子的,但是我们在实现自己的Server的时候好像并不需要实现一个for循环然后从Binder驱动读取消息也能实现作为一个Server的功能被Client访问的?是的,因为一个进程中可能有很多这样的Server,如果每个Server都要自己实现这样一个功能那就太麻烦了,我们只需要在进程的层面实现这样的一个功能,由进程去跟Binder驱动打交道,然后分发给不同的Server去处理就好了,这个过程在第4点Server的onTransact响应过程中会有分析。

1.获取ServiceMananger远程接口的过程

       从结果上讲,获取ServiceMananger远程接口和获取Server远程接口(getService)是一样的,因为ServiceMananger也是一个Server。只不过要获取Server的远程接口,首先要获得ServiceMananger的远程接口。

       在java端是如何获取ServiceMananger远程接口的呢?没错,Server通过ServiceManager.addService(“name”,new Server())向ServiceManager注册自己之前,是通过getIServiceManager() 获得ServiceMananger远程接口的。

ServiceManager.addService
public static void addService(String name, IBinder service) {
    try {
        getIServiceManager().addService(name, service, false);
    } catch (RemoteException e) {
        Log.e(TAG, "error in addService", e);
    }
}
private static IServiceManager getIServiceManager() {
    if (sServiceManager != null) {
        return sServiceManager;
    }

    // Find the service manager
    sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
    return sServiceManager;
}
ServiceManagerNative.asInterface

static public IServiceManager asInterface(IBinder obj)
{
    if (obj == null) {
        return null;
    }
    IServiceManager in =
        (IServiceManager)obj.queryLocalInterface(descriptor);
    if (in != null) {
        return in;
    }
    
    return new ServiceManagerProxy(obj);
}

        我们知道,想要跟Server通信,就要首先获得这个Server的远程接口,其实这个远程接口是指什么呢?个人理解是指这个IBinder对象。而从前面分析知道Client进程从Binder驱动得到的是一个32位的句柄,那么这个IBinder对象应该是根据这个句柄创建出来的一个对象了。

        跟踪过startActivity过程或者熟悉AIDL的应该对ServiceManagerNative.asInterface这个格式的代码很熟悉了。简单说一下,首先得到一个Server的远程接口IBinder,然后通过asInterface得到一个XXXProxy对象,XXXProxy实现了和Server一样的接口,因此访问XXXProxy就好像访问Server一样。

        这里关键是要理解这个IBinder参数 obj。这里我们是通过BinderInternal.getContextObject()得到这个IBinder对象的,而通过ServiceManager.getService(“”)得到的也会是一个IBinder对象,这个IBinder对象其实就是代表了远端的Server(也就是远程接口),所有对XXXProxy的调用,最终都会通过这个IBinder对象的transact方法访问到远程的Server。

现在来分析BinderInternal.getContextObject()

BinderInternal:getContextObject

public static final native IBinder getContextObject();

getContextObject是一个JNI方法,实现在android_util_Binder.cpp中

static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
    return javaObjectForIBinder(env, b);
}

       这里分两步,第一步通过ProcessState.getContextObject获得一个c++层的IBinder对象,然后通过javaObjectForIBinder将这个IBinder对象转化成java层使用的IBinder对象。

ProcessState.getContextObject

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    ...
    handle_entry* e = lookupHandleLocked(handle);
    ...
            b = new BpBinder(handle); 
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            ...
            e->refs->decWeak(this);
        }
    }

    return result;
}

        可以看到,得到的c++层的IBinder对象的实际类型是BpBinder,注意了,这里handle传进来的值是0。前面说过,通过BinderInternal.getContextObject()和ServiceManager.getService(“”)得到的都是一个IBinder对象,代表着远程的Server,那么BinderInternal.getContextObject()得到的IBinder代表的是ServiceMananger,而ServiceManager.getService(“”)得到的IBinder代表的是其它的Server对象。而这两种方法得到的IBinder对象都是通过getStrongProxyForHandle构造出来的,getService的流程下面会分析,他们不同的地方只有这个handle的值。前面说了Client从Binder驱动得到的是一个句柄,这里的handle就是这个句柄,getStrongProxyForHandle就是根据句柄创建一个c++层的IBinder对象,最终会转换为java的IBinder对象返回给java层。而ServiceManager这个Server比较特殊,它并没有在ServiceManager中注册自己,它在各个Client进程中的句柄固定为0。

现在来看看是如何将一个c++的IBinder转化成java的IBinder的

android_util_binder.cpp:javaObjectForIBinder 

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    ...

    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        ...
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
        ...
        val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env), proxy_cleanup);
        ...
    }

    return object;
}

       这里就是通过NewObject生成一个BinderProxy对象的,这个gBinderProxyOffsets是什么东西呢?我们把它当成记录着BinderProxy类的信息的东西就好,例如gBinderProxyOffsets.mClass就表示BinderProxy的Class,gBinderProxyOffsets.mObject就表示BinderProxy的成员变量mObject。这样就清楚了,通过javaObjectForIBinder,会根据一个BpBinder的对象创建出一个java层的BinderProxy对象,而这个BpBinder对象的地址保存在BinderProxy的成员变量mObject中(通过SetLongField)。

        总结一下:Clinet在获取Server的远程接口的时候会得到一个句柄(从Binder驱动得到或者是0),然后再在Client的进程中根据这个句柄构造一个BpBinder对象,最后创建出一个相对应的BinderProxy对象返回给java层。而ServiceManager对应的句柄在各个Cilent中都统一为0,这个句柄是不需要额外通过进程间通信得到的。

2.调用ServiceMananger.addService过程

ServiceManagerProxy:addService(“name”,new Server())

class ServiceManagerProxy implements IServiceManager {

    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    ...
    public void addService(String name, IBinder service, boolean allowIsolated)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        data.writeStrongBinder(service);
        data.writeInt(allowIsolated ? 1 : 0);
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }

       获得ServerMananger的远程接口后就可以调用addService将Server纳入ServerMananger的管理,方便以后Client端以字符串的形式查询到Server,使用Server的服务。

       这里有两个知识点,1.Parcel的作用 2.mRemote.transact的过程

       Parcel可以理解为数据的载体,通过传输,Parcel携带着数据来到进程的边界,另外一个进程通过读这个Parcel的内容取出数据。我们所说的Binder对象可以跨进程传输,就是将Binder对象写入Parcel,然后另外一个进程从这个Parcel读取Binder(当然实际传输的只是这个Binder实体的地址)。Parcel就是通过writeStrongBinder方法将一个Binder对象写入的。

          先来看看Parcel的构造方法

public final class Parcel {
...
private long mNativePtr; // used by native code
...
private Parcel(long nativePtr) {
    if (DEBUG_RECYCLE) {
        mStack = new RuntimeException();
    }
    ...
    init(nativePtr);
}
...
private void init(long nativePtr) {
    if (nativePtr != 0) {
        mNativePtr = nativePtr;
        mOwnsNativeParcelObject = false;
    } else {
        mNativePtr = nativeCreate();
        mOwnsNativeParcelObject = true;
    }
}
...
}

android_os_Parcel.cpp:android_os_Parcel_create

static jlong android_os_Parcel_create(JNIEnv* env, jclass clazz)
{
    Parcel* parcel = new Parcel();
    return reinterpret_cast<jlong>(parcel);
}

          可以看到,Parcel对象在c++层有个Parcel对象对应着,c++层的Parcel的地址保存在java层Parcel对象的成员变量mNativePtr中

          java层Parcel的writeStrongBinder也是简单的调用了c++层Parcel的writeStrongBinder

android_os_Parcel
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

在调用c++层Parcel的writeStrongBinder前先将java层的IBinder对象通过ibinderForJavaObject转换为c++层的IBinder对象。

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    ...
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh != NULL ? jbh->get(env, obj) : NULL;
    }
    ...
    return NULL;
}

       因为后面还会用到这个gBinderOffsets,因此先来解释一下gBinderOffsets,gBinderOffsets和前面分析过的gBinderProxyOffsets作用是一样的,只不过gBinderProxyOffsets记录的是BinderProxy的信息,而gBinderOffsets记录的是Binder的信息

static struct bindernative_offsets_t
{
    // Class state.
    jclass mClass;
    jmethodID mExecTransact;

    // Object state.
    jfieldID mObject;

} gBinderOffsets;

gBinderOffsets有三个变量,记录着Binder对应的三种信息

const char* const kBinderPathName = "android/os/Binder";

static int int_register_android_os_Binder(JNIEnv* env)
{
    jclass clazz = FindClassOrDie(env, kBinderPathName);

    gBinderOffsets.mClass = MakeGlobalRefOrDie(env, clazz);
    gBinderOffsets.mExecTransact = GetMethodIDOrDie(env, clazz, "execTransact", "(IJJI)Z");
    gBinderOffsets.mObject = GetFieldIDOrDie(env, clazz, "mObject", "J");

    return RegisterMethodsOrDie(
        env, kBinderPathName,
        gBinderMethods, NELEM(gBinderMethods));
}

        可以看到,gBinderOffsets.mClass就是Binder的Class,gBinderOffsets.mExecTransact就是Binder的execTransact方法,gBinderOffsets.mObject就是Binder的mObject变量。那么ibinderForJavaObject代码的意思是从java层的IBinder对象中取出它的成员变量mObject强制转换为JavaBBinderHolder对象,然后再调用JavaBBinderHolder的get方法返回的一个c++层的IBinder对象。那就看看java层的IBinder对象是什么时候给mObject赋值的。

IBinder是一个接口,它有个基本的实现类Binder类,通常Server都是继承这个Binder类然后实现自己的业务逻辑。

Binder.java

public class Binder implements IBinder {
    ...
    public Binder() {
        init();
        ...
    }
private native final void init();

进入android_util_binder.cpp的android_os_Binder_init

static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    ...
    env->SetLongField(obj, gBinderOffsets.mObject, (jlong)jbh);
}
class JavaBBinderHolder : public RefBase
{
}

       这里可以看到在Server初始化的时候在基类Binder的构造方法里生成了一个c++层的JavaBBinderHolder对象,并将这个对象的地址保存在了成员变量mObject里。

那就接着看这个JavaBBinderHolder的get方法

class JavaBBinderHolder : public RefBase
{
public:
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            mBinder = b;
        }

        return b;
    }
class JavaBBinder : public BBinder
{
}

       这里可以看到c++层的IBinder对象的实际类型是JavaBBinder,而JavaBBinder又是继承BBinder类的,并且这个java层的Binder对象保存在这个JavaBBinder对象的成员变量mObject中。那么这里的JavaBBinder类和BBinder类有什么作用呢?我们知道了,一个进程只有一处地方负责与Binder驱动通信,而进程中可能存在多个Server,这样当Client端请求到来时,进程怎么知道转给哪个Server处理呢?进程从Binder驱动得到的是某个Server的内存地址,进程拿到这个内存地址强制转化成BBinder(因为Server继承了Binder类,那么底层是有个JavaBBinder与之对应的),然后调用BBinder的相关方法进行处理,JavaBBinder通过重写该方法,然后层层传递给java层的Binder类处理的,具体过程会在第4点Server的onTransact响应过程中有所讲解。

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        IBinder *local = binder->localBinder();
        if (!local) {
            ...
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        ...
    }

    return finish_flatten_binder(binder, obj, out);
}

结构flat_binder_object用于表示传输中的Binder。

struct flat_binder_object {
    /* 8 bytes for large_flat_header. */
    unsigned long        type;
    unsigned long        flags;
 
    /* 8 bytes of data. */
    union {
        void        *binder;    /* local object */
        signed long    handle;        /* remote object */
    };
 
    /* extra data associated with local object */
    void            *cookie;
};

         type表示Binder的类型,为BINDER_TYPE_BINDER时表示传输的是Binder实体,例如addService添加的就是Binder实体;为BINDER_TYPE_HANDLE表示传输的是Binder引用,例如getService得到的就是Binder的引用。当type为BINDER_TYPE_BINDER时,使用binder指向Binder实体的地址,当type为BINDER_TYPE_HANDLE时,使用handle表示Binder实体对应的句柄,cookie存放一些额外的信息

代码执行的是

obj.type = BINDER_TYPE_BINDER;
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = reinterpret_cast<uintptr_t>(local);

        这里表示的是传输的是一个Binder的实体对象,指向该Binder实体对象地址(对应的c++层的JavaBBinder对象的地址)的指针local保存在cookie中,从这个结构体的内容中可以看出些端倪,Binder对象的跨进程传输其实传输的只是这个Binder对象的地址,最后调用finish_flatten_binder将这个flat_binder_object写入Parcel中。

         Parcel中保存了Binder对象后就可以通过mRemote.transact发起远程通信了。上面的分析知道mRemote的实际类型是BinderProxy,而BinderProxy的transact方法也是简单的通过jni进入c/c++层的调用流程。

public class Binder implements IBinder {
...
final class BinderProxy implements IBinder {
    ...
    public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        return transactNative(code, data, reply, flags);
    }
    ...
    public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
}

       简单解释一下transact的code参数的意义:方法编号,我们知道单进程中代理的实现方式是代理持有原始对象的引用,访问代理对象的方法是由代理在内部访问原始对象的方法来实现的,而跨进程中,代理是无法直接访问到原始对象的方法的。因此,只能发送一个方法的编号告诉远程的原始对象该调用哪个方法,这个code就是起这个作用的

android_util_binder.cpp

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    ...
    Parcel* data = parcelForJavaObject(env, dataObj);
    if (data == NULL) {
        return JNI_FALSE;
    }
    Parcel* reply = parcelForJavaObject(env, replyObj);
    if (reply == NULL && replyObj != NULL) {
        return JNI_FALSE;
    }

    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);
    ...
    status_t err = target->transact(code, *data, reply, flags);
    ...
    return JNI_FALSE;
}

       前两段代码就是将java层的Parcel转换为c/c++层的Parcel对象,而obj就是前面的BinderProxy类型的对象。还记得前面在讲解BinderInternal.getContextObject()的javaObjectForIBinder的时候说过,这个BinderProxy对象在c/c++层有个对应的BpBinder对象,这个BpBinder的地址保存在BinderProxy的成员变量mObject中。这里就是通过GetLongField将这个BpBinder取出来,然后通过这个BpBinder对象发起对远程Server的请求,因为这个BpBinder内部保存着一个句柄值handle,而这个handle值在Binder驱动中唯一对应着一个Server的,因此通过这个BpBinder发起的远程请求是可以访问到远程的Server的,而这里的Server就是ServiceMananger。

BpBinder:transact

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

        这里出现了一个新的类IPCThreadState,这个IPCThreadState就是专门负责跟Binder驱动通信的。注意一下这里IPCThreadState的transact的前两个参数,这两个参数连起来就是要告诉Binder驱动我要调用ServiceMananger的编号为ADD_SERVICE_TRANSACTION的方法。

IPCThreadState:transact

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();
    ...
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        ...
    } else {
        err = waitForResponse(NULL, NULL);
    }
    
    return err;
}
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        cmd = (uint32_t)mIn.readInt32();
        ...
        switch (cmd) {
        ...
        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    ...
    
    return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }
    binder_write_read bwr;
    ...
    do {
        ...
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
    ...
    } while (err == -EINTR);

    ...
        return NO_ERROR;
    }
    
    return err;
}

       这里看到在talkWithDriver里调用了ioctl跟Binder驱动通信,数据就是这个binder_write_read类型的bwr,这个bwr的内容来源就是前面的Parcel的内容,其中最重要的内容就是Binder实体对象的地址。

       这样一个Server实体对象的地址就传递到了Binder驱动,Binder驱动经过一系列处理后唤醒ServerManager,还记得ServerManager睡眠在ioctl代码里吗,被唤醒后执行binder_parse进行消息的处理,这样Server实体就被纳入了ServerManager的管理了。

3.调用ServiceMananger.getService过程

ServiceMananger:getService

public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }

我们已经知道getIServiceManager返回的是ServiceManagerProxy

ServiceManagerProxy:getService(“name”)

class ServiceManagerProxy implements IServiceManager {

    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    public IBinder getService(String name) throws RemoteException {
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IServiceManager.descriptor);
    data.writeString(name);
    mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
    IBinder binder = reply.readStrongBinder();
    reply.recycle();
    data.recycle();
    return binder;
    }
    ...
}

       分析过前面的两点,getService就简单了。getService中reply.readStrongBinder()之前的代码和addService的过程是类似的,这里的mRemote.transact就是要告诉Binder驱动我要调用ServerMananger的编号为GET_SERVICE_TRANSACTION的方法,具体就不展开分析了。当执行到了reply.readStrongBinder()时,Client端就拿到了name对应的远程Binder实体对象在该Client进程中对应的句柄,下面就通过readStrongBinder读取出来了。

Parcel.java:readStrongBinder

public final IBinder readStrongBinder() {
    return nativeReadStrongBinder(mNativePtr);
}
private static native IBinder nativeReadStrongBinder(long nativePtr);

通过jni进入c/c++流程

android_os_Parcel.cpp:android_os_Parcel_readStrongBinder

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

       首先将java层Parcel对象保存的地址nativePtr强制转换为c++层的Parcel;接着从c++层的Parcel中读取出数据;最后调用javaObjectForIBinder将c++层的对象转为java层的对象返回给java层使用。

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}
status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

         调用Parcel的readObject取出表示Binder对象的flat_binder_object,这里的flat->type就等于BINDER_TYPE_HANDLE,表示Binder引用,因此这个flat->handle就是对应的句柄值了。接下来的流程就和在获取ServiceMananger的远程接口中的流程一致了,调用proc的getStrongProxyForHandle获得了一个实际类型为BpBinder对象,然后调用javaObjectForIBinder将这个BpBinder对象转换为java层的BinderProxy对象。这样Client端就得到Server的远程接口了,然后再调用asInterface根据这个IBinder对象(BinderProxy)创建一个XXXProxy的代理对象,因为XXXProxy和Server实现了一样的接口,因此使用XXXProxy就好像使用了远程的Server一样。

4.Server的onTransact响应过程

        获得了Server的远程接口后,Client端就可以使用这个Server的服务了,具体是通过调用XXXProxy的方法,由XXXProxy在内部调用Server的远程接口IBinder的transact方法发起对远端Server的请求。这个过程和ServerMananger.addService、ServerMananger.getService的过程是类似的,主要是告诉Binder驱动我要调用哪个Server的哪个方法。ServerMananger的响应过程我们知道了,现在来看看其它Server的响应过程。我们在实现自己的Server的时候发现并不需要额外的起一个循环,然后在循环里通过ioctl向Binder驱动获取消息,最后处理的这样一个过程,那是因为该Server所在的进程在启动的时候就已经具备了这样的能力。

        在Android应用程序中,是由ActivityManagerService组件负责为Android应用程序创建新的进程的,主要是从其成员函数startProcessLocked开始

ActivityManagerService:startProcessLocked

private final void startProcessLocked(ProcessRecord app, String hostingType,
        String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
    ...
        boolean isActivityProcess = (entryPoint == null);
        if (entryPoint == null) entryPoint = "android.app.ActivityThread";
        ...
        Process.ProcessStartResult startResult = Process.start(entryPoint,
                app.processName, uid, uid, gids, debugFlags, mountExternal,
                app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
                app.info.dataDir, entryPointArgs);
        ...
}

       在startProcessLocked中,主要是调用Process.start创建新的进程,其中参数entryPoint = “android.app.ActivityThread”,这个类我们应该很熟悉了,它就是代表了应用程序的主线程,ActivityThread被加载进来后,就会调用其main方法开始消息的循环。

Process.start开始后经过层层调用,最终会调用到RuntimeInit的zygoteInit方法

RuntimeInit:zygoteInit

public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
        throws ZygoteInit.MethodAndArgsCaller {
    ...
    nativeZygoteInit();
    applicationInit(targetSdkVersion, argv, classLoader);
}

       这里有两个关键的方法调用,一个是nativeZygoteInit,一个是applicationInit。applicationInit是进行ActivityThread的加载,并调用它的main方法进入消息循环;而nativeZygoteInit就是用来支持与Binder驱动通信的

nativeZygoteInit方法就不一步一步跟了,想知道执行的流程的话可以参考老罗的文章,最后会执行ProcessState的startThreadPool

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = true;
        spawnPooledThread(true);
    }
}
void ProcessState::spawnPooledThread(bool isMain)
{
    if (mThreadPoolStarted) {
        String8 name = makeBinderThreadName();
        ALOGV("Spawning new pooled thread, name=%s\n", name.string());
        sp<Thread> t = new PoolThread(isMain);
        t->run(name.string());
    }
}

这里会创建一个PoolThread线程类,然后执行它的run方法,最终会调用PoolThread的threadLoop方法。

先来看一下这个PoolThread线程的名字name,它是由makeBinderThreadName起的

String8 ProcessState::makeBinderThreadName() {
    int32_t s = android_atomic_add(1, &mThreadPoolSeq);
    String8 name;
    name.appendFormat("Binder_%X", s);
    return name;
}

       这个名字的规则是Binder_%X,这个X是从1开始并且递增的,由此可知,最简单的APP进程也至少包含的Binder_1、Binder_2线程,这些线程就是在这里创建的,并且Binder_1线程是在进程创建的时候就已经创建了,而Binder_2或者Binder_X线程是因后面的进程间通信的需要由Binder驱动调度按需通知进程创建的。

接着看看PoolThread的threadLoop方法

class PoolThread : public Thread
{
public:
    PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }
    
protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }
    
    const bool mIsMain;
};

       线程里调用了IPCThreadState的joinThreadPool方法,IPCThreadState前面讲过,它是专门来跟Binder驱动通信的,离真相原来越近了。

IPCThreadState:joinThreadPool

void IPCThreadState::joinThreadPool(bool isMain)
{
    ...
    mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    ...
        
    status_t result;
    do {
        result = getAndExecuteCommand();
        ...
    } while (result != -ECONNREFUSED && result != -EBADF)
    ...
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}
status_t IPCThreadState::getAndExecuteCommand()
{
    status_t result;
    int32_t cmd;
    result = talkWithDriver();
    if (result >= NO_ERROR) {
        ...
        cmd = mIn.readInt32();
        ...
        result = executeCommand(cmd);
        ...
    }

    return result;
}

       在IPCThreadState的joinThreadPool里面,进入一个循环,在循环里,调用talkWithDriver从Binder驱动获取消息,如果没有消息就会睡眠,如果有消息就会调用executeCommand进行处理。

       代码分析到这里可以得出一个结论:在应用程序进程创建的时候,会创建一个名叫Binder_1的线程,在Binder_1线程里开启一个循环,在循环里会调用talkWithDriver与Binder驱动进行交互。那么如果一个进程里有多个Server,该进程怎么知道把消息分发到哪个Server进行处理呢?

来看一下executeCommand

status_t IPCThreadState::executeCommand(int32_t cmd)
{
    BBinder* obj;
    RefBase::weakref_type* refs;
    status_t result = NO_ERROR;
    
    switch ((uint32_t)cmd) {
    ...
    case BR_TRANSACTION:
        {
            binder_transaction_data tr;
            result = mIn.read(&tr, sizeof(tr));
            ...
            if (tr.target.ptr) {
                sp<BBinder> b((BBinder*)tr.cookie);
                error = b->transact(tr.code, buffer, &reply, tr.flags);
            } else {
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }
            ...
            
        }
        break;
    ...
    case BR_SPAWN_LOOPER:
        mProcess->spawnPooledThread(false);
        break;
        ...
    }
    ...
    
    return result;
}

         executeCommand里只关注两个命令,一个BR_SPAWN_LOOPER,一个BR_TRANSACTION。BR_SPAWN_LOOPER是Binder驱动根据调度给进程下达的一个新起线程的命令,Binder_2和之后的线程就是接收到这个命令创建的。

         BR_TRANSACTION就是Server响应Client请求的,其中binder_transaction_data结构和前面分析过的flat_binder_object是类似的,binder_transaction_data中的cookie保存的是Server的内存地址,因此此处强转为BBinder对象,然后调用BBinder对象的transact

status_t BBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    ...
    switch (code) {
        ...
        default:
            err = onTransact(code, data, reply, flags);
            break;
    }
    ...
    return err;
}

       记得在前面分析addService的过程中,通过Parcel的writeStrongBinder将一个Binder实体对象写入Parcel的时候,在c++层实际上是将一个与其对应的JavaBBinder对象的地址写入c++层的Parcel中,而这个JavaBBinder又是继承BBinder的。而刚才应用进程中得到的地址cookie就是这个JavaBBinder对象的地址,最后强转成父类BBinder后调用transact进行处理,最终会调用onTransact,JavaBBinder重写了onTransact方法。

JavaBBinder:onTransact

virtual status_t onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
    JNIEnv* env = javavm_to_jnienv(mVM);
    ...
    IPCThreadState* thread_state = IPCThreadState::self();
    ...
    jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
        code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
   ...
    return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}

       前面的分析知道java层的Binder对象(Server)就是保存在JavaBBinder的mObject中的,这里通过CallBooleanMethod就执行到了java层Binder对象的execTransact方法了,这个execTransact方法定义在Binder类中

private boolean execTransact(int code, long dataObj, long replyObj,
        int flags) {
    Parcel data = Parcel.obtain(dataObj);
    Parcel reply = Parcel.obtain(replyObj);
    ...
    res = onTransact(code, data, reply, flags);
    ...

    return res;
}

        在Binder的execTransact中调用了onTransact方法,而Server继承Binder类后都会重写onTransact方法,这样就回调到了java层Server的onTransact方法了。

猜你喜欢

转载自blog.csdn.net/myself0719/article/details/85784622