Android binder機(jī)制(native服務(wù)篇)

** 1、前言 **

Android系統(tǒng)使用binder機(jī)制進(jìn)行進(jìn)程間通信,為了更好地封裝,使用戶不用關(guān)心底層細(xì)節(jié),binder機(jī)制變得相當(dāng)復(fù)雜。

binder使用c/s架構(gòu),可類比socket通信,有服務(wù)端也有客戶端 ,而binder驅(qū)動(dòng)就相當(dāng)于網(wǎng)絡(luò)。

Paste_Image.png

本文以MediaPlayerService為例,闡述binder機(jī)制。

2、ServiceManager

ServiceManager,顧名思義,服務(wù)的管理者,所有的本地服務(wù)在啟動(dòng)的時(shí)候都會(huì)被保存在ServiceManager中,而用戶可直接訪問ServiceManager,獲取所需要的服務(wù)。

ServiceManager運(yùn)行在一個(gè)獨(dú)立進(jìn)程中,本地服務(wù)在啟動(dòng)時(shí)需要獲取ServiceManager,將自身保存,這也是一個(gè)IPC過程。此時(shí),ServiceManager作為服務(wù)端,而本地服務(wù)作為客戶端。

以MediaPlayerService為例,查看MediaPlayerService是如何與ServiceManager通信,并將自身保存的呢?

查看MediaPlayerService.cpp的instantiate方法:

void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
        String16("media.player"), new MediaPlayerService());
}

查看defaultServiceManager源碼:

sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
    AutoMutex _l(gDefaultServiceManagerLock);
    while (gDefaultServiceManager == NULL) {
        gDefaultServiceManager = interface_cast<IServiceManager>(
            ProcessState::self()->getContextObject(NULL));
        if (gDefaultServiceManager == NULL)
            sleep(1);
    }
}
return gDefaultServiceManager;
}

現(xiàn)在MediaPlayerService向ServiceManager發(fā)出請(qǐng)求,存儲(chǔ)服務(wù),ServiceManager此時(shí)做為Server端,那么defaultServiceManager究竟返回的是什么對(duì)象呢?

3、痛苦的宏定義
繼續(xù)查看ProcessState::self()->getContextObject(NULL)邏輯,ProcessState使用單例模式,確保一個(gè)進(jìn)程中只有一個(gè)ProcessState對(duì)象。

sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
    return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}

ProcessState的構(gòu)造方法中又做了什么呢?

ProcessState::ProcessState()
: mDriverFD(open_driver()) //初始化列表模式,打開binder驅(qū)動(dòng)
, mVMStart(MAP_FAILED)
 。。。
{
if (mDriverFD >= 0) {
    // mmap the binder, providing a chunk of virtual address space to receive transactions.
    mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
}

ProcessState構(gòu)造方法中,打開binder驅(qū)動(dòng),整篇都在講binder,終于提到有個(gè)類與binder驅(qū)動(dòng)交互了。

繼續(xù)查看getContextObject方法。

sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
// 根據(jù) handle值,在Vector 中查找
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
    IBinder* b = e->binder;
    //第一次查找,顯示會(huì)得到空值
    if (b == NULL || !e->refs->attemptIncWeak(this)) {
        。。。
        // 構(gòu)造一個(gè)BpBinder,最終返回它
        b = new BpBinder(handle); 
        e->binder = b;
        if (b) e->refs = b->getWeakRefs();
        result = b;
    } 
    。。。
}
return result;
}

回到前文的defaultServiceManager方法中,將返回值代入,得到

//注意,方法中傳入的handle為0,所以BpBinder參數(shù)為0
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));

interface_cast,初看以為是強(qiáng)制類型轉(zhuǎn)換的方法,以為自己太菜,這方法怎么沒見過一樣,左鍵點(diǎn)擊下查看方法,才發(fā)現(xiàn)別有洞天。

inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}

原來是調(diào)用泛型類中的asInterface的方法,那么IServiceManager的asInterface的具體邏輯是什么呢?查看IServiceManager.h或者cpp文件查看,都找不到asInterface這個(gè)方法。但看到了下面一段聲明:

// IServiceManager.h 中引用的
DECLARE_META_INTERFACE(ServiceManager);

點(diǎn)擊一看,這個(gè)宏定義中正好定義了asInterface 方法。

#define DECLARE_META_INTERFACE(INTERFACE)                               \
static const android::String16 descriptor;                          \
static android::sp<I##INTERFACE> asInterface(                       \
        const android::sp<android::IBinder>& obj);                  \
virtual const android::String16& getInterfaceDescriptor() const;    \
I##INTERFACE();                                                     \
virtual ~I##INTERFACE();                                            \

但這只是方法定義,哪里實(shí)現(xiàn)的呢?已經(jīng)在h文件中看到宏定義了,那么cpp文件中是否會(huì)有另外一定宏定義,來實(shí)現(xiàn)此方法呢? 答案是肯定的,在IServiceManager.cpp中果然看到一段宏定義

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

