6.前面5個(gè)段落我主要說明了BinderProxy是如何把數(shù)據(jù)發(fā)送出去的,Ok,那么接下來,我們肯定想要知道服務(wù)端是怎么接收數(shù)據(jù)并傳遞給相應(yīng)的BBinder進(jìn)行處理的,有沒有注意到前面waitForResponse我標(biāo)注為藍(lán)色的代碼,這給我們一個(gè)啟示,也許接收返回?cái)?shù)據(jù)(進(jìn)程作為客戶端)和接收命令(進(jìn)程作為服務(wù)端)處理的是同一個(gè)函數(shù),但這是我的一個(gè)猜測(cè),而實(shí)際上我參閱其它blog和代碼后并非這么回事,waitForResponse只在客戶端發(fā)送完數(shù)據(jù)等待接收數(shù)據(jù)才被調(diào)用的,那么服務(wù)端是怎么接收數(shù)據(jù)的呢?做過socket編程的同仁們可能知道,服務(wù)端為實(shí)現(xiàn)接收數(shù)據(jù)和鏈接,一般會(huì)啟動(dòng)一個(gè)監(jiān)聽線程去監(jiān)聽客戶端發(fā)過來的數(shù)據(jù),同樣android進(jìn)程通信的服務(wù)端也是這么做的,在這里我先給你看一個(gè)Debug線程圖:
這是一個(gè)簡(jiǎn)單的Android應(yīng)用進(jìn)程Debug圖,有沒有看到兩個(gè)Binder Thread線程,每個(gè)應(yīng)用都包含Binder Thread線程,不信你可以試試,它就是負(fù)責(zé)監(jiān)聽來自Binder驅(qū)動(dòng)的消息的,那么這兩個(gè)線程在什么時(shí)候被起來的呢,這又是我的一個(gè)疑問,我也不清楚不同Activity應(yīng)用的Binder Thread是在哪里被起來的,我后面有待研究,不過System_process進(jìn)程我倒是清楚它是如何啟動(dòng)這兩個(gè)線程的,在init1->system_init()
@System_init.cpp函數(shù)最后:
if (proc->supportsProcesses()) {
LOGI("System server: entering thread pool.\n");
ProcessState::self()->startThreadPool();//啟動(dòng)Binder監(jiān)聽線程
IPCThreadState::self()->joinThreadPool();
LOGI("System server: exiting thread pool.\n");
}
IPCThreadState::self()函數(shù)前面我們已經(jīng)講過了,它是線程綁定對(duì)象,ProcessState::self函數(shù)我列出如下
sp<ProcessState> ProcessState::self()
{
if (gProcess != NULL) return gProcess;
AutoMutex _l(gProcessMutex);
if (gProcess == NULL) gProcess = new ProcessState;
return gProcess;
}
顯然ProcessState是單例的,也即每個(gè)進(jìn)程擁有一個(gè)ProcessState對(duì)象,而每個(gè)線程擁有一個(gè)IPCThreadState對(duì)象,關(guān)于ProcessState,IPCThreadState,網(wǎng)上有一篇轉(zhuǎn)高煥堂先生的blog,建議你此時(shí)插讀一下,我不作詳細(xì)說明:
認(rèn)識(shí)Android的ProcessState類別和物件:http://www./Topic.aspx?BoardID=31&TopicID=1897
(圖2:摘自高煥堂先生課件)
ProcessState負(fù)責(zé)打開Binder驅(qū)動(dòng),與Binder驅(qū)動(dòng)進(jìn)行通信,而IPCStateThread負(fù)責(zé)每個(gè)具體線程IPC數(shù)據(jù)讀寫
7.服務(wù)端監(jiān)聽線程的構(gòu)建
服務(wù)端具體監(jiān)聽線程是怎樣構(gòu)建的的了,前面我只說了是通過ProcessState::self()->startThreadPool(); IPCThreadState::self()->joinThreadPool();這兩個(gè)函數(shù)創(chuàng)建的,網(wǎng)上很多blog也只是簡(jiǎn)單說一下,具體是怎樣一個(gè)過程呢?我這里進(jìn)行一下說明:
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
//////////////////////////////////////
//isMain==true
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
int32_t s = android_atomic_add(1, &mThreadPoolSeq);
char buf[32];
sprintf(buf, "Binder Thread #%d", s);
LOGV("Spawning new pooled thread, name=%s\n", buf);
sp<Thread> t = new PoolThread(isMain);
t->run(buf);
}
}
注意線程的創(chuàng)建是在run方法中,run方法并不像java中Thread.run是新線程的工作函數(shù),它仍在當(dāng)前線程中執(zhí)行,PoolThread并沒有覆蓋父類Thread.run方法,因此它執(zhí)行的是Thread.run方法:
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
。。。
//這個(gè)時(shí)候才真正創(chuàng)建一個(gè)新的線程,新線程的工作方法是_threadLoop,它仍是父類Thread的一個(gè)方法
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
。。。
}
////////////////////////////////////////////
//新線程工作方法
int Thread::_threadLoop(void* user)
{
。。。
do {
//調(diào)用虛函數(shù)threadLoop(),該函數(shù)被PoolThread實(shí)現(xiàn)
result = self->threadLoop();
}
。。。
} while(strong != 0);
return 0;
}
////////////////////////////////////////////
//PoolThread成員方法
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);//真正線程工作函數(shù)
return false;
}
通過上面的代碼我們看出,ProcessState::self()->startThreadPool();創(chuàng)建了一個(gè)新的線程,并且新線程的工作函數(shù) IPCThreadState::self()->joinThreadPool(true);緊接著當(dāng)前線程又調(diào)用了IPCThreadState::self()->joinThreadPool(true);我這里是以system_process進(jìn)程為例,那說明system_process至少有兩個(gè)binder線程監(jiān)聽Binder驅(qū)動(dòng)消息,接下來我們仔細(xì)看一下joinThreadPool(true)函數(shù)的實(shí)現(xiàn):
//服務(wù)端線程工作函數(shù)
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);//通知驅(qū)動(dòng)開始消息監(jiān)聽??
androidSetThreadSchedulingGroup(mMyThreadId, ANDROID_TGROUP_DEFAULT);//加入默認(rèn)線程組??
status_t result;
do {
int32_t cmd;
。。。
// now get the next command to be processed, waiting if necessary
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) continue;
cmd = mIn.readInt32();//讀取命令
}
result = executeCommand(cmd);//執(zhí)行命令
}
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);//通知驅(qū)動(dòng)結(jié)束消息監(jiān)聽
talkWithDriver(false);
}
通過while循環(huán)調(diào)用IPCThreadState.mIn讀取cmd并執(zhí)行,這我有一個(gè)疑惑就是多個(gè)線程去透過IPCThreadState.mIn讀取驅(qū)動(dòng)消息會(huì)不會(huì)存在問題?這個(gè)暫且mark一下,以后再分析
到此,我們總算了解服務(wù)端的消息監(jiān)聽機(jī)制,證明并不是如段落6我猜測(cè)的IPCThreadState.waitForResponse去接收消息的,而是IPCThreadState::joinThreadPool中直接透過IPCThreadState.mIn讀取消息的。
8.消息處理IPCThreadState::executeCommand(int32_t cmd)
走到這一步視乎離目標(biāo)已經(jīng)不遠(yuǎn)了,回到我們?cè)瓉淼膯栴},別讓我們身陷代碼堆棧而迷失了方向,我們前面做的這些工作,目的都是為了客戶端的BpBinder對(duì)象能夠調(diào)到服務(wù)端的BBinder對(duì)象,而在BpBinder中有一個(gè)mHandle參數(shù)指定了服務(wù)端的Binder通信地址,因此消息才得以發(fā)送到服務(wù)端,現(xiàn)在我們有一個(gè)問題要解決就是,服務(wù)端可能存在多個(gè)BBinder對(duì)象,我們接收消息后,如何找到對(duì)應(yīng)的BBinder對(duì)象把消息傳給它處理了,我們先看消息處理函數(shù)
executeCommand:
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;//BBinder對(duì)象地址
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch (cmd) {
case BR_ERROR:
...
...
//這是BC_TRANSACTION消息到服務(wù)端對(duì)應(yīng)的cmd(客戶端發(fā)送的是cmd==BC_TRANSACTION,服務(wù)端cmd變成BR_TRANSACTION?待研究)
case BR_TRANSACTION:
{
//構(gòu)造接收消息結(jié)構(gòu)體,與前面客戶端writeTransactionData構(gòu)造的傳輸數(shù)據(jù)包一致的結(jié)構(gòu)體
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));//讀取消息到結(jié)構(gòu)體tr
LOG_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.ptr.buffer是消息體,也就是傳輸參數(shù)Parcel
tr.data_size,
reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
tr.offsets_size/sizeof(size_t), freeBuffer, this);
const pid_t origPid = mCallingPid;
const uid_t origUid = mCallingUid;
mCallingPid = tr.sender_pid;//客戶端進(jìn)程pid,uid(uid代表什么??)
mCallingUid = tr.sender_euid;
。。。
Parcel reply;
if (tr.target.ptr) {//tr.target.ptr值在客戶端writeTransactionData中并未設(shè)置,只是設(shè)置了tr.target.handle = handle;猜測(cè)在Binder驅(qū)動(dòng),根據(jù)handle找到了對(duì)應(yīng)BBinder的地址并填寫到這個(gè)字段了。
sp<BBinder> b((BBinder*)tr.cookie);
const status_t error = b->transact(tr.code, buffer, &reply, 0);//調(diào)用對(duì)應(yīng)的BBinder對(duì)象的transact方法
if (error < NO_ERROR) reply.setError(error);
} else {//tr.target.ptr為空,沒有指定BBinder對(duì)象,調(diào)用the_context_object->transact方法,the_context_object具體是什么對(duì)象?我不能夠搜索到代碼
const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);//猜測(cè)the_context_object應(yīng)該是ApplicationThread對(duì)象,代表本應(yīng)用進(jìn)程上下文,不知道是否正確
if (error < NO_ERROR) reply.setError(error);
}
if ((tr.flags & TF_ONE_WAY) == 0) {//默認(rèn)同步方式,需要發(fā)送返回?cái)?shù)據(jù)
LOG_ONEWAY("Sending reply to %d!", mCallingPid);
sendReply(reply, 0);//發(fā)送返回?cái)?shù)據(jù)
} else {
LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);//ONEWAY方式客戶端并不等待調(diào)用返回,因此不需要發(fā)送返回?cái)?shù)據(jù)
}
mCallingPid = origPid;
mCallingUid = origUid;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
<< tr.target.ptr << ": " << indent << reply << dedent << endl;
}
}
break;
case BR_DEAD_BINDER:
...
...
}
...
return result;
}
盡管還是存在很多疑問,但是大概脈絡(luò)應(yīng)該已經(jīng)清楚了,收到數(shù)據(jù)包binder_transaction_data tr后根據(jù)tr.target.ptr得到BBinder對(duì)象指針,然后調(diào)用該對(duì)象的transact方法。
9.回到j(luò)ava層的Binder對(duì)象
在圖一中,對(duì)c層的IBinder類繼承結(jié)構(gòu)已有一個(gè)清楚的說明,BBinder有兩個(gè)子類,一個(gè)是JavaBBinder,一個(gè)是BnInterface,若Binder存根對(duì)象用C實(shí)現(xiàn)的,那它會(huì)繼承BnInterface,以MediaPlayerService為例,它的繼承結(jié)構(gòu)如下:MediaPlayerService-->BnMediaPlayerService-->BnInterface<IMediaPlayerService>-->BBinder-->IBinder
代碼調(diào)用過程圖如下:
(圖3)
這個(gè)很簡(jiǎn)單,再看怎么調(diào)用到j(luò)ava層的Binder對(duì)象,前面在圖1中已經(jīng)描述了,java Binder對(duì)象對(duì)應(yīng)到C空間的對(duì)象是JavaBBinder對(duì)象,所以,在BBinder::tansact方法中,調(diào)用到得是JavaBBinder.onTransact方法,在深入JavaBBinder.onTransact前我們先了解一下JavaBBinder是一個(gè)什么對(duì)象,它怎么建立與java層Binder對(duì)象聯(lián)系的,下面是JavaBBinder的構(gòu)造函數(shù):
//env:java虛擬機(jī)指針
//object:java層的Binder對(duì)象
JavaBBinder(JNIEnv* env, jobject object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
{
LOGV("Creating JavaBBinder %p\n", this);
android_atomic_inc(&gNumLocalRefs);
incRefsCreated(env);
}
通過JavaBBinder的構(gòu)造函數(shù),我們可以推測(cè),在構(gòu)建java層Binder對(duì)象時(shí)也構(gòu)造了對(duì)應(yīng)的C層的一個(gè)JavaBBinder,JavaBBinder對(duì)象有兩個(gè)成員,
JavaVM* const mVM;
jobject const mObject;
顯然,JavaBBinder其實(shí)就是對(duì)java層Binder對(duì)象的一個(gè)包裝對(duì)象,理解了這個(gè),我們?cè)倏碕avaBBinder.onTransact
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
{
JNIEnv* env = javavm_to_jnienv(mVM);
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, (int32_t)&data, (int32_t)reply, flags);
jthrowable excep = env->ExceptionOccurred();
。。。
return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
}
我用紅色標(biāo)注了關(guān)鍵代碼,可以看到,它通過虛擬機(jī)的CallBooleanMethod反向去調(diào)用了java層的Binder對(duì)象mObject的一個(gè)方法,該方法由函數(shù)指針gBinderOffsets.mExecTransact引用,我們看一下該函數(shù)指針的定義:
gBinderOffsets.mExecTransact
= env->GetMethodID(clazz, "execTransact", "(IIII)Z");
總算找到了execTransact方法,總算浮出水面到了我們熟悉的java層,我就不詳細(xì)解讀代碼了,畫個(gè)調(diào)用圖如下:
(圖4)
到此,Binder通信的內(nèi)部機(jī)制總算介紹完了,也遺留了不少問題,路過的同仁們?nèi)魧?duì)我提出的這些問題有清楚的也希望分享一下!