跟踪java层服务activity的添加过程

相关源码文件:

// app 进程
/frameworks/base/core/java/android/app/Activity.java
/frameworks/base/core/java/android/app/Instrumentation.java
/frameworks/base/core/java/android/app/ActivityManagerNative.java
/frameworks/base/core/java/android/os/Binder.java
/frameworks/native/libs/binder/BpBinder.cpp
/frameworks/native/libs/binder/ProcessState.cpp
/frameworks/native/libs/binder/IPCThreadState.cpp
/frameworks/base/core/jni/android_os_Parcel.cpp
// ServiceManager 进程
/frameworks/native/cmds/servicemanager/service_manager.c
/frameworks/native/cmds/servicemanager/binder.c
// binder 驱动层
/drivers/android/binder.c
/drivers/staging/android/binder.c

Binder 驱动在 Android 中是无所不在的,比如最常见的 startActivity 和 startService 等等,都会经历多次进程间通信。那本文就基于 Activity 的启动流程,从 Java 层来跟踪分析服务的查找返回过程:

public void startActivityForResult(Intent intent, int requestCode, 
  @Nullable Bundle options) {
  if (mParent == null) {
    Instrumentation.ActivityResult ar = mInstrumentation.execStartActivity(this, 
      mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);
    ...
  } else {
    ...
  }
}

public ActivityResult execStartActivity(Context who, IBinder contextThread, 
  IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {
  ...
  // 这里两次跨进程通讯,一次获取AMS,另一次通过AMS的startActivity
  try {
    int result = ActivityManagerNative.getDefault()
        .startActivity(whoThread, who.getBasePackageName(), intent,
        intent.resolveTypeIfNeeded(who.getContentResolver()),token,
        target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);
    checkStartActivityResult(result, intent);
  } catch (RemoteException e) {
    throw new RuntimeException("Failure from system", e);
  }
  return null;
}

static public IActivityManager getDefault() {
  return gDefault.get();
}

private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
  protected IActivityManager create() {
    IBinder b = ServiceManager.getService("activity");
    if (false) {
      Log.v("ActivityManager", "default service binder = " + b);
    }
    IActivityManager am = asInterface(b);
    if (false) {
      Log.v("ActivityManager", "default service = " + am);
    }
    return am;
  }
};

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;
    }

private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager,BinderInternal.getContextObject()返回的是BinderProxy,里面的mObject带有new bpBinder(0)地址 
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
  }

// 这里跟踪到 Native 层的源码里面
public static final native IBinder getContextObject();

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

jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    AutoMutex _l(mProxyLock);
    // mClass = android/os/BinderProxy,其实就是 new 一个 java 的 BinderProxy
    object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
    if (object != NULL) {
        // 把 BpBinder(0) 的地址设置给 BinderProxy 的 mObject 属性
        env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
    }
    return object;
}

这里会拿到BinderProxy对象。


final class BinderProxy implements IBinder {
    public native boolean pingBinder();
    public native boolean isBinderAlive();

    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }

    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 String getInterfaceDescriptor() throws RemoteException;
    public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
    public native void linkToDeath(DeathRecipient recipient, int flags)
            throws RemoteException;
    public native boolean unlinkToDeath(DeathRecipient recipient, int flags);

    public void dump(FileDescriptor fd, String[] args) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeFileDescriptor(fd);
        data.writeStringArray(args);
        try {
            transact(DUMP_TRANSACTION, data, reply, 0);
            reply.readException();
        } finally {
            data.recycle();
            reply.recycle();
        }
    }
    
    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeFileDescriptor(fd);
        data.writeStringArray(args);
        try {
            transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
        } finally {
            data.recycle();
            reply.recycle();
        }
    }

    BinderProxy() {
        mSelf = new WeakReference(this);
    }
    
    @Override
    protected void finalize() throws Throwable {
        try {
            destroy();
        } finally {
            super.finalize();
        }
    }
    
    private native final void destroy();
    
    private static final void sendDeathNotice(DeathRecipient recipient) {
        if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
        try {
            recipient.binderDied();
        }
        catch (RuntimeException exc) {
            Log.w("BinderNative", "Uncaught exception from death notification",
                    exc);
        }
    }
    
    final private WeakReference mSelf;
    private long mObject; //mObject即为native的new bpbinder(0)地址
    private long mOrgue;
}

//transactNative通过jni调用android_os_BinderProxy_transact方法,位于android_util_Binder.cpp中
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
  jint code, jobject dataObj, jobject replyObj, jint flags) {
  // 获取 native 层的 Parcel
  Parcel* data = parcelForJavaObject(env, dataObj);
  Parcel* reply = parcelForJavaObject(env, replyObj);
  // 获取 BpBinder(0)
  IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
  // 调用 BpBinder 的 transact 方法
  status_t err = target->transact(code, *data, reply, flags);
  return JNI_FALSE;
}

//调用 BpBinder 的 transact 方法,这里之前分析media添加过程也分析过,后面交给 IPCThreadState::self()对象发给binder驱动,通过binder驱动发给servicemanager。 

BinderInternal.getContextObject()返回的是Java 层来看是一个 IBinder (BinderProxy)对象,BinderProxy中的元素mObject即 new BpBinder(0)的地址

static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);
        if (in != null) {
            return in;
        }
        //这里返回一个ServiceManagerProxy的对象,obj即为BpBinder(0)的地址,通过java BinderProxy包装了一下。
        return new ServiceManagerProxy(obj);
    }

class ServiceManagerProxy implements IServiceManager {
    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }
    
    public IBinder asBinder() {
        return mRemote;
    }
    
    public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        //mRemote是BinderProxy对象
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

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

    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();
    }
    
    public String[] listServices() throws RemoteException {
        ArrayList<String> services = new ArrayList<String>();
        int n = 0;
        while (true) {
            Parcel data = Parcel.obtain();
            Parcel reply = Parcel.obtain();
            data.writeInterfaceToken(IServiceManager.descriptor);
            data.writeInt(n);
            n++;
            try {
                boolean res = mRemote.transact(LIST_SERVICES_TRANSACTION, data, reply, 0);
                if (!res) {
                    break;
                }
            } catch (RuntimeException e) {
                // The result code that is returned by the C++ code can
                // cause the call to throw an exception back instead of
                // returning a nice result...  so eat it here and go on.
                break;
            }
            services.add(reply.readString());
            reply.recycle();
            data.recycle();
        }
        String[] array = new String[services.size()];
        services.toArray(array);
        return array;
    }

    public void setPermissionController(IPermissionController controller)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeStrongBinder(controller.asBinder());
        mRemote.transact(SET_PERMISSION_CONTROLLER_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }

    private IBinder mRemote;
}