點(diǎn)擊查看宏定義具體內(nèi)容:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
const android::String16 I##INTERFACE::descriptor(NAME);             \
const android::String16&                                            \
        I##INTERFACE::getInterfaceDescriptor() const {              \
    return I##INTERFACE::descriptor;                                \
}                                                                   \
android::sp<I##INTERFACE> I##INTERFACE::asInterface(                \
        const android::sp<android::IBinder>& obj)                   \
{                                                                   \
    android::sp<I##INTERFACE> intr;                                 \
    if (obj != NULL) {                                              \
        intr = static_cast<I##INTERFACE*>(                          \
            obj->queryLocalInterface(                               \
                    I##INTERFACE::descriptor).get());               \
        if (intr == NULL) {                                         \
            intr = new Bp##INTERFACE(obj);                          \
        }                                                           \
    }                                                               \
    return intr;                                                    \
}                                                                   \
I##INTERFACE::I##INTERFACE() { }                                    \
I##INTERFACE::~I##INTERFACE() { }                                   \

將模板替換,可知asInterface方法代碼為:

android::sp<IServiceManager> IServiceManager::asInterface(                \
        const android::sp<android::IBinder>& obj)                   \
{                                                                   \
    android::sp<IServiceManager> intr;                                 \
    if (obj != NULL) {                                              \
        intr = static_cast<IServiceManager*>(                          \
            obj->queryLocalInterface(                               \
                    IServiceManager::descriptor).get());               \
        if (intr == NULL) {                                         \
            intr = new BpServiceManager(obj);                          \
        }                                                           \
    }                                                               \
    return intr;                                                    \
}  

如果有看過java中的aidl文件,會(huì)發(fā)現(xiàn)這段代碼和aidl被編譯器自動(dòng)處理過后的文件非常相似,如果client端和server端不在同一進(jìn)程,那么必定走的流程是返回 BpServiceManager 。

BpServiceManager 類在哪呢?它定義在IServiceManager.cpp文件中。

一般native服務(wù)的接口定義在 I××Service.h 文件中,Bp××Service一般定義在I××Service.cpp文件當(dāng)中

經(jīng)過一系列的折騰,終于回到MediaPlayerService.cpp的instantiate方法了,代替下就是

void MediaPlayerService::instantiate() {
BpServiceManager->addService(String16("media.player"), new MediaPlayerService());
}

4、和Binder驅(qū)動(dòng)正式通信

查看BpServiceManager的addService方法

virtual status_t addService(const String16& name, const sp<IBinder>& service,
        bool allowIsolated)
{
    Parcel data, reply;
    data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
    data.writeString16(name);
    data.writeStrongBinder(service);
    data.writeInt32(allowIsolated ? 1 : 0);
    status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
    return err == NO_ERROR ? reply.readExceptionCode() : err;
}

感覺這段代碼非常眼熟,和java中的aidl差別不大,主要就是調(diào)用remote()->transact,和Binder驅(qū)動(dòng)通信。問題來了,那remote()方法得到的是什么對(duì)象呢?

remote()方法返回的是mRemote對(duì)象,回溯上文所講的asInterface方法,構(gòu)造BpServiceManager對(duì)象,傳入了一個(gè)BpBinder,查看BpServiceManager的構(gòu)造函數(shù),它最終引用父類BpRefBase的構(gòu)造函數(shù)。

BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(NULL), mState(0)
{
   。。。。
}

于是得知addService方法中,其實(shí)是調(diào)用BpBinder的transact方法。

Paste_Image.png

根據(jù)在java中使用aidl的經(jīng)驗(yàn),調(diào)用transact方法后,最終肯定會(huì)調(diào)用到onTransact,最終調(diào)用到Server端的方法。

BpBinder的transact之后的調(diào)用流程如上,尤其關(guān)注IPCThreadState類。根據(jù)上圖,IPCThreadState與Binder驅(qū)動(dòng)通信,分別調(diào)用三個(gè)方法

  • writeTransactionData,向Binder驅(qū)動(dòng)寫數(shù)據(jù)
  • waitForResponse, 等待Binder驅(qū)動(dòng)返回指令
  • executeCommand,執(zhí)行Binder驅(qū)動(dòng)的指令

目前和Binder驅(qū)動(dòng)相關(guān)的代碼已經(jīng)有兩個(gè)類了,一個(gè)是ProcessState,另一個(gè)是IPCThreadState,他們的關(guān)系如何,待會(huì)再說。

已經(jīng)調(diào)用了onTransact方法,按理說,應(yīng)該要調(diào)用Server端的方法了,可ServiceManager的server端代碼在哪里呢?

ServiceManager是一個(gè)特殊的服務(wù),因?yàn)樗欠?wù)的管理者,它在其它服務(wù)啟動(dòng)之前啟動(dòng),它的server端代碼在Service_manager.c類中,查看它的main方法。

int main(int argc, char **argv)
{
struct binder_state *bs;
//打開Binder驅(qū)動(dòng)
bs = binder_open(128*1024);
//將自己設(shè)定為服務(wù)的管理者,管理者對(duì)象,整個(gè)android系統(tǒng)只有一個(gè)
if (binder_become_context_manager(bs)) {
    ALOGE("cannot become context manager (%s)\n", strerror(errno));
    return -1;
}
//開啟循環(huán),從binder中讀取命令,執(zhí)行命令
binder_loop(bs, svcmgr_handler);
}

