Android源码分析——从AIDL了解Binder机制

1,298 阅读9分钟

Android源码分析——从AIDL了解Binder机制

以AIDL为入口,探究Binder机制的原理

从AIDL了解Binder

前面简单学习了一下AIDL的用法,接下来就从AIDL入手,探究一下Binder机制。 在学习的过程中,看了以下几篇文章,觉得很有价值:
彻底理解Android Binder通信架构
Binder学习指南
Android Bander设计与实现 - 设计篇

背景知识

首先要知道的是,在Linux系统中,存在很多进程,不同进程之间,数据是不会共享的,他们各自有自己的空间。因此两个进程之间要想交换数据,需要一种机制来做一条数据通路。

还有一点,在Linux系统中,存在内核空间和用户空间两个概念。Linux内核是需要高度安全机制保护起来的,而我们的应用程序则只能运行在开放的用户空间中。如果应用程序需要访问内核空间,需要通过系统调用来实现。

因此,要想实现进程间的通信,我们可以通过在内核空间做一个“枢纽”,不同的进程虽然互相没法访问各自的内存,但是他们都可以用过系统调用来访问我们创建的“枢纽”。Binder机制就是这样的一个“枢纽系统”。

既然Android系统基于Linux系统,那么为什么要自创一套Bidner机制,而不用Linux现成的呢?在知乎上有篇回答很好:为什么Android系统要采用Binder机制做IPC?

Binder通信模型

首先在内核中,存在一个作为枢纽的东西,叫做Binder Driver(Binder驱动)。在Binder机制中,每一个进程最终都是需要在这里完成数据的交接。

其次,还有一个作为核心服务的东西叫做ServiceManager,与Binder Driver不同的是,他处于用户空间。

这两者,构成了Binder机制的核心。

举个例子,现在又两个进程A和B,A要访问B中的一个对象obj的方法f(),这就是跨进程通信了。那么在这之前,进程B会将自己注册在ServiceManager中,也就是说在这里存在一个表,进程B首先会把自己的信息作为一条数据插入在表中。之后,进程A要访问进程B,只需要访问这个ServiceManager,在这里查找B的先关信息,然后他就可以得到这个对象obj,之后就可以直接调用方法f()。

在这个流程里面,实际上并没有真的获取到对象obj,只是获取了一个obj的代理对象。实际对象还是在进程B中。调用f()时,传入的参数只会交给这个代理对象,然后代理对象再负责把数据交给真实对象。而在这整个流程之中,A和B还有ServiceManager都是进程,他们之间的数据交换都是要直接交给Binder驱动的。说起来有点乱,画个图就看出来了:

图中,虚线表示两者之间不是直接交互,因为这三者之间的交互实际上都是通过实线做的。

从AIDL到Binder

AIDL说白了其实就是帮我实现了一个可以用作Binder通信的类,抛开AIDL,我们自己也可以写一个差不多的,也可以用。通过AIDl自动生成的类,定义了一个内部类,并让内部类继承了Binder类。所以,我们只需继承Binder,也可以做简单的IPC了。

从Client开始

从MyAidlClient开始,探寻一下Binder通信的流程。

首先,如图所示

通过已经获得的IBinder对象,这里调用asInterface()方法,返回了一个IMyAidlInterface类的对象,调用他的add()方法。那就从这里开始:

IMyAidlInterface.java:

