文章仅仅用于个人的学习记录,基本上内容都是网上各个大神的杰作,此处摘录过来以自己的理解学习方式记录一下。 个人最为认可和推崇的大神文章: http://blog.csdn.net/luoshengyang/article/details/6618363 罗升阳Binder系列文章 http://blog.csdn.net/innost/article/details/47208049 Innost的Binder讲解
https://my.oschina.net/youranhongcha/blog/149575 侯 亮的Binder系列文章.
1、ProcessState
它被设计成单例模式,因此一个进程只会走一次它的构造,这也间接导致了只会打开一次binder设备(某一个server端.) 而当调用ProcessState::self()的时候就会调用.
ProcessState::ProcessState() //构造 : mDriverFD(open_driver())//在初始化列表时打开驱动. , mVMStart(MAP_FAILED) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { if (mDriverFD >= 0) { // mmap the binder, providing a chunk of virtual address space to receive transactions. //把设备文件映射到进程的虚拟地址空间.第一个好处,可以直接读写。 //BINDER_VM_SIZE = ((1*1024*1024) - (4096 *2)) 1M-8K mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { //...... } #else mDriverFD = -1; #endif } //...... }
ProcessState中另一个比较有意思的域是mHandleToObject,在.h文件中Vector<handle_entry>mHandleToObject声明.它是本进程中记 录所有BpBinder的向量表,非常重要.在Binder架构中,应用进程是通过“binder句柄”来找到对应的BpBinder的。从这张向量表中我们可 以看 到,那个句柄值其实对应着这个向量表的下标.
struct handle_entry { IBinder* binder; RefBase::weakref_type* refs; };
其中binder域记录的就是BpBinder对象. 2、IPCThreadState最终和Binder驱动打交道的地方,它是线程单例,存到了线程的本地存储区域. 由于 IPCThreadState的构造函数的声明如下,是在private下面声明的所以其它类不能实例化它,但是可以通过self()方法 来得到它的实例。 private: IPCThreadState(); ~IPCThreadState();
IPCThreadState* IPCThreadState::self() { if (gHaveTLS) {//第一次进来为false restart: const pthread_key_t k = gTLS; //TLS是Thread Local Storage的意思.线程本地存储的意思(C层实现的和java层的ThreadLocal类一样), //有pthread_getspecific,那么肯定有地方调用 pthread_setspecific。 IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k); if (st) return st; return new IPCThreadState; } //...... }
构造:函数如下,需要特别关注的由mProcess私有变量的初始化问题,此变量标记了当前线程输入那个进程,并且通过 ProcessState的self方法拿到这个单例模式的ProcessState的变量,就可以拿到在实例化时候打开binder设备时返回 的文件描述符fd了,其实最终IPCThreadState还是通过这个fd通过ioctl机制来和设备驱动文件通信。
IPCThreadState::IPCThreadState() : mProcess(ProcessState::self()),//很关键!!! mMyThreadId(androidGetTid()), mStrictModePolicy(0), mLastTransactionBinderFlags(0) { pthread_setspecific(gTLS, this);//在构造中这个存入本地存储区.保证每个线程有自己的IPCThreadState. clearCaller(); mIn.setDataCapacity(256); mOut.setDataCapacity(256); }
2.1、 IPCThreadState中的client端发出请求和驱动交互的大体流程: 一般在代理端如BpServiceManager的addservice调用时,本身代理端是没有通信机制的它还是要靠BpBinder来操作, 所以都会获得一个mRemote,这是一个BpBinder对象然后调用它的 transact()方法传入指定的命令 code,更具code驱动会做 出反应。
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) { //当是一个service通过service manager 调用addservice,然后到这里的时候. //这里的mHandle为0,code为ADD_SERVICE_TRANSACTION。ADD_SERVICE_TRANSACTION是上面以参数形式传进来的, //那mHandle的只是由前面实例化BpBinder传入的值决定的,一般在如:BpXXXX : public BpInterface<XXX> //而在实例化BpXXX的时候构造中都会需要传入一个IBinder对象,在跨进程调用的时候这个对象就是此处的BpBinder //传入这个BpBinder的时候由于模板类BpInterface就会去实例化BpRefBase最终实例化这个BpBinder的相关变量. status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); if (status == DEAD_OBJECT) mAlive = 0; return status; } return DEAD_OBJECT; }
可以看出BpBinder最终是调用IPCThreadState去和驱动打交道的。此处显示通过实例化获取 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(); //IPCThreadState::transact函数的参数flags ==0 ,这是因为在BpBinder中默认参数列表传入的0. flags |= TF_ACCEPT_FDS;//TF_ACCEPT_FDS = 0x10 ,binder.h linux中
//......
if (err == NO_ERROR) { //准备好一个struct binder_transaction_data结构体变量,这个是等一下要传输给Binder驱动程序的数据. //这里就是发送数据的地方.把它的handle,code,data封装好然后写入到IPCThreadState的mOut中 err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL); } //...... //如果没有设置TF_ONE_WAY这个置也就是需要回复。 if ((flags & TF_ONE_WAY) == 0) {//0x10&0x01确实会进入. //...... //等待回复,如果reply可以用就直接用,否则自己新建一个. if (reply) { err = waitForResponse(reply); } else { Parcel fakeReply; err = waitForResponse(&fakeReply); } //...... } else { //不需要回复的时候会走到这里. err = waitForResponse(NULL, NULL); } return err; }
可以看到在IPCThreadState的 transact方法中主要有两步,第一步把要传输的数据封装成 binder_transaction_data的结构 体(就是要这么定义,也方便驱动那别解析啊,大家都按照这种来)然后写入到Parcel mOut当中,这个就是当前的IPCThrea d State要往驱动中传入的序列化的数据.第二步就是真正通过ioctl要和驱动去交流的地方在 waitForResponse当中.
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;//代表Binder传输过程中的数据.
//这个结构体的初始化设置.
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */ tr.target.handle = handle; tr.code = code;//注意!!!!这个code会存入到封装的binder_transaction_data结构体当中!!!!!注意和cmd的区别 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(); //data.ipcData();就相当于. //writeInt32(IPCThreadState::self()->getStrictModePolicy() | STRICT_MODE_PENALTY_GATHER); //writeString16("android.os.IServiceManager"); //writeString16("media.player"); //writeStrongBinder(new MediaPlayerService()); tr.data.ptr.buffer = data.ipcData();
//真正要传输的数据保存的地方.
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
//记录一下偏移量.
tr.data.ptr.offsets = data.ipcObjects(); } else if (statusBuffer) { //...... } else { return (mLastError = err); } //Parcel mOut 往驱动发送的数据最终都存入到mOut. mOut.writeInt32(cmd);//cmd为BC_TRANSACTION直接存入到mOut当中,在binder_thread_write方法中读取. mOut.write(&tr, sizeof(tr)); return NO_ERROR; }
注意此处写入的cmd不要和一开始从BpXXXX传入的code弄混了,这个cmd就是和binder设备文件进行ioctl的时候的命令 码,在驱动的实现中又具体的定义.此处的 writeStrongBinder也十分的关键后面再分析.接下来看一下 waitForResponse。
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult) { int32_t cmd; int32_t err; while (1) { //
最后bwr.write_size和bwr.read_size均为0,IPCThreadState::talkWithDriver函数什么也不做,返回到IPCThreadState::waitForResponse函
中
//
在IPCThreadState::waitForResponse函数,又继续从mIn读出一个整数,这个便是BR_TRANSACTION_COMPLETE.
//
进入到Binder驱动程序中的binder_ioctl函数中。由于bwr.write_size为0,bwr.read_size不为0,这次
直接就进入到binder_thread_read //函数中。这时候,
//thread->transaction_stack!=0,thread-
>todo为空,线程通过:
wait_event_interruptible(thread->wait, binder_has_thread_work(thread))
//进入睡眠状态,等待Service Manager来唤醒了。(!!!!反正最终又是要等待Service Manager来唤醒,注意此时Service Manager已经被唤醒)
//主要调用了talkWithDriver函数来与Binder驱动程序进行交互 if ((err=talkWithDriver()) < NO_ERROR) break; //从驱动返回以后,这里开始操作mIn了,看来talkWithDriver中把mOut发出去,然后从driver中读到数据放到mIn中了。 err = mIn.errorCheck();//addservice时候,mIn读出一个整数,这个便是BR_NOOP了,这是一个空操作,什么也不做。 if (err < NO_ERROR) break; if (mIn.dataAvail() == 0) continue; cmd = mIn.readInt32();//取出来驱动放入的命令. //...... 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: //...... return err; }
此时我们主要关注的是往驱动发出的时候的事情,那么此时就是去调用 talkWithDriver.一定要注意那个mProcess的成员变 量mDriverFD,最终是通过,这个fd和binder设备文件交互. binder_write_read这个结构体用来进一步的封装和驱动交互的数据 结构。通过下面可见最终还是通过ioctl来和binder驱动进行交互.Binder驱动收到后根据不同的cmd做出不同的处理.
status_t IPCThreadState::talkWithDriver(bool doReceive) { if (mProcess->mDriverFD <= 0) { return -EBADF; } // binder_write_read是用来与Binder设备交换数据的结构, binder_write_read bwr;//来换传入Binder命令的时候就会用到这个结构体. // 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();//!!!非常重要,看出来把前面的cmd和
binder_transaction_data放入到了buffer
// This is what we'll read. if (doReceive && needRead) { //接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中了。 bwr.read_size = mIn.dataCapacity(); bwr.read_buffer = (uintptr_t)mIn.data(); } else { bwr.read_size = 0; bwr.read_buffer = 0; }
//......
// Return immediately if there is nothing to do. status_t err; do { //...... #if defined(HAVE_ANDROID_OS) //看来不是read/write调用去和Binder设备文件进行通信,而是ioctl方式。 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; } //...... } while (err == -EINTR);//应该是只要有数据就会一直循环的往外发送,通过ioctl的返回值判断的.
//......
if (err >= NO_ERROR) { //到这里从驱动中回来了,回复数据就在bwr中了,bmr接收回复数据的buffer就是mIn提供的 if (bwr.write_consumed > 0) { if (bwr.write_consumed < mOut.dataSize()) mOut.remove(0, bwr.write_consumed); else mOut.setDataSize(0);//从驱动回来以后,首先是把mOut的数据清空.方便下一次操作啊. } if (bwr.read_consumed > 0) { mIn.setDataSize(bwr.read_consumed);//然后设置已经读取的内容的大小. mIn.setDataPosition(0); } //...... return NO_ERROR; } //然后就返回到了waitForResponse当中.我们去看一下. //在addservice流程中到这里,我们发送addService的流程就彻底走完了。 return err; }
此处一定要注意bwr算是又进行了一层的封装,把 binder_transaction_data和cmd等放入mOut当中的数据通过: bwr.write_buffer = (uintptr_t)mOut.data()、bwr.read_buffer = (uintptr_t)mIn.data()等放入到了binder_write_read结构体的对应的buffer缓冲区中。
3、 ProcessState::self()->startThreadPool()和 IPCThreadState::self()->joinThreadPool()两个操作. 3.1、 ProcessState:: startThreadPool方法.
void ProcessState::startThreadPool() { AutoMutex _l(mLock); if (!mThreadPoolStarted) { mThreadPoolStarted = true; spawnPooledThread(true); } }
可以看到就是调用了spawnPooledThread(true).
void ProcessState::spawnPooledThread(bool isMain) { if (mThreadPoolStarted) { String8 name = makeBinderThreadName(); ALOGV("Spawning new pooled thread, name=%s\n", name.string()); //创建线程池,然后run起来,和java的Thread何其像也。 sp<Thread> t = new PoolThread(isMain);//会去实例化父类Thread. t->run(name.string());//调用PoolThread::run,实际调用了父类Thread的run } }
Thread的run函数最终调用子类的threadLoop函数,这里即为PoolThread::threadLoop函数:
virtual bool threadLoop() { //此时mIsMain为true. IPCThreadState::self()->joinThreadPool(mIsMain); return false; }
可以看到此处也是调用 IPCThreadState::self()->joinThreadPool().一般在native层的标准调用: ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool(); 它们的区别是,这里的参数isMain都是等于true,表示是应用程序自己主动创建的Binder线程,而不是Binder驱动程序请求应用程序创 建的.接下来看看 IPCThreadState:: joinThreadPool()的实现.
注意它在. h的声明文件中void joinThreadPool(bool isMain = true) 默认的参数是true.
void IPCThreadState::joinThreadPool(bool isMain) { mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER); set_sched_policy(mMyThreadId, SP_FOREGROUND); status_t result; do {//进入到这个循环中. processPendingDerefs(); // now get the next command to be processed, waiting if necessary result = getAndExecuteCommand();//去里面读取 if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) { ...... } // Let this thread exit the thread pool if it is no longer // needed and it is not the main process thread. if(result == TIMED_OUT && !isMain) { break; } } while (result != -ECONNREFUSED && result != -EBADF); ...... mOut.writeInt32(BC_EXIT_LOOPER); talkWithDriver(false); }
函数最终是在一个无穷循环中,通过调用talkWithDriver函数来和Binder驱动程序进行交互,实际上就是调用 talkWithDriver来等待Client 的请求,然后调用executeCommand来处理请求,而在getAndExecuteCommand 函数中,最终会调 用BBinder::transact来真正处理Client的 请求.
status_t IPCThreadState::getAndExecuteCommand() { status_t result; int32_t cmd; result = talkWithDriver(); if (result >= NO_ERROR) { size_t IN = mIn.dataAvail(); if (IN < sizeof(int32_t)) return result; cmd = mIn.readInt32(); IF_LOG_COMMANDS() { alog << "Processing top-level Command: " << getReturnString(cmd) << endl; } result = executeCommand(cmd); // After executing the command, ensure that the thread is returned to the // foreground cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we // need to take care of that here in userspace. Note that we do make // sure to go in the foreground after executing a transaction, but // there are other callbacks into user code that could have changed // our group so we want to make absolutely sure it is put back. set_sched_policy(mMyThreadId, SP_FOREGROUND); } return result; }
可以看到就是调用到executeCommand(int cmd )
status_t IPCThreadState::executeCommand(int32_t cmd) { BBinder* obj; RefBase::weakref_type* refs; status_t result = NO_ERROR; switch (cmd) { ...... default: printf("*** BAD COMMAND %d received from Binder driver\n", cmd); result = UNKNOWN_ERROR; break; } if (result != NO_ERROR) { mLastError = result; } return result; }
它会走到case为:BR_TRANSACTION当中,我们单独提取出来分析.
case BR_TRANSACTION: //Binder通信 { binder_transaction_data tr; result = mIn.read(&tr, sizeof(tr)); ALOG_ASSERT(result == NO_ERROR, "Not enough command data for brTRANSACTION"); if (result != NO_ERROR) break; Parcel buffer; buffer.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); const pid_t origPid = mCallingPid; const uid_t origUid = mCallingUid; const int32_t origStrictModePolicy = mStrictModePolicy; const int32_t origTransactionBinderFlags = mLastTransactionBinderFlags; mCallingPid = tr.sender_pid; mCallingUid = tr.sender_euid; mLastTransactionBinderFlags = tr.flags; int curPrio = getpriority(PRIO_PROCESS, mMyThreadId); if (gDisableBackgroundScheduling) { if (curPrio > ANDROID_PRIORITY_NORMAL) { // We have inherited a reduced priority from the caller, but do not // want to run in that state in this process. The driver set our // priority already (though not our scheduling class), so bounce // it back to the default before invoking the transaction. setpriority(PRIO_PROCESS, mMyThreadId, ANDROID_PRIORITY_NORMAL); } } else { if (curPrio >= ANDROID_PRIORITY_BACKGROUND) { // We want to use the inherited priority from the caller. // Ensure this thread is in the background scheduling class, // since the driver won't modify scheduling classes for us. // The scheduling group is reset to default by the caller // once this method returns after the transaction is complete. set_sched_policy(mMyThreadId, SP_BACKGROUND); } } //ALOGI(">>>> TRANSACT from pid %d uid %d\n", mCallingPid, mCallingUid); //前面是来了一个命令,解析成BR_TRANSACTION,然后读取后续的信息 Parcel reply; status_t error; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BR_TRANSACTION thr " << (void*)pthread_self() << " / obj " << tr.target.ptr << " / code " << TypeCode(tr.code) << ": " << indent << buffer << dedent << endl << "Data addr = " << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer) << ", offsets addr=" << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl; } if (tr.target.ptr) { sp<BBinder> b((BBinder*)tr.cookie);//看来这个binder_transaction_data.cookie很关键啊!!!!!!!! error = b->transact(tr.code, buffer, &reply, tr.flags); } else { /* the_context_object是IPCThreadState.cpp中定义的一个全局变量, 可通过setTheContextObject函数设置 */ error = the_context_object->transact(tr.code, buffer, &reply, tr.flags); } //ALOGI("<<<< TRANSACT from pid %d restore pid %d uid %d\n", // mCallingPid, origPid, origUid); if ((tr.flags & TF_ONE_WAY) == 0) { LOG_ONEWAY("Sending reply to %d!", mCallingPid); if (error < NO_ERROR) reply.setError(error); sendReply(reply, 0); } else { LOG_ONEWAY("NOT sending reply to %d!", mCallingPid); } mCallingPid = origPid; mCallingUid = origUid; mStrictModePolicy = origStrictModePolicy; mLastTransactionBinderFlags = origTransactionBinderFlags; IF_LOG_TRANSACTIONS() { TextOutput::Bundle _b(alog); alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj " << tr.target.ptr << ": " << indent << reply << dedent << endl; } } break;
接下来再看一下BBinder::transact的实现:
status_t BBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { data.setDataPosition(0); status_t err = NO_ERROR; switch (code) { case PING_TRANSACTION: reply->writeInt32(pingBinder()); break; default: err = onTransact(code, data, reply, flags);//就是调用自己的onTransact函数嘛,谁实例化的就调用谁! break; } if (reply != NULL) { reply->setDataPosition(0); } return err; }
然后会调用到子类的onTransact函数来处理. PCThreadState接收到了Client处的请求后,就会调用BBinder类的transact函数,并传入相关参数,BBinder类的transact函数最终调 用BnMediaPlayerService类的onTransact函数,于是,就开始真正地处理Client的请求 .