getIServiceManager 返回的其实就是 new BpBinder(0) ,只不过在 Java 层来看是一个 IBinder (BinderProxy)对象。我们接着往下跟踪 getService() 的具体实现。

public IBinder getService(String name) throws RemoteException {
  // 构建一个发送数据的 Parcel 和一个接收数据的 Parcel
  Parcel data = Parcel.obtain();
  Parcel reply = Parcel.obtain();
  // 把请求数据写入 data 
  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;
}

final class BinderProxy implements IBinder {
  ...
  public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;

  public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
    return transactNative(code, data, reply, flags);
  }
  // mObject = new BpBinder(0)
  private long mObject;
  ...
}
//根据gBinderProxyMethods变量transactNative会调用到android_os_BinderProxy_transact方法
//static const JNINativeMethod gBinderProxyMethods[] = {
     /* name, signature, funcPtr */
//    {"pingBinder",          "()Z", (void*)android_os_BinderProxy_pingBinder},
//    {"isBinderAlive",       "()Z", (void*)android_os_BinderProxy_isBinderAlive},
//    {"getInterfaceDescriptor", "()Ljava/lang/String;", (void*)android_os_BinderProxy_getInterfaceDescriptor},
//    {"transactNative",      "(ILandroid/os/Parcel;Landroid/os/Parcel;I)Z", (void*)android_os_BinderProxy_transact},
//    {"linkToDeath",         "(Landroid/os/IBinder$DeathRecipient;I)V", (void*)android_os_BinderProxy_linkToDeath},
//    {"unlinkToDeath",       "(Landroid/os/IBinder$DeathRecipient;I)Z", (void*)android_os_BinderProxy_unlinkToDeath},
//    {"destroy",             "()V", (void*)android_os_BinderProxy_destroy},
//};

//位于frameworks\base\core\jni\android_util_Binder.cpp中
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
  jint code, jobject dataObj, jobject replyObj, jint flags) {
  // 获取 native 层的 Parcel
  Parcel* data = parcelForJavaObject(env, dataObj);
  Parcel* reply = parcelForJavaObject(env, replyObj);
  // 获取 BpBinder(0)
  IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
  // 调用 BpBinder 的 transact 方法
  status_t err = target->transact(code, *data, reply, flags);
  return JNI_FALSE;
}

//位于frameworks\native\libs\binder\BpBinder.cpp
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;
}

// 在《Android Binder 驱动 - Media 服务的添加过程》一文中有详细介绍
status_t IPCThreadState::transact(int32_t handle,uint32_t code, 
    const Parcel& data,Parcel* reply, uint32_t flags){
  ...
}

下面主要来看下 ServiceManager 进程是如何回复我们的。

int main(int argc, char **argv)
{
    struct binder_state *bs;

    bs = binder_open(128*1024);
    if (!bs) {
        ALOGE("failed to open binder driver\n");
        return -1;
    }

    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    selinux_enabled = is_selinux_enabled();
    sehandle = selinux_android_service_context_handle();
    selinux_status_open(true);

    if (selinux_enabled > 0) {
        if (sehandle == NULL) {
            ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
            abort();
        }

        if (getcon(&service_manager_context) != 0) {
            ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
            abort();
        }
    }

    union selinux_callback cb;
    cb.func_audit = audit_callback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
    cb.func_log = selinux_log_callback;
    selinux_set_callback(SELINUX_CB_LOG, cb);

    binder_loop(bs, svcmgr_handler);

    return 0;
}

//servicemanager进入binder_loop函数
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;
    uint32_t readbuf[32];

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;
    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }

        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);

        switch(cmd) {
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: txn too small!\n");
                return -1;
            }
            binder_dump_txn(txn);
            if (func) {
                unsigned rdata[256/4];
                struct binder_io msg;
                struct binder_io reply;
                int res;

                bio_init(&reply, rdata, sizeof(rdata), 4);
                bio_init_from_txn(&msg, txn);
                // 先执行回调函数,fun函数是svcmgr_handler
                res = func(bs, txn, &msg, &reply);
                // 然后把执行结果写入 binder 驱动
                binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
            }
        }
    }

    return r;
}

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //找到handle的值
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);
        return 0;
        ...
    }

    bio_put_uint32(reply, 0);
    return 0;
}

void bio_put_ref(struct binder_io *bio, uint32_t handle)
{
    struct flat_binder_object *obj;

    if (handle)
        obj = bio_alloc_obj(bio);
    else
        obj = bio_alloc(bio, sizeof(*obj));

    if (!obj)
        return;
    // 向 replay 中写入一个 flat_binder_object
    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    obj->type = BINDER_TYPE_HANDLE;
    obj->handle = handle;
    obj->cookie = 0;
}

void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       binder_uintptr_t buffer_to_free,
                       int status)
{
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;
    // 第一个命令是BC_FREE_BUFFER,释放之前的数据占用的内存
    data.cmd_free = BC_FREE_BUFFER;
    data.buffer = buffer_to_free;
    // 第二个命令是BC_REPLY,回复命令
    data.cmd_reply = BC_REPLY;
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        ...
    } else {
        // 把回复的数据写入data.txn
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    binder_write(bs, &data, sizeof(data));
}

int binder_write(struct binder_state *bs, void *data, size_t len)
{
    struct binder_write_read bwr;
    int res;
    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    // 向驱动层写入数据,read_size = 0 
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    if (res < 0) {
        fprintf(stderr,"binder_write: ioctl failed (%s)\n",
                strerror(errno));
    }
    return res;
}

客户端是怎么进入等待的?。
客户端是因为在请求服务端的时候驱动层会写入一个 BINDER_WORK_TRANSACTION_COMPLETE , 然后会清空 writeData , 从新进入驱动层,进入读方法,因为todo队列里面没东西进入等待,等待服务端执行完毕唤醒客户端。流程如下:

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();
    ...
    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
    ...
    if ((flags & TF_ONE_WAY) == 0) {
        ...
        if (reply) {
            //客户端在这里进入睡眠,等待服务端的回复
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        #if 0
        if (code == 4) { // relayout
            ALOGI("<<<<<< RETURNING transaction 4");
        } else {
            ALOGI("<<<<<< RETURNING transaction %d", code);
        }
        #endif
        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
    return err;
}

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    ...
    flags |= TF_ACCEPT_FDS;   //添加TF_ACCEPT_FDS
    ...
    //等待响应
    if ((flags & TF_ONE_WAY) == 0) { //检查本次通讯是否有TF_ONE_WAY标志,即没有响应
        //reply是否为空
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        ...
    }
    ...
    return err;
}