/**
         * Cast an IBinder object into an com.levent_j.myaidlserver.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.levent_j.myaidlserver.IMyAidlInterface asInterface(android.os.IBinder obj) {
            //非空判断
            if ((obj == null)) {
                return null;
            }
            //查找本地是否存在 如果存在,则直接可以使用,就不需要跨进程通信了
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.levent_j.myaidlserver.IMyAidlInterface))) {
                return ((com.levent_j.myaidlserver.IMyAidlInterface) iin);
            }
            //没有找到,那么就只能跨进程通信了
            //这里通过IBinder对象创建了一个Proxy对象并返回
            //从名字就可以看得出,返回了一个代理对象
            return new com.levent_j.myaidlserver.IMyAidlInterface.Stub.Proxy(obj);
        }

再来

//首先要知道,这个类实现了那个接口
private static class Proxy implements com.levent_j.myaidlserver.IMyAidlInterface {
            //持有的一个IBinder对象的引用
            private android.os.IBinder mRemote;
            //创建对象的时候,只是让代理对象保持了对IBinder对象的引用
            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
            //返回保存的那个引用
            @Override
            public android.os.IBinder asBinder() {
                return mRemote;
            }
            //…………
        
        }

调用asInterface()方法到这里就结束了,可以看到实际上返回来一个代理对象Proxy,那么之后调用add()方法也就是调用了代理对象的add()方法,也就是Proxy类的add()方法:


@Override
            public int add(int arg1, int agr2) throws android.os.RemoteException {
                //创建两个Parcel对象
                //obtain()方法意味着这儿有个Parcel对象的缓存池,避免浪费
                //Parcel对象就是支持跨进程对象的数据结构
                //这个_data用来存放调用的方法的请求参数
                android.os.Parcel _data = android.os.Parcel.obtain();
                //_reply用来存放返回结果
                android.os.Parcel _reply = android.os.Parcel.obtain();
                int _result;
                try {
                    //先向_data中写入数据
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //两个arge刚好就是我们传入的参数
                    _data.writeInt(arg1);
                    _data.writeInt(agr2);
                    //重点来了,这里调用了IBinder对象的transact()方法
                    mRemote.transact(Stub.TRANSACTION_add, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readInt();
                } finally {
                    //最后释放掉
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

这个IBinder类是个接口,而在这获取的对象实际上是Binder.java中的内部类BinderProxy类的对象(什么?Proxy?对没错,这里又是一个代理)。那么获取到这个BinderProxy对象之后,如上所示调用了他的transcat()方法,将参数传入,之后数据传到Server那里,经过实际对象的add()之后会取得返回值。所以这里就是Binder的起点了:

//参数code为前面的Stub.TRANSACTION_add,作用是做一个标识,后面会用到
//两个Parcel对象,作为数据
//最后flags为0
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        //先检查一下两个Parcel
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");

        if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) {
            // For now, avoid spamming the log by disabling after we've logged
            // about this interface at least once
            mWarnOnBlocking = false;
            Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY",
                    new Throwable());
        }

        final boolean tracingEnabled = Binder.isTracingEnabled();
        if (tracingEnabled) {
            final Throwable tr = new Throwable();
            Binder.getTransactionTracker().addTrace(tr);
            StackTraceElement stackTraceElement = tr.getStackTrace()[1];
            Trace.traceBegin(Trace.TRACE_TAG_ALWAYS,
                    stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName());
        }
        try {
        //最后是调用了transactNative()方法,也就是到了Native层
            return transactNative(code, data, reply, flags);
        } finally {
            if (tracingEnabled) {
                Trace.traceEnd(Trace.TRACE_TAG_ALWAYS);
            }
        }
    }

看这个方法的定义:


public native boolean transactNative(int code, Parcel data, Parcel reply,
            int flags) throws RemoteException;
            

从这里开始,就进入了native层:

在android_util_Binder.cpp中:

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    if (dataObj == NULL) {
        jniThrowNullPointerException(env, NULL);
        return JNI_FALSE;
    }
    //将Java的Parcel转换为C++的Parcel
    Parcel* data = parcelForJavaObject(env, dataObj);
    if (data == NULL) {
        return JNI_FALSE;
    }
    Parcel* reply = parcelForJavaObject(env, replyObj);
    if (reply == NULL && replyObj != NULL) {
        return JNI_FALSE;
    }
    //此时target指向了BpBinder
    //这是开机时Zygote调用AndroidRuntime::startReg方法来完成jni方法的注册
    //其中register_android_os_Binder()过程就有一个初始并注册BinderProxy的操作
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);
    if (target == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException", "Binder has been finalized!");
        return JNI_FALSE;
    }

    ALOGV("Java code calling transact on %p in Java object %p with code %" PRId32 "\n",
            target, obj, code);


    bool time_binder_calls;
    int64_t start_millis;
    if (kEnableBinderSample) {
        // Only log the binder call duration for things on the Java-level main thread.
        // But if we don't
        time_binder_calls = should_time_binder_calls();

        if (time_binder_calls) {
            start_millis = uptimeMillis();
        }
    }

    //这里就是BpBinder的transact()
    //printf("Transact from Java code to %p sending: ", target); data->print();
    status_t err = target->transact(code, *data, reply, flags);
    //if (reply) printf("Transact from Java code to %p received: ", target); reply->print();

    if (kEnableBinderSample) {
        if (time_binder_calls) {
            conditionally_log_binder_call(start_millis, target, code);
        }
    }

    if (err == NO_ERROR) {
        return JNI_TRUE;
    } else if (err == UNKNOWN_TRANSACTION) {
        return JNI_FALSE;
    }

    signalExceptionForError(env, obj, err, true /*canThrowRemoteException*/, data->dataSize());
    return JNI_FALSE;
}

