如何利用關鍵問題,感性理解Binder
1.service_manager的啟動
用來管理服務,所有的系統服務都會註冊到這裡。
本質上是服務的引用BpBinder的管理者,可以將服務引用BpBinder分發給其他Client。
當然了,這種分發在核心中是傳遞binder_node到其他程式,並在該程式中建立新的binder_ref和 BpBinder
思考:
service_manager是如何成為管理者的
{
必須是公共入口
提供了儲存服務
}
如何與管理者通訊 {
/dev/binder休眠喚醒
資料協議
}
複製程式碼
2.BpBinder、BBinder、IPCThreadState、ProcessState之間的關係
程式複用的底層與/dev/Binder的互動邏輯,全部放到了IPCThreadState中,資料的分發是靠Parcel + binder_transaction_data -> binder_write_read協議來實現的,所以只要將資料打包好,自然能夠傳送到目的地。
ProcessState主要快取了BpBinder,實現放到IPCThreadState中也沒有什麼問題。
3.BpInterface、BnInterface、BpBinder、BBinder之間的關係
C++層的aidl而已,這個理解應用比較到位吧
Java層的
IXXXService.Stub繼承自Binder對映了JNI中的JavaBBinder
IXXXService.Proxy繼承自BinderProxy,從IPCProcessState傳過來的Parcel,最終解析成為BpBinder,轉化為了Java層的BinderProxy。
複製程式碼
4.如何劃分Binder架構層次
Java層:
Binder.exeTransact
複製程式碼
C++層:
(BnInterface)
JavaBBinder.onTransact (data)
BBinder.transact (data、BBinder -> Parcel)
IPCThreadState::getAndExecuteCommand (Parcel -> binder_transaction_data ->
binder_write_read )
IPCThreadState::talkWifiDriver + waitForResponse
複製程式碼
核心層:
ioctl
/dev/binder (binder_write_read -> binder_transaction_data -> binder_write_read)
binder_ioctl
binder_write_read
binder_write_thread
binder_transaction
複製程式碼
5.一次有效的通訊是如何實現的
無論是Java層還是C++層的上層呼叫,都是利用BpBinder -> IPCThreadState來傳送資料,利用BBinder-> IPCThreadState來接收資料。一次有效的資料通訊涉及到幾個方面:
1.BBinder實體的註冊
2.BpBinder引用的獲取
3.利用上層資料(data + flat_binder_object + 協議) + 傳輸handle 進行傳輸
4.核心驅動資料轉發實現
6.如和註冊到實名binder的
要註冊實名binder(service_manager進行一次add,其他binder先得獲得引用,然後執行add操作) A.service_manager中執行add,先獲取其引用BpBinder(0),Java層構建了ServiceManager_Proxy->Binder_Proxy->BpBinder(0),可以直接通訊了。
1.一個服務在Java層註冊
利用aidl生成Stub和Proxy,實現Stub的介面,利用ServiceManager.addService(name, Stub)註冊到ServiceManager中.程式碼如下:
142 public void addService(String name, IBinder service, boolean allowIsolated)
143 throws RemoteException {
144 Parcel data = Parcel.obtain();
145 Parcel reply = Parcel.obtain();
146 data.writeInterfaceToken(IServiceManager.descriptor);
147 data.writeString(name);
148 data.writeStrongBinder(service);
149 data.writeInt(allowIsolated ? 1 : 0);
150 mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
151 reply.recycle();
152 data.recycle();
153 }
複製程式碼
Java層的Binder寫到Parcel中變成了ibinderForJavaObject(env, object),即轉換成了JavaBBinder,並與Stub構建了關係關係,即JavaBBinder (BBinder) <-> Stub (Binder)
2.一個服務在C++層註冊
利用BpInterface和BnInterface約定關係,實現BnXXXService,並實現其中的code與函式呼叫關係。BnXXXService是BBinder的子類,最後呼叫C++層的IServiceManager.defaultServiceManager.addService(name, BBinder)來註冊。
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;
}
複製程式碼
這裡還需要記錄一點:Binder節點基本上是第一次註冊到實名Binder時,在通訊的兩個程式中,分別在核心中建立的binder_node。當然了,在傳送端是建立binder_node節點,而在接收端是拷貝binder_node節點。
7.如何拿到引用以及引用如何找到目標
要拿到引用,只要跟實名binder通訊一次(servcie_manager是一次、其他實名binder是兩次) 如果要從service_manager中拿到引用,首先在IPCThreadState中找到BpBinder(0),利用其構造getService的通訊handle + data + target binder -> Parcel -> binder_transaction_data -> binder_write_read,利用通訊協議將binder_transaction_data.handle傳遞到核心,核心根據handle去查詢binder_ref (兩處查詢,一個是binder_proc->refs_by_desc,一個是binder_context_mgr_node),進而查詢到目標binder_node。利用binder_node通訊的過程:喚醒目標binder執行緒、取資料、解析,於是到了service_manager的上層了,後續不詳述了。
1.Java層如何找到服務
ServiceManager.getService在Java層是帶有快取的,如果有快取那麼直接取,如果沒有那麼利用ServiceManagerProxy -> BinderProxy -> BpBinder(0)來獲取服務,看下程式碼吧。最後得到的是一個經JNI轉換的BinderProxy。native得到的是BpBinder,而Java很顯然不能使用,瞭解Binder層次的話,很自然能夠確定一定是Binder_Proxy。
118 public IBinder getService(String name) throws RemoteException {
119 Parcel data = Parcel.obtain();
120 Parcel reply = Parcel.obtain();
121 data.writeInterfaceToken(IServiceManager.descriptor);
122 data.writeString(name);
123 mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
124 IBinder binder = reply.readStrongBinder();
125 reply.recycle();
126 data.recycle();
127 return binder;
128 }
複製程式碼
2.在C++層找到服務
同樣利用BpInterface來找到服務,先構建了一個BpServiceManager (繼承自BpInterface和IServiceManager),然後通訊就好了。最後得到的是一個BpBinder
gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL));
146 virtual sp<IBinder> getService( const String16& name) const
147 {
148 Parcel data, reply;
149 data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
150 data.writeString16(name);
151 remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
152 return reply.readStrongBinder();
153 }
複製程式碼
8.Java層和C++層的對映關係
Binder構造時:
JavaBBinder 放到了JavaBBinderHolder 的mBinder域, JavaBBinderHolder放到了 Binder.mObject 域,而Binder引用放到了 JavaBBinder.mObject,因此Binder和JavaBBinder建立了Java到C++的雙向關聯引用關係。
BinderProxy構造時:
基本在C++裡面出發,將BpBinder放到BinderProxy.mObject,而例如ServiceManagerProxy將BinderProxy放到了ServiceManagerProxy.mRemote域中。
9.Android層服務的註冊和引用
首先註冊Service到SystemServer程式,然後在Context中靜態初始化Client,應用利用Context.getSystemServer即可找到IVibratorService.Proxy了。