Binder基礎業務分析

afxstarx發表於2018-08-22

ProcessState

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

一個單例類,開啟了Binder裝置、mHandleToObject快取了一堆BpBinder、快取了context_mgr、啟動binder執行緒

IPCThreadState

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

一個單例,保持了mProcess、儲存了程式pid和uid資訊、joinThreadPool讓Binder執行緒進入訊息迴圈getAndExecuteCommand、transact用來傳送訊息並接受返回。

下面是幾個通訊最小操作單元:

writeTransactionData 將資料寫入mOut緩衝器

talkWithDriver 一次ioctrl操作

waitForResponse 等待返回

executeCommand 執行命令

sendReply 傳送返回訊息

因此傳送transact = writeTransactionData + talkWithDriver + waitForResponse getAndExecuteCommend = talkWithDriver + executeCommand + sendReply

service_manager.c

androidxref.com/6.0.0_r1/xr…

binder_open  ->  binder_become_context_mgr  ->  binder_loop  ->  binder_parse  ->  BR_TRANSACTION  -> func ->  svcmgr_handle  ->  binder_send_reply

name, handle  ----->  svcinfo_list  ->   svcinfo  ->  handle、binder_node
複製程式碼

main_mediaserver.cpp

androidxref.com/5.0.0_r2/s?…

androidxref.com/5.0.0_r2/xr…

sp<ProcessState> proc(ProcessState::self());
MediaPlayerService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
複製程式碼

因為ProcessState是單例,多以必然會在當前程式開啟一次binder裝置檔案

其中MediaPlayerService繼承自BnMediaPlayService

而BnMediaPlayerService繼承自BnInterface

因此MediaPlayerService繼承與BnMediaPlayerService和IMediaPlayerService

繼承關係為:MediaPlayerService <- BnMediaPlayerService <- BnInterface 、IMediaPlayerService <- BBinder -> IBinder

因此MediaPlayerService可以看出是BBinder的包裝類,onTransact最終交由前者重寫的函式處理 資料最終根據code分發到IMediaPlayerService的介面中

IMediaPlayerService: sp createMediaRecorder() sp createMetadataRetriever() sp create(); status_t decode(...);

智慧時刻:

1.建構函式: 建立了XXXService -> IXXXService -> BnXXXService -> BBinder (訊息最終交由BBinder路由,分發到IXXXService不同函式中)

2.instantiate: IServiceManager->defaultServiceManager->addService(xxx, new XXXService) 首先拿到了BpServiceManager即BpBinder(0), 不明白看下面的解釋

呼叫了BpServiceManager-BpBinder(0)->transact, 程式碼看下面

IServiceManager

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

單例defaultServiceManager(),從ProcessState中取出了BpBinder,然後構建了IServiceManager和BpServiceManager的子類BpServiceManager (Bpxxx必須要繼承自Ixxx和BpInterface)

函式理解一下:

virtual sp<IBinder> getService( const String16& name) const
 {
       Parcel data, reply;
       data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
       data.writeString16(name);
       remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
       return reply.readStrongBinder();
 }
複製程式碼
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;
}
複製程式碼

總體上來說,是從ProcessState中利用handle拿到了BpBinder,然後構建了外觀類BpServiceManager,但最終通訊還是利用BpBinder->transact,實際上是利用IPCThreadState::transact傳送訊息,該函式利用mIn和mOut快取資料,利用BpBinder(0)->transact(ADD_SERVICE_TRANSACTION, data, &reply)利用一次ioctrl(fd, BC_CMD, &bwr)寫操作和一次ioctrl(fd, BC_CMD, &bwr)讀操作,來與驅動通訊。關注一下傳送的命令,ADD_SERVICE_TRANSACTION居然還藏著一個祕密,看看它是在哪被接收的吧!

IInterface.h

androidxref.com/5.0.0_r2/xr…

inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
複製程式碼

該函式很常見,由一個BpBinder生成一個外觀類BpXXXService(繼承自BpRefBase、INTERFACE)

BpINTERFACE  ->  BpInterface 、INTERFACE、BpRefBase
複製程式碼

因此interface_cast相當於new BpINTERFACE(obj)

interface_cast相當於生成了IServiceManager子類new BpServiceManager(obj)

下面的程式碼很魔性,理解一下:

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();
};
複製程式碼
template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
                               BpInterface(const sp<IBinder>& remote);