然后是BpBinder.cpp中的transact()方法:

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        //IPCThreadState采用单例模式
        //返回了一个status
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

到了IPCThreadState.cpp的transact()方法:

tatus_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();

    flags |= TF_ACCEPT_FDS;

    IF_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }

    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 (err != NO_ERROR) {
        if (reply) reply->setError(err);
        return (mLastError = err);
    }
    
    //根据是否是ONE WAY方式而分别给waitForResponse()传了不同的参数
    if ((flags & TF_ONE_WAY) == 0) {
        #if 0
        if (code == 4) { // relayout
            ALOGI(">>>>>> CALLING transaction 4");
        } else {
            ALOGI(">>>>>> CALLING transaction %d", code);
        }
        #endif
        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;
}

这里的write方法显然是写入数据

//写入数据 
//此时cmd:BC_TRANSACTION
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数据结构
    binder_transaction_data tr;

    tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
    tr.target.handle = handle;//handle指向AMS
    tr.code = code;
    tr.flags = binderFlags;
    tr.cookie = 0;
    tr.sender_pid = 0;
    tr.sender_euid = 0;

    const status_t err = data.errorCheck();
    if (err == NO_ERROR) {//数据没有错误,则封装数据
        tr.data_size = data.ipcDataSize();
        tr.data.ptr.buffer = data.ipcData();
        tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
        tr.data.ptr.offsets = data.ipcObjects();
    } else if (statusBuffer) {
        tr.flags |= TF_STATUS_CODE;
        *statusBuffer = err;
        tr.data_size = sizeof(status_t);
        tr.data.ptr.buffer = reinterpret_cast<uintptr_t>(statusBuffer);
        tr.offsets_size = 0;
        tr.data.ptr.offsets = 0;
    } else {
        return (mLastError = err);
    }
    //给mOut写数据
    mOut.writeInt32(cmd);
    mOut.write(&tr, sizeof(tr));

    return NO_ERROR;
}

可以看出,mOut用来将数据写入 那么在将数据写入之后,来到了这个waitForResponse()方法,等待应答

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
    //一个死循环,一直等待返回数据
    while (1) {
        //调用taklWithDriver()方法,返回一个错误码
        //如果有error 则break
        if ((err=talkWithDriver()) < NO_ERROR) break;
        err = mIn.errorCheck();
        if (err < NO_ERROR) break;
        //没有可用数据,继续循环
        if (mIn.dataAvail() == 0) continue;
        //从mIn读数据
        cmd = (uint32_t)mIn.readInt32();

        IF_LOG_COMMANDS() {
            alog << "Processing waitForResponse Command: "
                << getReturnString(cmd) << endl;
        }
        //通过cmd
        switch (cmd) {
            //本次通讯结束
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;
            break;

        case BR_DEAD_REPLY:
            err = DEAD_OBJECT;
            goto finish;

        case BR_FAILED_REPLY:
            err = FAILED_TRANSACTION;
            goto finish;

        case BR_ACQUIRE_RESULT:
            {
                ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;

        case BR_REPLY:
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;

                if (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);
                        freeBuffer(NULL,
                            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), this);
                    }
                } else {
                    freeBuffer(NULL,
                        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), this);
                    continue;
                }
            }
            goto finish;

        default:
            err = executeCommand(cmd);
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }

    return err;
}