一般通讯都需要响应,所以我们就只看有响应的情况了,即flags中不包含TF_ONE_WAY标记。调用waitForResponse()函数时,如果没有reply,会创建一个fakeReplay。我们回顾一下:
transact(0, IBinder::PING_TRANSACTION, data, NULL, 0)
紧接着,我们就进入到IPCThreadState::waitForResponse()中了。

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    while (1) {
        //真正和Binder驱动交互的是talkWithDriver()函数
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
    }
    ...
}

这个方法中,一开始就有些隐蔽的调用了一个十分重要的方法IPCThreadState::talkWithDriver(),从名字也能看出来,真正和Binder驱动talk的逻辑是在这个函数中的。这个地方给差评!
IPCThreadState::talkWithDriver()这个函数的参数默认为true!

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    ...
    //读写结构体,它是用户空间和内核空间的信使
    binder_write_read bwr;
    ...
    //配置发送信息
    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();
    ...
    //获取接收信息
    if(doReceive && needRead){
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
    ...
    //设置消耗为0
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        ...
        //通过ioctl操作与内核进行读写
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        ...
    } while (err == -EINTR);
    ...
}

这个函数中,有一个重要结构被定义,就是binder_write_read。它能够储存一些必要的发送和接收的通讯信息,它就像用户空间和内核空间之间的一个信使一样,在两端传递信息。

在这个函数中,首先会把用户空间要传递/读取信息放到bwr中,然后通过一句关键的代码ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)与Binder驱动talk。
注意这里我们给ioctl()函数传递的参数。

第一个参数,是从本进程中取出上面篇中打开并保存Binder设备文件描述符,通过它可以获取到之前生成的file文件结构,然后传给binder_ioctl()函数。没印象的同学先看看上篇回顾下这里。
第二个参数,是命令,它决定了待会到内核空间中要执行那段逻辑。
第三个参数,我们把刚刚定义的信使bwr的内存地址传到内核空间去。

static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
    int ret;
    // 从file结构体中取出进程信息
    struct binder_proc *proc = filp->private_data;
    struct binder_thread *thread;
    unsigned int size = _IOC_SIZE(cmd);
    //表明arg是一个用户空间地址
    //__user标记该指针为用户空间指针,在当前空间内无意义
    void __user *ubuf = (void __user *)arg;
    ...
    //锁定同步
    binder_lock(__func__);
    //取出线程信息
    thread = binder_get_thread(proc);
    ...
    switch (cmd) {
        //读写数据
        case BINDER_WRITE_READ:
            ret = binder_ioctl_write_read(filp, cmd, arg, thread); 
            ...
        }
        ...
    }
    ...
    //解锁
    binder_unlock(__func__);
    ...
}

static int binder_ioctl_write_read(struct file *filp,
                                   unsigned int cmd, unsigned long arg,
                                   struct binder_thread *thread)
{
    int ret = 0;
    //获取发送进程信息
    struct binder_proc *proc = filp->private_data;
    unsigned int size = _IOC_SIZE(cmd);
    //来自用户空间的参数地址
    void __user *ubuf = (void __user *)arg;
    //读写信息结构体
    struct binder_write_read bwr;
    ...
    //拷贝用户空间的通讯信息bwr到内核的bwr
    if (copy_from_user(&bwr, ubuf, sizeof(bwr)))
    ...
    if (bwr.write_size > 0) {
        //写数据
        ret = binder_thread_write(proc, thread,
                                  bwr.write_buffer,
                                  bwr.write_size,
                                  &bwr.write_consumed);
    ...
}

首先自然是取出用户空间的进程信息,然后转换获得用户空间的参数地址(对应本次通讯中为bwr的地址),这些都跟在binder_ioctl()中做的差不多。

接下来,你可以看到一个binder_write_read结构的申明struct binder_write_read bwr,紧跟着通过copy_from_user(&bwr, ubuf, sizeof(bwr))把用户空间的bwr拷贝到了当前内核空间的bwr。现在,Binder内核空间的bwr就获取到了来自用户空间的通讯信息了。

获取到来自用户空间的信息后,先调用binder_thread_write()函数来处理,我看看是如何进行处理的。

static int binder_thread_write(struct binder_proc *proc,
                               struct binder_thread *thread,
                               binder_uintptr_t binder_buffer, size_t size,
                               binder_size_t *consumed)
{
    uint32_t cmd;
    void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
    void __user *ptr = buffer + *consumed;    //起始地址
    void __user *end = buffer + size;         //结束地址
    while (ptr < end && thread->return_error == BR_OK) {
        //从用户空间获取cmd命令
        if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
        ptr += sizeof(uint32_t);
        switch (cmd) {
            case BC_TRANSACTION:
            case BC_REPLY: {
                //用来储存通讯信息的结构体
                struct binder_transaction_data tr;
                //拷贝用户空间的binder_transaction_data
                if (copy_from_user(&tr, ptr, sizeof(tr)))   return -EFAULT;
                ptr += sizeof(tr);
                //处理通讯
                binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
                break;
            }
                ...
        }
        *consumed = ptr - buffer;
    }
    return 0;
}

首先,binder_buffer是啥?哪来的?快到到传参的地方方看看bwr.write_buffer,它是写的buffer。那么它里面装了啥?bwr.write_buffer = (uintptr_t)mOut.data(),嗯,它指向了mOut中的数据。那么问题又来了?mOut中的数据是啥?…
writeTransactionData(),就是通讯事务结构定义的那个地方。看到没,mOut中储存的就是一个通讯事务结构。如下:

status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
    int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
    //储存通讯事务数据的结构
    binder_transaction_data tr;
    tr.target.ptr = 0;  //binder_node的地址
    tr.target.handle = handle;  //用于查找目标进程Binder的handle,对应binder_ref
    tr.code = code; //表示事务类型
    tr.flags = binderFlags;
    tr.cookie= 0;
    ...
    //Parcel mOut,与之相反的有Parcel mIn
    //写入本次通讯的cmd指令
    mOut.writeInt32(cmd);
    //把本次通讯事务数据写入mOut中
    mOut.write(&tr, sizeof(tr));
    return NO_ERROR;
}
这个函数主要创建了一个用于储存通讯事务数据的binder_transaction_data结构t,
并把需要发送的事务数据放到其中,然后再把这个tr写入IPCThreadState的mOut中。
这样一来,后面就可以从mOut中取出这个通讯事务数据结构了。

