一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Android FrameWork

 quasiceo 2014-09-18

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ì)我提出的這些問題有清楚的也希望分享一下!


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    微拍一区二区三区福利| 国产精品第一香蕉视频| 国产一区二区在线免费| 国产成人精品在线播放| 国产韩国日本精品视频| 国产内射一级一片内射高清| 99热在线播放免费观看| 99少妇偷拍视频在线| 大香伊蕉欧美一区二区三区| 九九热这里只有免费精品| 亚洲国产性生活高潮免费视频| 国产av乱了乱了一区二区三区| 欧美胖熟妇一区二区三区| 亚洲欧美日韩色图七区| 欧美日韩国产黑人一区| 精品日韩视频在线观看| 99久久国产亚洲综合精品| 久热在线视频这里只有精品| 欧美人与动牲交a精品| 色丁香之五月婷婷开心| 日韩精品中文字幕在线视频| 高清欧美大片免费在线观看| 插进她的身体里在线观看骚| 午夜资源在线观看免费高清| 日本午夜免费观看视频| 日本女优一区二区三区免费 | 丝袜诱惑一区二区三区| 国产一区二区三区丝袜不卡| 日本深夜福利视频在线| 麻豆蜜桃星空传媒在线观看| 日韩精品一区二区三区四区| 国产精品一区二区视频| 色婷婷在线精品国自产拍| 欧美日韩视频中文字幕| 日韩成人午夜福利免费视频| 在线懂色一区二区三区精品| 天堂av一区一区一区| 国产亚洲精品一二三区| 99久久免费中文字幕| 91插插插外国一区二区| 国产自拍欧美日韩在线观看|