还有talkWithDriver()方法:

//交给Driver处理 此时mOut已经有了数据,mIn还没有,这里来处理数据
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {
        return -EBADF;
    }

    binder_write_read bwr;

    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    // We don't want to write anything if we are still reading
    // from data left in the input buffer and the caller
    // has requested to read the next data.
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }

    IF_LOG_COMMANDS() {
        TextOutput::Bundle _b(alog);
        if (outAvail != 0) {
            alog << "Sending commands to driver: " << indent;
            const void* cmds = (const void*)bwr.write_buffer;
            const void* end = ((const uint8_t*)cmds)+bwr.write_size;
            alog << HexDump(cmds, bwr.write_size) << endl;
            while (cmds < end) cmds = printCommand(alog, cmds);
            alog << dedent;
        }
        alog << "Size of receive buffer: " << bwr.read_size
            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
    }
    //输入和输出数据都为空则直接返回
    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(__ANDROID__)
        //ioctl()执行到Binder Driver中 这里才是真正与Driver通信了
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
        IF_LOG_COMMANDS() {
            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);

    IF_LOG_COMMANDS() {
        alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
            << bwr.write_consumed << " (of " << mOut.dataSize()
                        << "), read consumed: " << bwr.read_consumed << endl;
    }

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        IF_LOG_COMMANDS() {
            TextOutput::Bundle _b(alog);
            alog << "Remaining data size: " << mOut.dataSize() << endl;
            alog << "Received commands from driver: " << indent;
            const void* cmds = mIn.data();
            const void* end = mIn.data() + mIn.dataSize();
            alog << HexDump(cmds, mIn.dataSize()) << endl;
            while (cmds < end) cmds = printReturnCommand(alog, cmds);
            alog << dedent;
        }
        return NO_ERROR;
    }

    return err;
}

所以talkWithDriver()方法是直接去和Binder驱动通信了,其核心是ioctl()方法。

在通信结束之后,回到最初的起点,等待得到返回值(如果有的话),最后从mIn拿到返回的数据。

Server端做了什么

现在已经知道了,数据通过Binder代理,现在已经到了Server端,主要处理过程在内部类Stub中的onTransact()方法内:

@Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                //正是这个方法标识,要调用add()方法
                case TRANSACTION_add: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    int _arg1;
                    _arg1 = data.readInt();
                    //这里调用add()
                    int _result = this.add(_arg0, _arg1);
                    reply.writeNoException();
                    reply.writeInt(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

曾记否,在Server端重写了add()方法,对没错,这里就是调用了那个add()方法

总结

总体上来说,Binder的整个流程就是:

  1. Client
  2. 创建binder_transaction_data
  3. 填code
  4. 参数填入data.buffer
  5. 填入target.handle(Client端的引用)
  6. BC_TRANSACTION发送给Binder驱动
  7. 查找目标,填写target.ptr(Server端的实体)
  8. 到接受线程
  9. 调用onTransact()方法
  10. Server

我们说,Bidner相较于其他IPC机制的一个优势就在于只存在一次拷贝。那么这是怎么一回事呢? 通过mmap()映射了一片缓存池,数据拷贝时,binder_transaction_data是可以分为很多部分,但是其中只有一个叫做buffer的部分是大小不可预料的,其他的部分其实大小是限定的。因此除了buffer之外的其他部分由接收方自己提供,而buffer的存储区由缓存池提供,这样就完成了数据的“一次拷贝”,给人的感觉就是完整的数据直接从Client端拷贝到了Server端,实际上还是借助了内核。