再次回到onTransact方法,現(xiàn)在server端代碼找到了,client端調(diào)用了addService,那么server端響應(yīng)了什么操作呢?

Paste_Image.png

到目前為止,針對(duì)ServiceManager,從client端發(fā)起請(qǐng)求,到服務(wù)端響應(yīng)請(qǐng)求的整個(gè)流程已經(jīng)講完了。

5、MediaPlayerService

根據(jù)ServiceManager的分析經(jīng)驗(yàn),一個(gè)本地服務(wù)至少涉及到以下幾個(gè)類

  • I××Service.h,定義接口,引用宏定義等,從后文可知,它還會(huì)定義BN××Service類
  • I××Service.cpp,定義Bp××Service類,聲明實(shí)現(xiàn)宏定義,從后文可知,它還會(huì)重寫B(tài)N××Service類的onTransact方法
  • Service_manager.c,類似的看似不相關(guān)文件,打開binder驅(qū)動(dòng),初始化,循環(huán)讀取binder驅(qū)動(dòng)消息等
  • ××Service.cpp,I××Service.h中接口的具體實(shí)現(xiàn)者,ServiceManager中server端的具體邏輯實(shí)現(xiàn)在Service_manager.c中,但一般來說,會(huì)有這樣的一個(gè)類,實(shí)現(xiàn)具體邏輯

MediaPlayerService服務(wù)的初始化在Main_mediaserver.cpp中,對(duì)應(yīng)著ServiceManager系統(tǒng)的Service_manager.c,負(fù)責(zé)初始化,打開binder驅(qū)動(dòng),建議消息循環(huán)等等

int main(int argc __unused, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
MediaPlayerService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}

然道先前的推測(cè)不對(duì)?main方法中并沒有直接打開binder,也沒有建立消息循環(huán)。聯(lián)想到前文中的內(nèi)容,與Binder驅(qū)動(dòng)打交道的主要有兩個(gè)類,一是ProcessState,另一個(gè)就是IPCThreadState。

在ProcessState的構(gòu)造方法中,已經(jīng)打開了binder驅(qū)動(dòng)。

從代碼上看 ProcessState::self()->startThreadPool(),好像是啟動(dòng)線程。


Paste_Image.png

查看IPCThreadState的joinThreadPool方法

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();
        // 從binder驅(qū)動(dòng)中取出指令并執(zhí)行
        result = getAndExecuteCommand();
    } while (result != -ECONNREFUSED && result != -EBADF);
    
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

此方法正好是建立消息死循環(huán),與binder驅(qū)動(dòng)溝通,取指令,執(zhí)行指令等等。

但為什么此方法被調(diào)用兩次呢?ProcessState的startThreadPool方法調(diào)用一次,而main方法最后又調(diào)用了一次,在工作線程中調(diào)用了,在主線程也調(diào)用了。是否可去掉其中之一,筆者不得而知。

IPCThreadState::self(),此方法又做了哪些工作呢?

IPCThreadState* IPCThreadState::self()
{
    if (gHaveTLS) {
restart:
        const pthread_key_t k = gTLS;
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadState;
    }
    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {
        int key_create_value = pthread_key_create(&gTLS, threadDestructor);
        if (key_create_value != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true;
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;
}

TLS,線程局部存儲(chǔ),變量與線程相關(guān),每個(gè)線程私有,不必考慮加鎖問題,類似于java中的ThreadLocal類

由此可見,IPCThreadState,它是每個(gè)線程所獨(dú)有的對(duì)象。
ProcessState是進(jìn)程唯一的對(duì)象,這是兩個(gè)非常有意思的單例。

這兩個(gè)類都有與Binder驅(qū)動(dòng)通信的邏輯,實(shí)質(zhì)上是,IPCThreadState的構(gòu)造方法中傳入了ProcessState對(duì)象,IPCThreadState利用ProcessState與binder驅(qū)動(dòng)通信

6、MediaPlayerService相關(guān)文件

IMediaPlayerService.h中定義了server端應(yīng)該實(shí)現(xiàn)的接口,也定義了BnMediaPlayerService類

和前文中的IServiceManager.h一樣

IMediaPlayerService.cpp中定義了BpMediaPlayerService類,也重寫了BnMediaPlayerService的onTransact方法

IMediaPlayerService.h中定義的方法,在MediaPlayerService.cpp中具體實(shí)現(xiàn)。

7、總結(jié)

MediaPlayerService的client端與server端通信,和ServiceManager模塊中類似,就不再復(fù)述。

此時(shí)再結(jié)合前言中的圖片,如果每個(gè)類都做到心中有數(shù)了,那native服務(wù)的binder機(jī)制就基本了解了。

引用材料:
http://www.cnblogs.com/innost/archive/2011/01/09/1931456.html
http://blog.csdn.net/victorfreedom/article/details/43648309
http://blog.csdn.net/ykdsea/article/details/39271133

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評(píng)論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評(píng)論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評(píng)論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評(píng)論 3 392
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容