protected:
    virtual IBinder*            onAsBinder();
};
複製程式碼
74#define DECLARE_META_INTERFACE(INTERFACE)                               
75    static const android::String16 descriptor;                          
76    static android::sp<I##INTERFACE> asInterface( const android::sp<android::IBinder>& obj);      
78    virtual const android::String16& getInterfaceDescriptor() const;    
79    I##INTERFACE();                                                     
80    virtual ~I##INTERFACE();                                            
81
82
83#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       
84    const android::String16 I##INTERFACE::descriptor(NAME);             
85    const android::String16& I##INTERFACE::getInterfaceDescriptor() const {              
87        return I##INTERFACE::descriptor;                                
88    }                                                                   
89    android::sp<I##INTERFACE> I##INTERFACE::asInterface(const android::sp<android::IBinder>& obj) 
91    {                                                                   
92        android::sp<I##INTERFACE> intr;                                 
93        if (obj != NULL) {                                              
94            intr = static_cast<I##INTERFACE*>(obj->queryLocalInterface( I##INTERFACE::descriptor).get());
97            if (intr == NULL) {                                         
98                intr = new Bp##INTERFACE(obj);                          
99            }                                                           
100        }                                                               
101        return intr;                                                    
102    }                                                                   
103    I##INTERFACE::I##INTERFACE() { }                                    
104    I##INTERFACE::~I##INTERFACE() { }                                   
複製程式碼

BpBinder

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

繼承自IBinder,成員變數mHandle,關鍵函式transact呼叫IPCThreadState::transact

 IPCThreadState::self()->transact(mHandle, code, data, reply, flags);
複製程式碼

最終呼叫了talkWithDriver呼叫得到reply

Parcel.cpp

androidxref.com/5.0.0_r2/xr…

androidxref.com/5.0.0_r2/xr…

雜項資料和Binder的包裝類,主要包含mData和mObjects

依靠(uint8_t*)malloc(desired)來分配記憶體,並不斷擴容

status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
    return flatten_binder(ProcessState::self(), val, this);
}
複製程式碼
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;

    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) {
        IBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                ALOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
            obj.cookie = reinterpret_cast<uintptr_t>(local);
        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = 0;
        obj.cookie = 0;
    }
    return finish_flatten_binder(binder, obj, out);
}
複製程式碼

1.以上函式說明BpBinder傳遞時,最終建立了一個flat_binder_object,並將handle寫入了flat_binder_object.handle中,最終記錄到了核心驅動binder_node.handle中

2.同理對於BBinder,將BBinder的物件地址寫到了flat_binder_object.binder和flat_binder_object.cookie中,最終記錄到了binder_node的binder和cookie中。傳送端傳送訊息時,先根據handle在核心中找到binder_ref,即找到了binder_proc和binder_node,選擇喚醒binder_proc上的等待佇列即喚醒binder執行緒,並將訊息交由binder執行緒返回給使用者空間,使用者空間取出flat_binder_object,根據裡面的cookie可以得到BBinder物件。最終根據code分發給BBinder的處理函式onTransact中,由BpXXX來分發給IXXX。

binder驅動

androidxref.com/kernel_3.14…

androidxref.com/kernel_3.14…

binder執行緒ioctrl讀資料進入休眠

IPCThreadState::transact 進行寫資料

第一步:開始寫資料,記錄到binder_work, 並喚醒binder執行緒,binder_thread_read從wait_event中醒來,並將binder_work中的buffer資料取出來放到binder_transaction_data中,最後利用copy_to_user(ptr, &tr, sizeof(tr))寫入使用者空間binder_write_read bwr的ptr,函式返回。至此,上層就可以從ptr取出資料,並進行資料分發了。

從這裡可以看出來:

A.使用者空間BpXXX裡面使用Parcel寫入strongBinder資料flat_binder_object

B.使用者空間IPCThreadState中首先將flat_binder_object寫入binder_transaction_data的中,並寫入mOut中,接著從mOut中取出資料放入到binder_write_read.write_buffer中,最後呼叫ioctrl(fd, BC_CMD, bwr)傳送資料了

binder_transaction_data tr;
tr.data_size = data.ipcDataSize();
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t);
tr.data.ptr.offsets = data.ipcObjects();
複製程式碼

資料包裝的結構為 binder_write_read包含binder_transaction_data包含flat_binder_object,額外資料放到了binder_transaction_data->data.ptr.buffer中,而flat_binder_object放到了data_ptr_offsets中

應用層Parcel -> flat_binder_object + data -> binder_transaction_data -> binder_write_read

進入核心空間 -> 傳送端的binder_write_read 取出binder_transaction_data,放入接收端的binder_write_read.buffer中,至此已經將資料傳入到應用接收層了

binder通訊總結

  • 第一階段:新建服務,在核心中建立binder_node (第一次與實名binder通訊時,在核心中建立)
  • 第一階段:傳送binder_node到一個程式,建立binder_ref引用
  • 第三階段:利用binder_ref傳送資料到binder_node程式,並進入等待reply
  • 第四階段:binder_node程式接收並處理資料,傳送binder_reply

binder資料流向

傳送端 接收端
XXXService->IXXXService
BpXXXService BnXXXService
BpInterface BnInterface
BpBinder BBinder
IPCThreadState::transact IPCThreadState::getAndExecuteCommand
/dev/binder /dev/binder
binder_ioctl binder_ioctl
binder_write_thread binder_read_transaction
binder_transaction binder_transaction

相關文章