回到binder_thread_write函数中
通过get_user(cmd, (uint32_t __user *)ptr)函数,我们可以将用户空间的tr的cmd拷贝到内核空间。get_user()和put_user()这对函数就是干这个的,拷贝一些简单的变量。回到第2步writeTransactionData()中,看看参数。没错,cmd为BC_TRANSACTION。所以,进到switch中,对应执行的就是case BC_TRANSACTION。
可以看到BC_TRANSACTION事务命令和BC_REPLAY响应命令,执行的是相同的逻辑。

binder_transaction()来处理事务,先看第一个使用到的参数replay。由于上一步中的cmd为BC_TRANSACTION,所以很明显,走的是false,所以我们直接看false里的逻辑。


static void binder_transaction(struct binder_proc *proc,
                               struct binder_thread *thread,
                               struct binder_transaction_data *tr, int reply){
    // reply=(cmd==BC_REPLY)即false
    ...
    if (reply) {
        ...
    } else {
        if (tr->target.handle) {
            //如果参数事物信息中的进程的句柄不为0,即不是系统ServiceManager进程
            
            //定义binder引用
            struct binder_ref *ref;
            //根据参数binder进程和句柄handle来查找对应的binder
            ref = binder_get_ref(proc, tr->target.handle);
            ...
            //设置目标binder实体为上面找到的参数进程的binder引用的binder实体
            target_node = ref->node;
        } else {
            //如果参数事物信息中的进程的句柄为0,即是系统ServiceManager进程
            
            //设置通讯目标进程的Binder实体为ServiceManager对应的Binder
            target_node = binder_context_mgr_node;
        }
        //设置通讯目标进程为target_node对应的进程
        target_proc = target_node->proc;
        ...
         //判断目标线程是否为空
         //首先看target_thread是否为空,由于我们没有走if(replay)的TRUE逻辑,所以这里target_thread是为空的。那么,从目标进程信息target_proc分别去除todo任务队列和wait对象,赋值给target_list和target_wait。同样需要记住!

    if (target_thread) {
        ...
        //目标线程的todo队列
        target_list = &target_thread->todo;
        target_wait = &target_thread->wait;
        ...
    } else {
        //获得通讯目标进程的任务队列
        target_list = &target_proc->todo;
        //获取通讯目标进程的等待对象
        target_wait = &target_proc->wait;
    }
    ...
    /*其实这么多代码,主要使用在给binder事务t的成员赋值了。我们简单看几个我认为重要的赋值。

首先为事务t和work tcomplete申请了内存。然后设置事务t的from线程(也就是发送方线程)的值,如果不是BC_REPLAY事务,并且通讯标记没有TF_ONE_WAY(即本次通讯需要有响应),那么把参数thread赋值给t->from。前面说过,我们本次通讯是BC_TRANSACTION事务,所以事务t就需要储存发送方的线程信息,以便后面给发送方响应使用。

参数thread是那来的呢?顺着往回找,在binder_ioctl()中,我们从用户空间调用ioctl()函数的进程(即发送方进程)的进程信息中获取到了thread。

接着设置事务t的目标进程t->to_proc和目标进程的线程t->to_thread为前面处理好的target_proc和target_thread(本次通讯,target_thread为空哦)
然后把通讯事务数据tr中的code和flags赋值给事务t的code和flags。code和flags是什么呢?我们回到用户空间,定义通讯事务数据,即IPCThreadState::writeTransaction()中可以看到,code和flags均是传进来的参数。而的发源地是通讯的起始点IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0),即code = IBinder::PING_TRANSACTION, flags = 0。记住了哦!后面还会用。
然后开始设置事务t的buffer信息。首先通过binder_alloc_buf()函数,在目标进程target_proc中为t->buffer申请了内存,即t->buffer指向了目标进程空间中的一段内存。然后配置一下t->buffer的信息,这些信息后面也会用到。记住了哦!
接着通过copy_from_user()函数,把用户空间的需要发送的数据拷贝到t->buffer的data中。
再往下到了if(replay),本次通讯会走false逻辑。于是,事务t会把发送方的事务栈transaction_stack储存在from_parent中,而发送方把自己的事务栈设置以成t开始。这些都需要记住,不然再往后你就会越来越迷糊!
*/

    //为本次通讯事务t申请空间
    t = kzalloc(sizeof(*t), GFP_KERNEL);
    ...
    tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
    ...
    if (!reply && !(tr->flags & TF_ONE_WAY))
        //采用非one way通讯方式,即需要等待服务端返回结果的通讯方式
        
        //设置本次通讯事务t的发送线程为用户空间的线程
        t->from = thread;
    else
        t->from = NULL;
    ...
    //设置本次通讯事务的接收进程为目标进程
    t->to_proc = target_proc;
    //设置本次通讯事务的接收线程为目标线程
    t->to_thread = target_thread;
    //设置本次通讯事务的命令为用户空间传来的命令
    t->code = tr->code;
    //设置本次通讯事务的命令为用户空间传来的flags
    t->flags = tr->flags;
    ...
    //开始配置本次通讯的buffer
    //在目标进程中分配进行本次通讯的buffer的空间  
    t->buffer = binder_alloc_buf(target_proc, tr->data_size,
                                 tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
    
    t->buffer->allow_user_free = 0; //通讯buffer允许释放
    t->buffer->transaction = t;  //把本次通讯存入buffer中
    //设置本次通讯的buffer的目标Binder实体为target_node
    //如前面一样,通过这个buffer可以找到对应的进程
    t->buffer->target_node = target_node;
    ...
    offp = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
    //将用户空间发送来的数据拷贝到本次通讯的buffer的data中
    copy_from_user(t->buffer->data, (const void __user *)(uintptr_t)tr->data.ptr.buffer, tr->data_size);
    ...
    //将用户空间发送来的偏移量offsets拷贝给起始offp
    copy_from_user(offp, (const void __user *)(uintptr_t)tr->data.ptr.offsets, tr->offsets_size);
    ...
    //计算结尾off_end
    off_end = (void *)offp + tr->offsets_size;
    ...
    //判断是否是BC_REPLY
    if (reply) {
        ...
        
        binder_pop_transaction(target_thread, in_reply_to);
    } else if (!(t->flags & TF_ONE_WAY)) {
        //如果没有ONE_WAY标记,即需要等待响应
        t->need_reply = 1;  //1标示这是一个同步事务,需要等待对方回复。0表示这是一个异步事务,不用等对方回复
        //设置本次通讯事务的from_parent为发送方进程的事务
        t->from_parent = thread->transaction_stack;
        //设置发送方进程的事务栈为本次通讯事务
        thread->transaction_stack = t;
    }
    ...
   
     /*先把事务t的work.type类型设置为BINDER_WORK_TRANSACTION类型,这决定了该事务后面走的流程,然后把事务t的任务添加到目标进程的任务栈target_list中。接着把work tcomplete的类型设置为BINDER_WORK_TRANSACTION_COMPLETE,用于告诉发送方,和Binder驱动的一次talk完成了,同样,需要把这个项任务添加到发送方的任务列表里。
最后,通过wake_up_interruptible(target_wait)函数唤醒休眠中的目标进程,让它开始处理任务栈中的任务,也就是刚刚我们添加到target_list中的任务。接着return结束该函数。*/
    //将本次通讯事务的work类型设置为BINDER_WORK_TRANSACTION
    t->work.type = BINDER_WORK_TRANSACTION;
    //将本次通讯事务的work添加到目标进程的事务列表中
    list_add_tail(&t->work.entry, target_list);
    
    //设置work类型为BINDER_WORK_TRANSACTION_COMPLETE
    tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
    //将BINDER_WORK_TRANSACTION_COMPLETE类型的work添加到发送方的事务列表中
    list_add_tail(&tcomplete->entry, &thread->todo);
    
    if (target_wait)
        //唤醒目标进程,开始执行目标进程的事务栈
        wake_up_interruptible(target_wait);//当target_node = binder_context_mgr_node时,这里唤醒的是servicemanager
    return;
}

/*上一个函数结束后回到binder_thread_write()函数中,retrun 0;,binder_thread_write()函数结束。然后回到binder_ioctl_write_read()函数中继续执行。*/
static int binder_ioctl_write_read(struct file *filp,
                                   unsigned int cmd, unsigned long arg,
                                   struct binder_thread *thread)
{
    ...
    if (bwr.read_size > 0) {
        //读数据
        ret = binder_thread_read(proc, thread, bwr.read_buffer,
                                 bwr.read_size,
                                 &bwr.read_consumed,
                                 filp->f_flags & O_NONBLOCK);
        ...
}

//Binder驱动会调用binder_thread_read()函数,为发送进程读取数据。我们看看是怎么读取的。
/*
我们先看这个片段,前面一堆代码掠过了。首先,需要看看能不能从发送进程的线程thread的任务栈中取出任务来,回顾binder_transaction()中,我们在最后往发送进程的线程thread的任务栈中添加了一个BINDER_WORK_TRANSACTION_COMPLETE类型的work。所以这里是能取到任务的,就直接执行下一步了。
*/
```cpp
static int binder_thread_read(struct binder_proc *proc,
                              struct binder_thread *thread,
                              binder_uintptr_t binder_buffer,
                              size_t size,
                              binder_size_t *consumed,
                              int non_block)
{
    ...
    while (1) {
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        if (!list_empty(&thread->todo)) {
            //获取线程的work队列
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
            //获取从进程获取work队列
            w = list_first_entry(&proc->todo, struct binder_work, entry);
        } else {
            //没有数据,则返回retry
            if (ptr - buffer == 4 &&
                !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
                goto retry;
            break;
        }
    ...
    switch (w->type) {
            ...
            case BINDER_WORK_TRANSACTION_COMPLETE:
                //设置cmd为BR_TRANSACTION_COMPLETE
                cmd = BR_TRANSACTION_COMPLETE;
                //将BR_TRANSACTION_COMPLETE写入用户进程空间的mIn中
                put_user(cmd, (uint32_t __user *)ptr)//从事务队列中删除本次work
                list_del(&w->entry);
                //释放
                kfree(w);
                break;
            ...
        }
}

//接着又会回到binder_ioctl_write_read()函数。
static int binder_ioctl_write_read(struct file *filp,
                                   unsigned int cmd, unsigned long arg,
                                   struct binder_thread *thread)
{
    ...
    //将内核的信使bwr拷贝到用户空间
    if (copy_to_user(ubuf, &bwr, sizeof(bwr)))
    ...
}

/*上面函数最后会把内核中的信使拷贝到用户空间。然后,我们直接的再次的回到第3步的函数IPCThreadState::waitForResponse()中。经过刚刚的读取,这次mIn中可是有数据了哦!我们从mIn中取出cmd命令。这是什么命令呢?就是刚刚写到用户空间的BR_TRANSACTION_COMPLETE。在这段逻辑中,由于之前我们传入了一个fakeReplay进来,所以程序走bredk,然后继续循环,执行下一次talkWithDriver()函数。到此,我们和Binder内核的一次通讯算是完成了。
*/
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    while (1) {
        //真正和Binder驱动交互的是talkWithDriver()函数
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        ...
        if (mIn.dataAvail() == 0) continue;
        //取出在内核中写进去的cmd命令
        cmd = mIn.readInt32();
        ...
        
        switch (cmd) {
            //表示和内核的一次通讯完成
            case BR_TRANSACTION_COMPLETE:
                if (!reply && !acquireResult) goto finish;
                break;
            ...
        }
        
    }

经过刚刚的读取,这次mIn中可是有数据了哦!我们从mIn中取出cmd命令。这是什么命令呢?就是刚刚写到用户空间的BR_TRANSACTION_COMPLETE。在这段逻辑中,由于之前我们传入了一个fakeReplay进来,所以程序走bredk,然后继续循环,执行下一次talkWithDriver()函数。到此,我们和Binder内核的一次通讯算是完成了。

通讯发起端的休眠ING
发起端进程在收到Binder内核响应的BR_TRANSACTION_COMPLETE后,再一次的进入了IPCThreadState::talkWithDriver()函数。这就意味着发起端需要和Binder内核再通讯一次。

而这一次通讯,由于没有需要发送的的数据,所以我们直接看Binder内核中的binder_thread_read()函数,在图中找到对应的位置进入状态了啊。那么我们看看这一次发起端进程在binder_thread_read()函数中被进行了怎样的处理

static int binder_thread_read(struct binder_proc *proc,
                              struct binder_thread *thread,
                              binder_uintptr_t binder_buffer,
                              size_t size,
                              binder_size_t *consumed,
                              int non_block)
{
    ...
    //检查是否需要等待进程work完成
    wait_for_proc_work = thread->transaction_stack == NULL && list_empty(&thread->todo);
    ...
    if (wait_for_proc_work) {
        ...
    } else {
        if (non_block) {
            ...
        } else
            //如果不需要等待,进程进入休眠,等待唤醒
            ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));
    }
    ...

我们只看关键的。还记得binder_transaction()函数中,我们最后把添加到目标进程中的事务t同时赋值给了发送端进程的thread->transaction_stack。所以此处的thread->transaction_stack是不为NULL的。从而wait_for_proc_work就为false,于是就执行到了ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));这一句,然后发送端进程就进入了休眠。目的是为了等待目标进程处理完请求后给予它响应。
现在,发送端进程进入了休眠,是时候来看一看本次通讯的目标进程了。在binder_transaction()函数中,我们把发送端的诉求封装进了一个事务t中,然后把事务t添加到了目标进程的事务队列中,最后把目标进程唤醒了。

第一步 从沉睡中醒来

static int binder_thread_read(struct binder_proc *proc,
                              struct binder_thread *thread,
                              binder_uintptr_t binder_buffer,
                              size_t size,
                              binder_size_t *consumed,
                              int non_block)
{
    ...
    ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));
    ...
    if (ret)
        return ret;
    ...
}

由于是通过正常的wake_up_interruptible()函数进行唤醒,所以返回的ret = 0。接着,目标进程会进入switch,根据之前设置的cmd执行相应逻辑。

static int binder_thread_read(struct binder_proc *proc,
                              struct binder_thread *thread,
                              binder_uintptr_t binder_buffer,
                              size_t size,
                              binder_size_t *consumed,
                              int non_block)
{
    ...
        while (1) {
        
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        if (!list_empty(&thread->todo)) {
            //获取线程的work队列
            w = list_first_entry(&thread->todo, struct binder_work, entry);
        } else if (!list_empty(&proc->todo) && wait_for_proc_work) {
            //获取从进程获取work队列
            w = list_first_entry(&proc->todo, struct binder_work, entry);
        } else {
            //没有数据,则返回retry
            if (ptr - buffer == 4 &&
                !(thread->looper & BINDER_LOOPER_STATE_NEED_RETURN))
                goto retry;
            break;
        }
        
        switch (w->type) {
            case BINDER_WORK_TRANSACTION:
                //根据队列中的work获取包含该work的事务
                t = container_of(w, struct binder_transaction, work);
                break;
                
            ...
        }
    ...
}

这部分需要结合binder_transaction()函数来看,很多参数都是来自于那的。
根据之前的逻辑,我们并没有给目标进程的thread->todo赋值,而是给它的proc->todo赋了值。如下:

if (target_thread) {
		e->to_thread = target_thread->pid;
		target_list = &target_thread->todo;
		target_wait = &target_thread->wait;
	} else {
		target_list = &target_proc->todo;
		target_wait = &target_proc->wait;
	}

因此,我们从proc->todo的任务队列中取出之前添加的任务。因为任务类型是BINDER_WORK_TRANSACTION,所以swicth中走了BINDER_WORK_TRANSACTION的逻辑,获取到通讯事务t。接着看下面的逻辑。

static int binder_thread_read(struct binder_proc *proc,
                              struct binder_thread *thread,
                              binder_uintptr_t binder_buffer,
                              size_t size,
                              binder_size_t *consumed,
                              int non_block)
{
    ...
        while (1) {
        
        uint32_t cmd;
        struct binder_transaction_data tr;
        struct binder_work *w;
        struct binder_transaction *t = NULL;
        ...
        //只有BINDER_WORK_TRANSACTION命令,即t不为空才能继续往下执行
        if (!t)
            continue;
        
        //判断事物t中是否有目标进程的Binder实体
        if (t->buffer->target_node) {
            struct binder_node *target_node = t->buffer->target_node;
            tr.target.ptr = target_node->ptr;
            tr.cookie =  target_node->cookie;
            t->saved_priority = task_nice(current);
            ...
            cmd = BR_TRANSACTION;  //设置命令为BR_TRANSACTION
        } else {
            tr.target.ptr = NULL;
            tr.cookie = NULL;
            cmd = BR_REPLY; //设置命令为BR_REPLY
        }
        //给刚刚定义的事务信息体设置成员的值
        tr.code = t->code;
        tr.flags = t->flags;
        tr.sender_euid = t->sender_euid;
        ...
        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.buffer = (void *)t->buffer->data +
        proc->user_buffer_offset;
        tr.data.ptr.offsets = tr.data.ptr.buffer +
        ALIGN(t->buffer->data_size,
              sizeof(void *));
        
        //将cmd和数据写回用户空间的mIn
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        //刚刚赋值好的事务信息写会用户空间的mIn,ptr是servicemanager用户空间传来的地址
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
        ptr += sizeof(tr);
        //删除本次work
        list_del(&t->work.entry);
        ...
        kfree(t); //通信完成,则运行释放
        break;
    }
    ...
    return 0;
}

对于if(!t),很明显,我们是有事务t,所以代码会接着往下执行。

我们之前有t->buffer->target_node = target_node;,所以这里t->buffer->target_node)是不为空的。然后,取出这个target_node,也就是目标进程的Binder实体。

接着,把目标进程的Binder实体的引用和cookie缓存保存到新定义的通讯数据tr中。然后,设置命令为BR_TRANSACTION,这些都需要记好了哦。
接下来就是把事务t中的数据储存到新定义的通讯数据tr中。然后把刚刚的cmd拷贝到目标进程空间,再把新定义的通讯数据tr也拷贝到目标进程空间。最后删除本次事务,释放内存,结束该函数。

退出ioctl()函数
上一步函数结束后,函数基本都是一路退出,直到Binder内核的binder_ioctl()函数。至此,由于我们的目标进程是ServiceManager,所以binder_ioctl()函数执行完后,返回的是/frameworks/native/cmds/servicemanager/binder.c中的binder_looper()。
至于为什么会回到binder_looper()函数,这与ServiceManager的机制有关。由于它在系统中既是一个Service,又是一个守护进程,它需要不断的循环等待Client的请求。处理完一个请求,就再次进入循环等待下一个请求。而这个函数就是为它提供这种能力的。这里我们先不讨论ServiceManager工作原理,继续把目光聚焦在我们本次通讯的流程上。

我们进入/frameworks/native/cmds/servicemanager/binder.c中的binder_looper()看看在这个流程中它有什么用?

void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...
    
    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;
        ...
        //和binder通讯,等待Client链接
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        ...
        //解析Client的数据
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ...
    }
}

可以看到,ServiceManager通过一个无限循环,反复的进行ioctl()和binder_parse()操作。还记得第一步中,在没有消息时,ServiceManager会在Binder内核的binder_thread_read()函数中被休眠。

这里,从ioctl()函数出来后,表明ServiceManager收到了Binder内核传递过来的信息,所以下一步就是要多信息进行处理。

int binder_parse(struct binder_state *bs, struct binder_io *bio,
                 uintptr_t ptr, size_t size, binder_handler func)
{
    int r = 1;
    uintptr_t end = ptr + (uintptr_t) size;
    
    while (ptr < end) {
        uint32_t cmd = *(uint32_t *) ptr;
        ptr += sizeof(uint32_t);
        ...
        switch(cmd) {
            case BR_NOOP:
                break;
                //通知ServiceManager通讯事务完成
            case BR_TRANSACTION_COMPLETE:
                break;
                ...
                //执行事务
            case BR_TRANSACTION: {
                //获取通讯事务数据
                struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
                ...
                if (func) {
                    unsigned rdata[256/4];
                    // 用于保存"Binder驱动反馈的信息"
                    struct binder_io msg;
                    // 用来保存"回复给Binder驱动的信息"
                    struct binder_io reply;
                    int res;
                    // 初始化reply
                    bio_init(&reply, rdata, sizeof(rdata), 4);
                    // 根据txn(Binder驱动反馈的信息)初始化msg
                    bio_init_from_txn(&msg, txn);
                    // 消息处理
                    res = func(bs, txn, &msg, &reply);
                    // 反馈消息给Binder驱动
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
                ptr += sizeof(*txn);
                break;
            }
            case BR_REPLY: {
                ...
                break;
            }
                ...
        }
    }  
    return r;
}

首先关注参数ptr,它是ServiceManager传到内核空间的信使binder_write_read bwr的读取缓冲区read_buffer。在第二步binder_thread_read()中,我们在这个buffer中装了一个命令BR_TRANSACTION和一个事物数据tr。忘了快回过头看看吧。
end变量可以指向这个缓冲区结束位置,而此时的ptr是指向缓冲区的头部。所以能够进入while循环。接着从缓冲区中取出刚刚存入的命令cmd,然后将ptr移动一个cmd的距离。
前面说过Binder驱动传过来的cmd是BR_TRANSACTION类型,所以我们只看相关逻辑。
在BR_TRANSACTION中,首先要做的就是获得从Binder内核读取到的信息。可以看到,将参数ptr转换成了binder_transaction_data指针。接下来初始化两个binder_io结构,msg用来储存从Binder内核读取的信息,replay用来储存待会儿需要反馈给请求端的信息。然后通过bio_init_from_txn(&msg, txn)函数将从Binder内核读取的信息,存入msg中。然后我们看到,这里调用了一个fun()函数,它是一个函数指针,代表着svcmgr_handler()函数。不难看出,它就是ServiceManager用于处理Binder内核消息的函数。

//位于frameworks\native\cmds\servicemanager\service_manager.c
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;
    ...
    
    //测试指令PING_TRANSACTION直接返回
    if (txn->code == PING_TRANSACTION)
        return 0;
    
    ...
}

我们知道,binder_transaction_data装有来自Binder内核的消息。它装有的消息基本就是请求发起进程发送的消息,也就是其发送的binder_transaction_data里的信息。这部分你需要看上面的binder_transaction()和这一篇中的第一步binder_thread_read(),它们中关于binder_transaction_data结构的赋值逻辑需要理清楚。

既然如此,那么我们就回过头看发起请求的进程在binder_transaction_data结构中装了什么信息。我们需要回到IPCThreadState::writeTransactionData()函数中,也就是初始化发送信使binder_transaction_data的地方。在这里,我们可以看到,信使中的code码是参数传进来的。我们沿着这条线往回找,可以发现,就是一开始我们发起这次Binder通讯的地方status_t status = IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0) ,设置了code为IBinder::PING_TRANSACTION。真想大白,code为PING_TRANSACTION类型就什么也不干,直接退出这个函数。这就是为什么说我们发起这次请求只是测试一下ServiceManager是否已经注册的原因。
实际上,如果code为其它情况的话,在这里会进行一些其它的逻辑。比如,添加一个Service或者查找获得一个Service。在后面遇到了再回过头了说。

上一步,service_manager.c中的svcmgr_handler()函数中,对请求端的请求进行了处理。然后函数退出,回到binder.c的binder_parse()继续执行。下一步就是给予请求端处理结果,即这一次ServiceManager要给请求端发送消息了。

//位于frameworks\native\cmds\servicemanager\binder.c
void binder_send_reply(struct binder_state *bs,
                       struct binder_io *reply,
                       binder_uintptr_t buffer_to_free,
                       int status)
{
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;
    //把回复数据放到data中
    data.cmd_free = BC_FREE_BUFFER;
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY;
    data.txn.target.ptr = 0;
    data.txn.cookie= 0;
    data.txn.code = 0;
    if (status) {
       ...
    } else {
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    //发送响应
    binder_write(bs, &data, sizeof(data));
}

上面这段代码不长,它主要干了两个事:

定义并初始化储存回复信息的data结构体。其中,cmd_replay是本次通讯的指令,后面进行什么逻辑,是更具这个值判断的。
调用binder_write()函数,准备和Binder内核通讯,从而将回复信息传递给发送端。

int binder_write(struct binder_state *bs, void *data, size_t len)
{
    struct binder_write_read bwr;
    int res;
    //初始化信使
    bwr.write_size = len;
    bwr.write_consumed = 0;
    bwr.write_buffer = (uintptr_t) data;
    bwr.read_size = 0;
    bwr.read_consumed = 0;
    bwr.read_buffer = 0;
    //通过Binder发送响应
    res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
    ...
    return res;
}

和Binder内核的通讯同样是通过ioctl()函数进行的。这会让代码逻辑回到/drivers/staging/android/binder.c中的binder_ioctl()函数中。

我们回到/drivers/staging/android/binder.c中的binder_ioctl()函数中,在图中找到对应位置哦!

逻辑其实和上一篇读取发送端消息,然后在传输给接收端大致是差不多的。只是中间的一些cmd不同,某些步骤执行的操作有区别罢了。
在binder_ioctl()函数中,同样先获取到发送过来的消息参数,然后由于调用ioctl()的参数是BINDER_WRITE_READ,所以直接进入binder_ioctl_write_read()函数。大家在图中找到对应位置。在这个函数中,由于是发送消息,所以会进入binder_thread_write()函数。

binder_thread_write()函数还是和之前差不多,先读取发送端的消息信息等,然后根据信使binder_write_read的write_buffer中的cmd决定执行什么逻辑。而这个cmd的值你可以回到binder_send_reply()中看看,它是BC_REPLY类型的。那么就简单了,和上一篇发送端逻辑一样,会进入到binder_transaction()函数中。

binder_transaction()函数就是之前说的有些复杂的函数,大家在图中继续找到对应位置啊。通过上一篇的阅读,相信你已经知道了这个函数主要会根据发送端信息(此时为ServiceManager)和接收端(原本的发送端)的信息,构造两个事务分别添加到发送端和接收端进程的事务列表中。同样,一个事务是给发送端通知本次你发送的信息Binder内核已经转发给接收端了,另一个事务自然是将发送端的消息带到接收端中处理。

binder_transaction()函数执行完后,对ServiceManager而言,由于执行的事务是告知ServiceManager本次Transication完成了,消息已经发送出去,即BINDER_WORK_TRANSACTION_COMPLETE命令,所以逻辑同上一篇的基本一致。总之函数一路执行完毕,然后回到/frameworks/native/cmds/servicemanager/binder.c的binder_parse()中。你可以在这个函数中看到:

...
 case BR_TRANSACTION_COMPLETE:
                break;
...

在图中找找对应位置哦。收到BR_TRANSACTION_COMPLETE指令后,直接break。然后binder_parse()函数执行完毕。代码逻辑回到第三步的binder_loop()中,由于有一个for循环,所以会再次执行到

void binder_loop(struct binder_state *bs, binder_handler func)
{
    ...
    
    for (;;) {
       ...
        //和binder通讯,等待Client链接
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        ...
    }
}

这一次和Binder内核ioctl通讯,由于没数据要发,所以会一路进入/drivers/staging/android/binder.c的binder_thread_read()函数中。就在第一步醒来的地方再次进入休眠,等待下一次的唤醒。

//休眠,等待下一次唤醒
ret = wait_event_freezable_exclusive(proc->wait, binder_has_proc_work(proc, thread));

至此,以我们本次通讯为例,ServiceManager的任务算是完成了。

以下分析通讯发起端收到来自接收端的响应
第一步 通讯发起端醒来
开篇我们说过,通讯发起端在/drivers/staging/android/binder.c的binder_thread_read()函数中的``ret = wait_event_freezable(thread->wait, binder_has_thread_work(thread));`未知休眠了,那么这一次被唤醒的自然是我们通讯发起端。

第二步 读取Servicemanager端的响应信息
同上面的逻辑一样,Client端在醒来后会从事务中读取来自S的响应信息。在binder_thread_read()函数中找到下面这段代码。

...
//判断事物t中是否有目标进程的Binder实体
        if (t->buffer->target_node) {
            ...
        } else {
            tr.target.ptr = NULL;
            tr.cookie = NULL;
            cmd = BR_REPLY; //设置命令为BR_REPLY
        }
...
//将cmd和数据写回用户空间的mIn
        if (put_user(cmd, (uint32_t __user *)ptr))
            return -EFAULT;
        ptr += sizeof(uint32_t);
        //刚刚赋值好的事务信息写会用户空间的mIn
        if (copy_to_user(ptr, &tr, sizeof(tr)))
            return -EFAULT;
...

由于在binder_transaction()函数中,由于S的cmd为BC_REPLAY,所以走的是reply的逻辑。这意味着t->buffer->target_node为NULL。所以这一步,会走上面的逻辑。注意,此时cmd被设置成了BR_REPLY。

第三步 Client读取Servicemanager的响应
上一步执行完毕后,C就一路退出,结束和Binder内核的通讯。即会从/frameworks/native/libs/binder/IPCThreadState.cpp的IPCThreadState::talkWithDriver()中退出,然后回到IPCThreadState::waitForResponse()中。

上一步中,我们知道cmd被赋值为BR_REPLY,然后写到了Client中。所以看看IPCThreadState::waitForResponse()中的switch逻辑吧,知道会往那执行了不?

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    ...
    while (1) {
        //真正和Binder驱动交互的是talkWithDriver()函数
        if ((err=talkWithDriver()) < NO_ERROR) break;
        ...
        //取出在内核中写进去的cmd命令
        cmd = mIn.readInt32();
        ...
        
        switch (cmd) {
            ...
            case BR_REPLY:
            {
                binder_transaction_data tr;
                //读取内核中写入的事务数据
                err = mIn.read(&tr, sizeof(tr));
                ...
                if (reply) {
                    //通常这里的reply都不会为空
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                           reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                           tr.data_size,
                           reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                           tr.offsets_size/sizeof(binder_size_t),
                           freeBuffer, this);
                    } else {
                        err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                        ...
                    }
                }
                ...
            }
        }
    }
    ...
    return err;
}

