在 Zygote啟動過程 一文中我們說道,,Zygote一生中最重要的一件事就是生下了 System Server 這個大兒子,,System Server 擔負著提供系統(tǒng) Service的重任,在深入了解這些Service 之前,,我們首先要了解 什么是Service,?它的工作原理是什么?
1. Service是什么,?簡單來說,,Service就是提供服務(wù)的代碼,這些代碼最終體現(xiàn)為一個個的接口函數(shù),,所以,,Service就是實現(xiàn)一組函數(shù)的對象,,通常也稱為組件,。Android 的Service 有以下一些特點:
要了解Service,,我們得先從 Binder 入手。 2. Binder先給一張Binder相關(guān)的類圖一瞰Binder全貌,,從上面的類圖(點擊看大圖)跟Binder大致有這么幾部分: Native 實現(xiàn): IBinder, BBinder, BpBinder, IPCThread, ProcessState, IInterface, etc Java 實現(xiàn): IBinder, Binder, BinderProxy, Stub, Proxy. Binder Driver: binder_proc, binder_thread, binder_node, etc. 我們將分別對這三部分進行詳細的分析,,首先從中間的Native實現(xiàn)開始。 通常來說,,接口是分析代碼的入口,,Android中'I' 打頭的類統(tǒng)統(tǒng)是接口類(C++里就是抽象類), 自然,分析Binder就得先從IBinder下手,。先看看他的定義,。
class IBinder : public virtual RefBase { public: ... virtual sp<IInterface> queryLocalInterface(const String16& descriptor); //返回一個IInterface對象 ... virtual const String16& getInterfaceDescriptor() const = 0; virtual bool isBinderAlive() const = 0; virtual status_t pingBinder() = 0; virtual status_t dump(int fd, const Vector<String16>& args) = 0; virtual status_t transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) = 0; virtual status_t linkToDeath(const sp<DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0) = 0; virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient, void* cookie = NULL, uint32_t flags = 0, wp<DeathRecipient>* outRecipient = NULL) = 0; ... virtual BBinder* localBinder(); //返回一個BBinder對象 virtual BpBinder* remoteBinder(); //返回一個BpBinder對象 }; 有接口必然有實現(xiàn),從圖中可以看出,,BBinder和BpBinder都是IBinder的實現(xiàn)類,,它們干啥用的,有啥區(qū)別,?有興趣同學可以去分別去讀讀他們的代碼,,分別在
這里我們簡單總結(jié)一下他們的區(qū)別:
看出來了吧,,它們的差異在于它們是通信兩端的不同實現(xiàn),,BBinder是服務(wù)端,而BpBinder是客戶端,,為什么這么說,?
所以結(jié)論是,,BBinder代表著服務(wù)端,,而BpBinder則是它在客戶端的代理,客戶程序通過BpBinder的transact()發(fā)起請求,,而服務(wù)器端的BBinder在onTranscat()里響應請求,,并將結(jié)果返回。 可是交易肯定有目標的吧,,回到航空公司和機票代理的例子,,如果要訂去某個地方的機票,我們怎么也得先查詢一下都有那些航班,,然后才能告訴機票代理訂具體的航班號吧,。這里的查詢和預訂可以看成服務(wù)的接口函數(shù),而航班號就是我們傳遞給機票代理的參數(shù),??蛻舫绦蛲ㄟ^queryLocalInterface() 可以知道航空公司都提供哪些服務(wù)。 可是奇怪的是BBinder和BpBinder都沒有實現(xiàn)這個接口啊,,那肯定另有他人實現(xiàn)這個類了,,這個人就是IInterface.h, 看看代碼 template<typename INTERFACE> inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface( const String16& _descriptor) { if (_descriptor == INTERFACE::descriptor) return this; return NULL; } template<typename INTERFACE> class BnInterface : public INTERFACE, public BBinder { public: virtual sp<IInterface> queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: virtual IBinder* onAsBinder(); };
是一個模板類,,繼承了BBinder, 還有模板 INTERFACE,。我們剛才已經(jīng)看過,BBinder沒有實現(xiàn)queryLocalInterface(), 而BnInterface 返回自己,,可以他并沒有繼承IInterface, 怎么可以強制轉(zhuǎn)換呢,,唯一的解釋就是 INTERFACE模板必須繼承和實現(xiàn)IInterface. class IInterface : public virtual RefBase { public: IInterface(); sp<IBinder> asBinder(); sp<const IBinder> asBinder() const; protected: virtual ~IInterface(); virtual IBinder* onAsBinder() = 0; };
這也太簡單了吧,只是定義了 從Interface 到 IBinder的轉(zhuǎn)換接口 asBinder, 而剛才我們研究的queryLocalInterface() 正好反過來,,說明IBinder 和 IInterface 之間是可以互轉(zhuǎn)的,,一個人怎么可以變成另外一個人呢?唯一的解釋就是這個人有雙重性格,,要么他同時繼承 IInterface 和 IBinder, 要么他體內(nèi)有這兩個對象同時存在,,不賣關(guān)子了,在服務(wù)端,,這個雙重性格的人就是BnXXX,, XXX 代表某個具體的服務(wù),,我們以圖中的BnMediaPlayer為例,看看他的定義 class BnMediaPlayer: public BnInterface<IMediaPlayer> { public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; class IMediaPlayer: public IInterface { public: DECLARE_META_INTERFACE(MediaPlayer); ... }
這下本性都露出來了,,IBinder 和 IInterface 的影子都露出來了,,讓我們用圖梳理一下 (箭頭代表繼承關(guān)系)
歸納一下,
為什么搞得那么復雜,?Google 是希望通過這些封裝盡可能減少開發(fā)者的工作量,,開發(fā)一個native的service 開發(fā)者只需要做這么幾件事(上圖中深色部分):
那客戶端呢? 我們的目標是找到一個類,,它必須同時擁有IBinder 和 IIterface的特性, 先看看BpBinder 吧
class BpBinder : public IBinder
跟IInterface 沒有關(guān)系,,那一定是別人,看看BpInterface 吧,, template<typename INTERFACE> class BpInterface : public INTERFACE, public BpRefBase { public: BpInterface(const sp<IBinder>& remote); protected: virtual IBinder* onAsBinder(); };
我們剛才已經(jīng)知道了,,INTERFACE 是 IMediaPlayer, 它繼承了IInterface, IInterface 的對象找到了, 但跟IBinder 沒關(guān)系,?只剩下BpRefBase 了,, class BpRefBase : public virtual RefBase { protected: ... inline IBinder* remote() { return mRemote; } ... private: ... IBinder* const mRemote; RefBase::weakref_type* mRefs; volatile int32_t mState; };
有了,BpRefBase 里有IBinder 成員變量,,看來在客戶端,,沒有一個類同時繼承IBinder 和 IInterface, 但是有一個類繼承了其一,,但包含了另外一個,,這種在設(shè)計模式里成為組合(Composition). 還是不太明白?還是用圖解釋吧,,
看明白了,?從BpInterface開始,通過BpRefBase 我們可以找到IBinder, 這個轉(zhuǎn)換就在 asBinder() 的實現(xiàn)里,,看看代碼 sp<IBinder> IInterface::asBinder(){ return this ? onAsBinder() : NULL; } sp<const IBinder> IInterface::asBinder() const{ return this ? const_cast<IInterface*>(this)->onAsBinder() : NULL; } template<typename INTERFACE> inline IBinder* BpInterface<INTERFACE>::onAsBinder() { return remote(); } template<typename INTERFACE> IBinder* BnInterface<INTERFACE>::onAsBinder() { return this; } 這里印證我們上面兩張圖的正確性,,onAsBinder是轉(zhuǎn)換的發(fā)生的地方,服務(wù)端(BnInterface)的實現(xiàn)直接返回了自己,,因為它繼承了兩者,,而客戶端(BpInterface)則需要通過remote()(返回mRemote 成員變量)獲取,,因為他自己本身不是IBinder, 那個BpRefbase的mRemote是如何被賦值的?看看以下代碼 //frameworks/native/libs/binder/binder.cpp BpRefBase::BpRefBase(const sp<IBinder>& o) : mRemote(o.get()), mRefs(NULL), mState(0) { ... }
//frameworks/native/include/binder/iinterface.h template<typename INTERFACE> inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote) : BpRefBase(remote) { }
//frameworks/av/media/libmedia/IMediaPlayer.cpp
原來是從子類一級一級注入的,,那唯一的問題就是在哪里完成這個注入操作, 馬上搜索"new BpMediaPlayer", 奇怪,,竟然沒有,試試搜索"IMediaPlayer“,,發(fā)現(xiàn)了一點線索 //av/media/libmedia/IMediaPlayerService.cpp 70: virtual sp<IMediaPlayer> create( 71: const sp<IMediaPlayerClient>& client, int audioSessionId) { 72 Parcel data, reply; 73: ... 77 remote()->transact(CREATE, data, &reply); 78: return interface_cast<IMediaPlayer>(reply.readStrongBinder()); //reply里讀出IBinder,然后轉(zhuǎn)成IMediaPlayer接口對象 79 }
這里通過interface_cast 直接把IBinder 轉(zhuǎn)換成了 IMediaPlayer,, interface_cast 到底有什么魔力? template<typename INTERFACE> inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj) { return INTERFACE::asInterface(obj); }
繼續(xù)跟進 asInterface, 結(jié)果發(fā)現(xiàn)里以下代碼 #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(); #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; } \
恍然大悟,,原來在DECLARE_META_INTERFACE 這個宏里定義了asInterface, 在IMPLEMENT_META_INTERFACE 里實現(xiàn)了它,,這里果然有一個new BpMediaPlayer! 然后把它轉(zhuǎn)換成父父類 IMediaPlayer。 一切都清楚了,,用一張圖來表示 客戶端從遠端獲取一個IBinder對象,,接著生成BpMediaPlayer, 將其轉(zhuǎn)成 IMediaPlayer 接口對象,這是用戶程序看到的對象,,并通過其調(diào)用接口方法,,最終調(diào)到BpBinder的transact()。 問題又來了,,這個transact() 怎么傳遞到服務(wù)端,,并最終調(diào)到 onTransact()? 回想一下,onTransact() 是IBinder的接口函數(shù)吧,,而且Server的IBinder實現(xiàn)是BBinder, 那一定有人通過某種方式得到了BBinder對象,。 這個人就是Binder Driver. 為了找到真相,必須用源頭開始,,那就是transact() status_t BpBinder::transact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { ... status_t status = IPCThreadState::self()->transact( mHandle, code, data, reply, flags); ... return DEAD_OBJECT; }
IPCThreadState的transact()函數(shù)相比IBinder 多了一個mHandle, 啥來歷,? BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
構(gòu)造帶進來的,趕緊找“new BpBinder", 結(jié)果在ProcessState.cpp 看到了 sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle) { ... IBinder* b = e->binder; if (b == NULL || !e->refs->attemptIncWeak(this)) { b = new BpBinder(handle);
找誰call了getStrongProxyForHandle,?為了快速找到調(diào)用棧,,我們在BpBinder的構(gòu)造函數(shù)里加了這么幾句話: #include <utils/CallStack.h> ... CallStack cs; cs.update(); cs.dump("BpBinder")
然后得到了下面的打印 09-29 07:11:14.363 1624 1700 D BpBinder: #00 pc 0001eb34 /system/lib/libbinder.so (android::BpBinder::BpBinder(int)+260) 09-29 07:11:14.363 1624 1700 D BpBinder: #01 pc 0003b9a2 /system/lib/libbinder.so (android::ProcessState::getStrongProxyForHandle(int)+226) 09-29 07:11:14.363 1624 1700 D BpBinder: #02 pc 00032b8c /system/lib/libbinder.so (android::Parcel::readStrongBinder() const+316) //frameworks/native/libs/binder/Parcel.cpp:247 09-29 07:11:14.363 1624 1700 D BpBinder: #03 pc 000ad9d2 /system/lib/libandroid_runtime.so //frameworks/base/core/jni/android_os_Parcel.cpp:355 09-29 07:11:14.363 1624 1700 D BpBinder: #04 pc 00029c5b /system/lib/libdvm.so (dvmPlatformInvoke+79) //dalvik/vm/arch/x86/Call386ABI.S:128
#04 dvmPlatformInvork 說明這是一個Jni調(diào)用,#03 對應的代碼是 return javaObjectForIBinder(env, parcel->readStrongBinder());
應該是Java傳下來一個Parcel對象,,然后由本地代碼進行解析,,從中讀出IBinder對象,并最終返回,。也就是說,,遠端有人將這個IBinder對象封在Parcel里。還是沒有頭緒,?繼續(xù)順著調(diào)用棧往前看,, #02 對應于下面的代碼 status_t unflatten_binder(const sp<ProcessState>& proc, const Parcel& in, sp<IBinder>* out) { const flat_binder_object* flat = in.readObject(false); ...case BINDER_TYPE_HANDLE: *out = proc->getStrongProxyForHandle(flat->handle); return finish_unflatten_binder( static_cast<BpBinder*>(out->get()), *flat, in); } } return BAD_TYPE; }
#bionic/libc/kernel/common/linux/binder.h
原來mHandle就是flat_binder_object里面的handle, 它只是一個數(shù)字!這個數(shù)據(jù)結(jié)構(gòu)定義在Kernel里,,是經(jīng)過Kernel轉(zhuǎn)手的,。越來越亂了,,趕緊整理一下思路: 1. Kernel 封裝了一個數(shù)據(jù)結(jié)構(gòu)(flat_binder_object),里面帶有一個數(shù)字(mHandle),。 2. 客戶端獲取這個數(shù)字后,,生成一個BpBinder的對象。 3. 然后當客戶端需要訪問遠端服務(wù)的時候,,將這個數(shù)字附上,。 回到現(xiàn)實生活,機票代理需要向航空公司查詢或訂票的話,,一定要知道是哪個航空公司,,莫非這個號就是航空公司的編號? 恭喜你,,就是那么簡單,,這個號就對應了服務(wù)器端的提供的某一個服務(wù),Android 中每個Service都有一個號碼(根據(jù)創(chuàng)建時間遞增,,0號Service 是ServiceManager,讓我用下面的圖來描述整個過程吧,,
1. 在已知服務(wù)名的情況下,,App 通過getService() 從ServiceManager 獲取該服務(wù)的信息,該信息封裝在Parcel里,。 2. 應用程序收到返回的這個Parcel對象(通過Kernel), 從中讀取出flat_binder_object 對象,,最終從對象中得到服務(wù)對應的服務(wù)號,mHandle. 3. 以該號碼作為參數(shù)輸入生成一個IBinder對象(實際是BpBinder),。 4. 應用獲取該對象后,,通過asInterface(IBinder*) 生成服務(wù)對應的Proxy對象(BpXXX),并將其強轉(zhuǎn)為接口對象(IXXX),然后直接調(diào)用接口函數(shù),。 5. 所有的接口對象調(diào)用最終會走到BpBinder->transact()函數(shù),,這個函數(shù)調(diào)用IPCThreadState->transact()并以Service號作為參數(shù)之一。 6. 最終通過系統(tǒng)調(diào)用ioctrl() 進入內(nèi)核空間,,Binder驅(qū)動根據(jù)傳進來的Service 號尋找該Service正處于等待狀態(tài)的Binder Thread, 喚醒它并在該線程內(nèi)執(zhí)行相應的函數(shù),,并返回結(jié)果給APP。 強調(diào)一下: 1. 從應用程序的角度來看,,他只認識IBinder 和 IMediaPlayer 這兩個類,,但真正的實現(xiàn)在BpBinder 和 BpMediaPlayer, 這正是設(shè)計模式所推崇的“ Programs to interface, not implementations", 可以說Android 是一個嚴格遵循設(shè)計模式思想精心設(shè)計的系統(tǒng),我們將來會就這個話題進行深入的探討,。 2. 客戶端應該層層的封裝,,最終的目的就是獲取和傳遞這個mHandle 值,從圖中,,我們看到,,這個mHandle至來自與IServiceManager, 他是一個管理其他服務(wù)的服務(wù),,通過服務(wù)的名字我們可以拿到這個服務(wù)對應的Handle號,類似網(wǎng)絡(luò)域名服務(wù)系統(tǒng),。但是我們說了,,IServiceManager也是服務(wù)啊,要訪問他我們也需要一個Handle號啊,,對了,,就如同你必須為你的機器設(shè)置DNS 服務(wù)器地址,你才能獲得DNS 服務(wù),。在Android系統(tǒng)里, 默認的將ServiceManger的Handler號設(shè)為0,,0就是DNS服務(wù)器的地址,這樣,,我們通過調(diào)用 getStrongProxyForHandle(0) 就可以拿到ServiceManager 的IBinder 對象,,當然,系統(tǒng)提供一個 getService(char *)函數(shù)來幫助完成這個過程,。 3. Android Binder 的設(shè)計目標就是讓訪問遠端服務(wù)就像調(diào)用本地函數(shù)一樣簡單,,但是遠端的對象不在本地控制之內(nèi),我們必須保證調(diào)用過程中遠端的對象不能被析構(gòu),,否則本地應用程序?qū)⒑苡锌赡鼙罎?。同時,萬一遠端服務(wù)異常退出,,如Crash, 本地對象必須知曉從而避免后續(xù)的錯誤,。Android 通過 智能指針 和 DeathNotification 來支持這兩個要求,我們會有專門的章節(jié)介紹智能指針,,這里我們會在后面簡單介紹 DeathNotifycation的實現(xiàn)原理,。 Binder的上層設(shè)計邏輯簡單介紹完畢。我們接下來看看Binder的底層設(shè)計,。 3. Binder Driver我們知道,,Linux的進程空間相互獨立,兩個進程只能通過Kernel space 進行互訪,,所有的IPC 機制,,最底層的實現(xiàn)都是在Kernel space. Binder 也是如此,通過系統(tǒng)調(diào)用切入內(nèi)核態(tài),,內(nèi)核尋找到提供服務(wù)的進程,,喚醒他并進入用戶空間,然后在某個線程里調(diào)用onTransact(), 完成特定操作,,并將結(jié)果返回到應用程序,。那Binder Driver是如何搭起連接服務(wù)端和客戶端的這座橋梁呢? 先看看binder driver 內(nèi)部的數(shù)據(jù)結(jié)構(gòu)吧: 下面一一進行解釋: 1. Binder node: 我們前面說過Service 其實是一個存在于某個進程里的對象,因此,,進程PID 和 對象地址可以唯一的標識一個Service 對象,,除此之外,因為這個對象可能被很多應用所使用,,必須有引用計數(shù)來管理他的生命周期,。這些工作都必須在內(nèi)核里完成,Binder node 就是這樣一個結(jié)構(gòu)體來管理每個Service 對象,。
struct binder_node { int debug_id; //kernel內(nèi)部標識node的id struct binder_work work; union { struct rb_node rb_node; struct hlist_node dead_node; }; struct binder_proc *proc; //Service所在進程的結(jié)構(gòu)體 struct hlist_head refs; //雙向鏈表頭,,鏈表里存放一系列指針,指向引用該Service的binder_ref對象,, int internal_strong_refs; //內(nèi)部強引用計數(shù) int local_weak_refs; //弱引用計數(shù) int local_strong_refs; //強引用計數(shù) binder_ptr __user ptr; //Service對象地址 binder_ptr __user cookie; unsigned has_strong_ref:1; unsigned pending_strong_ref:1; unsigned has_weak_ref:1; unsigned pending_weak_ref:1; unsigned has_async_transaction:1; unsigned accept_fds:1; unsigned min_priority:8; struct list_head async_todo; };
2. binder_ref binder_ref 描述了每個對服務(wù)對象的引用,,對應與Client端。如上圖所示,,每個Ref通過node指向binder_node. 一個進程所有的binder_ref通過兩個紅黑樹(RbTree)進行管理,,通過binder_get_ref() 和 binder_get_ref_for_node快速查找。 struct binder_ref { /* Lookups needed: */ /* node + proc => ref (transaction) */ /* desc + proc => ref (transaction, inc/dec ref) */ /* node => refs + procs (proc exit) */ int debug_id; struct rb_node rb_node_desc; struct rb_node rb_node_node; struct hlist_node node_entry; struct binder_proc *proc; //應用進程 struct binder_node *node; uint32_t desc; int strong; int weak; struct binder_ref_death *death; //如果不為空,,則client想獲知binder的死亡 };
3. binder_proc 一個進程既包含的Service對象,,也可能包含對其他Service對象的引用. 如果作為Service對象進程,它可能會存在多個Binder_Thread,。這些信息都在binder_proc結(jié)構(gòu)體進行管理,。 struct binder_proc { struct hlist_node proc_node; //全局鏈表 binder_procs 的node之一 struct rb_root threads; //binder_thread紅黑樹,存放指針,,指向進程所有的binder_thread, 用于Server端 struct rb_root nodes; //binder_node紅黑樹,存放指針,,指向進程所有的binder 對象 struct rb_root refs_by_desc; //binder_ref 紅黑樹,,根據(jù)desc(service No) 查找對應的引用 struct rb_root refs_by_node; //binder_ref 紅黑樹,根據(jù)binder_node 指針查找對應的引用 int pid; struct vm_area_struct *vma; struct mm_struct *vma_vm_mm; struct task_struct *tsk; struct files_struct *files; struct hlist_node deferred_work_node; int deferred_work; void *buffer; ptrdiff_t user_buffer_offset; struct list_head buffers; struct rb_root free_buffers; struct rb_root allocated_buffers; size_t free_async_space; struct page **pages; size_t buffer_size; uint32_t buffer_free; struct list_head todo; //task_list, binder_work鏈表,,存放指針最終指向某個binder_transaction對象 wait_queue_head_t wait; struct binder_stats stats; struct list_head delivered_death; int max_threads; int requested_threads; int requested_threads_started; int ready_threads; long default_priority; struct dentry *debugfs_entry; };
為了實現(xiàn)快速的查找,,binder_proc內(nèi)部維護了若干個數(shù)據(jù)結(jié)構(gòu),如圖中黃色高亮所示,, 4. binder_transaction 每個transact() 調(diào)用在內(nèi)核里都會生產(chǎn)一個binder_transaction 對象,,這個對象會最終送到Service進程或線程的todo隊列里,然后喚醒他們來最終完成onTransact()調(diào)用,。 struct binder_transaction { int debug_id; //一個全局唯一的ID struct binder_work work; // 用于存放在todo鏈表里 struct binder_thread *from; //transaction 發(fā)起的線程,。如果BC_TRANSACTION, 則為客戶端線程,如果是BC_REPLY, 則為服務(wù)端線程,。 struct binder_transaction *from_parent; //上一個binder_transaction. 用于client端 struct binder_proc *to_proc; //目標進程 struct binder_thread *to_thread; //目標線程 struct binder_transaction *to_parent; //上一個binder_transaction, 用于server端 unsigned need_reply:1; /* unsigned is_dead:1; */ /* not used at the moment */ struct binder_buffer *buffer; unsigned int code; unsigned int flags; long priority; long saved_priority; kuid_t sender_euid; };
5. binder_thread binder_proc里的threads 紅黑樹存放著指向binder_thread對象的指針,。這里的binder_thread 不僅僅包括service的binder thread, 也包括訪問其他service的調(diào)用thread. 也就是說所有與binder相關(guān)的線程都會在binder_proc的threads紅黑樹里留下記錄。binder_thread里最重要的兩個成員變量是 transaction_stack 和 wait. struct binder_thread { struct binder_proc *proc; struct rb_node rb_node; //紅黑樹節(jié)點 int pid; int looper; // struct binder_transaction *transaction_stack; //transaction棧 struct list_head todo; uint32_t return_error; uint32_t return_error2; wait_queue_head_t wait; //等待隊列,用于阻塞等待 struct binder_stats stats; }; 在binder_proc里面我們也能看到一個wait 隊列,,是不是意味著線程既可以在proc->wait上等待,,也可以在thread->wait上等待?binder driver 對此有明確的用法,,所有的binder threads (server 端)都等待在proc->wait上,。因為對于服務(wù)端來說,用哪個thread來響應遠程調(diào)用請求都是一樣的,。然而所有的ref thread(client端)的返回等待都發(fā)生在調(diào)用thread的wait 隊列,,因為,當某個binder thread 完成服務(wù)請求后,,他必須喚醒特定的等待返回的線程,。但是有一個例外,在雙向調(diào)用的情況下,,某個Server端的thread將會掛在thread->wait上等待,,而不是proc->wait. 舉個例子,假設(shè)兩個進程P1 和 P2,,各自運行了一個Service,, S1,S2,, P1 在 thread T1 里調(diào)用S2提供的服務(wù),,然后在T1->wait里等待返回。S2的服務(wù)在P2的binder thread(T2)里執(zhí)行,,執(zhí)行過程中,,S2又調(diào)到S1里的某個接口,按理S1 將在P1的binder thread T3里執(zhí)行,, 如果P1接下來又調(diào)到了P2,,那又會產(chǎn)生新的進程 T4, 如果這個反復調(diào)用棧很深,,需要耗費大量的線程,,顯然這是非常不高效的設(shè)計。所以,,binder driver 里做了特殊的處理,。當T2 調(diào)用 S1的接口函數(shù)時,binder driver 會遍歷T2的transaction_stack, 如果發(fā)現(xiàn)這是一個雙向調(diào)用(binder_transaction->from->proc 等于P1), 便會喚醒正在等待reply的T1,,T1 完成這個請求后,,繼續(xù)等待S2的回復。這樣,,只需要最多兩個Thread就可以完成多層的雙向調(diào)用,。 binder_thread里的transaction_stack 是用鏈表實現(xiàn)的堆棧,, 調(diào)用線程和服務(wù)線程的transaction有著不同的堆棧。下圖是上面這個例子的堆棧情形:
6. binder_ref_death binder_ref 記錄了從client進程到server進程某個service的引用,,binder_ref_death 是binder_ref的一個成員變量,,它的不為空說明了client進程想得到這個service的死亡通知(嚴格意義上講,是service所在進程的死亡通知,,因為一個進程一個/dev/binder的fd, 只有進程死亡了,,driver才會知曉,通過 file_operations->release 接口),。 struct binder_ref_death { struct binder_work work; binder_ptr __user cookie; };
我們可以下面一張時序圖來了解binder death notifycation 的全過程,。
7. binder_work 從應用程序角度來看,所有的binder調(diào)用都是同步的,。但在binder driver 內(nèi)部,,兩個進程間的交互都是異步的,一個進程產(chǎn)生的請求會變成一個binder_work, 并送入目標進程或線程的todo 隊列里,,然后喚醒目標進程和線程來完成這個請求,,并阻塞等待結(jié)果。binder_work的定義如下: struct binder_work { struct list_head entry; enum { BINDER_WORK_TRANSACTION = 1, BINDER_WORK_TRANSACTION_COMPLETE, BINDER_WORK_NODE, BINDER_WORK_DEAD_BINDER, BINDER_WORK_DEAD_BINDER_AND_CLEAR, BINDER_WORK_CLEAR_DEATH_NOTIFICATION, } type; };
很簡單,,其實只定義了一個鏈表的節(jié)點和work的類型,。 8. binder_buffer 進程間通信除了命令,還有參數(shù)和返回值的交換,,要將數(shù)據(jù)從一個進程的地址空間,,傳到另外一個進程的地址空間,通常需要兩次拷貝,,進程A -> 內(nèi)核 -> 進程B,。binder_buffer 就是內(nèi)核里存放交換數(shù)據(jù)的空間(這些數(shù)據(jù)是以Parcel的形式存在)。為了提高效率,,Android 的 binder 只需要一次拷貝,,因為binder 進程通過mmap將內(nèi)核空間地址映射到用戶空間,從而可以直接訪問binder_buffer的內(nèi)容而無需一次額外拷貝,。binder_buffer由內(nèi)核在每次發(fā)起的binder調(diào)用創(chuàng)建,,并賦給binder_transaction->buffer. binder driver 根據(jù)binder_transaction 生產(chǎn) transaction_data(包含buffer的指針而非內(nèi)容), 并將其復制到用戶空間,。 9. flat_binder_obj 前面我們說過,,<proc, handle> 可以標識一個BpBinder 對象,而<proc, ptr> 可以標識一個BBinder對象,。Binder Driver 會收到來自與BpBinder 和 BBinder的系統(tǒng)調(diào)用,,它是如何判別它們的身份呢?答案就在flat_binder_obj里,,先看看它的定義,, struct flat_binder_object { unsigned long type; //見下面定義 unsigned long flags; union { void *binder; //BBinder,通過它driver可以找到對應的node signed long handle; //BpBinder,根據(jù)它driver可以找到對應的ref }; void *cookie; }; enum { BINDER_TYPE_BINDER = B_PACK_CHARS('s', 'b', '*', B_TYPE_LARGE), BINDER_TYPE_WEAK_BINDER = B_PACK_CHARS('w', 'b', '*', B_TYPE_LARGE), BINDER_TYPE_HANDLE = B_PACK_CHARS('s', 'h', '*', B_TYPE_LARGE), BINDER_TYPE_WEAK_HANDLE = B_PACK_CHARS('w', 'h', '*', B_TYPE_LARGE), BINDER_TYPE_FD = B_PACK_CHARS('f', 'd', '*', B_TYPE_LARGE), }; union表明了在Server端和Client端它有著不同的解讀,。type則表明了它的身份,。binder driver 根據(jù)它可以找到BpBinder 和 BBinder 在內(nèi)核中相對應的對象 (ref 或 node). flat_binder_obj 封裝在parcel里,詳見Parcel.cpp. 至此,,binder driver里面重要的數(shù)據(jù)結(jié)構(gòu)都介紹完了,,大家對binder driver的工作原理也有了大致的了解,這里再稍作總結(jié): 1. 當一個service向binder driver 注冊時(通過flat_binder_object), driver 會創(chuàng)建一個binder_node, 并掛載到該service所在進程的nodes紅黑樹,。 2. 這個service的binder線程在proc->wait 隊列上進入睡眠等待,。等待一個binder_work的到來。 3. 客戶端的BpBinder 創(chuàng)建的時候,,它在driver內(nèi)部也產(chǎn)生了一個binder_ref對象,,并指向某個binder_node, 在driver內(nèi)部,將client和server關(guān)聯(lián)起來,。如果它需要或者Service的死亡狀態(tài),,則會生成相應的binfer_ref_death. 4. 客戶端通過transact() (對應內(nèi)核命令BC_TRANSACTION)請求遠端服務(wù),driver通過ref->node的映射,,找到service所在進程,,生產(chǎn)一個binder_buffer, binder_transaction 和 binder_work 并插入proc->todo隊列,接著喚醒某個睡在proc->wait隊列上的Binder_thread. 與此同時,,該客戶端線程在其線程的wait隊列上進入睡眠,,等待返回值。 5. 這個binder thread 從proc->todo 隊列中讀出一個binder_transaction, 封裝成transaction_data (命令為 BR_TRANSACTION) 并送到用戶空間,。Binder用戶線程喚醒并最終執(zhí)行對應的on_transact() 函數(shù),。 6. Binder用戶線程通過transact() 向內(nèi)核發(fā)送 BC_REPLY命令,driver收到后從其thread->transaction_stack中找到對應的binder_transaction, 從而知道是哪個客戶端線程正在等待這個返回,。 7. Driver 生產(chǎn)新的binder_transaction (命令 BR_REPLY), binder_buffer, binder_work, 將其插入應用線程的todo對立,,并將該線程喚醒。 8. 客戶端的用戶線程收到回復數(shù)據(jù),,該Transaction完成,。 9. 當service所在進程發(fā)生異常退出,driver 的 release函數(shù)被調(diào)到,,在某位內(nèi)核work_queue 線程里完成該service在內(nèi)核態(tài)的清理工作(thread,,buffer,node,,work...), 并找到所有引用它的binder_ref, 如果某個binder_ref 有不為空的binder_ref_death, 生成新的binder_work, 送人其線程的todo 對立,,喚醒它來執(zhí)行剩余工作,用戶端的DeathRecipient 會最終被調(diào)用來完成client端的清理工作,。 下面這張時序圖描述了上述一個transaction完成的過程,。不同的顏色代表不同的線程,。注意的是,雖然Kernel和User space 線程的顏色是不一樣的,,但所有的系統(tǒng)調(diào)用都發(fā)生在用戶進程的上下文里(所謂上下文,,就是Kernel能通過某種方式找到關(guān)聯(lián)的進程(通過Kernel的current 宏),并完成進程相關(guān)的操作,,比如說喚醒某個睡眠的線程,,或跟用戶空間交換數(shù)據(jù),copy_from, copy_to, 與之相對應的是中斷上下文,,其完全異步觸發(fā),,因此無法做任何與進程相關(guān)的操作,比如說睡眠,,鎖等),。
4. Java BinderBinder 的學習已經(jīng)接近尾聲了,我們已經(jīng)研究了Binder Driver, C/C++的實現(xiàn),,就差最后一個部分了,,Binder在Java端的實現(xiàn)了。Java端的實現(xiàn)與Native端類似,,我們用下面的表格和類圖概括他們的關(guān)系
可見,,Java較Native端實現(xiàn)簡單很多,通過Aidl工具來實現(xiàn)類似功能,。所以,,要實現(xiàn)一個Java端的service,只需要做以下幾件事情: 1. 寫一個.aidl文件,,里面用AIDL語言定義一個接口類IXXX,。 2.在Android.mk里加入該文件,這樣編譯系統(tǒng)會自動生成一個IXXX.java, 放在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core 下面,。 3. 在服務(wù)端,,寫一個類,擴展IXXX.Stub,,具體實現(xiàn)IXXX的接口函數(shù),。
|
|
來自: just_person > 《Binder項目》