没错,走的是获取响应信息的BR_REPLY逻辑。首先会把内核中传递过来的事务tr读取出来,由于前面tr是有值的,所以这里err = NO_ERROR。接着,reply在上一篇中说过,它是初始化过的,所以不为NULL,进入reply逻辑。tr.flags的值是来自于servicemanager的,具体在上面的binder_send_reply()函数中,有这样一句data.txn.flags = 0。忘记了翻回去找找哦。因此,这里调用了reply的Parcel::ipcSetDataReference()函数,写入响应信息。然后该函数就该返回了。注意此时err仍然为NO_ERROR。

第四步 退出waitForResponse()函数
上一步waitForResponse()函数返回了一个NO_ERROR,然后回到IPCThreadState::transact()函数中。接着,这个函数也没什么逻辑需要执行了,就将err返回。

第五步 一次完整的通讯终于完成啦!
IPCThreadState::transact()函数结束后,我们终于回到了最初的地方(以PING_TRANSACTION为例),那个通讯发起的地方。

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;
    
    ...
    //在handle对应的BpBinder第一次创建时
    //会执行一次虚拟的事务请求,以确保ServiceManager已经注册
    status_t status = IPCThreadState::self()->transact(0, IBinder::PING_TRANSACTION, data, NULL, 0);
    if (status == DEAD_OBJECT)
        //如果ServiceManager没有注册,直接返回
        return NULL;
    ...
}

此时,status为NO_ERROR,即ServiceManager已经注册了。

本文参考:能用【白话文】来分析Binder通讯机制
Binder机制之一次响应的故事

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值