Binder c++試驗、分析與理解
本文的文章結構和內容依賴於韋東山老師講解的Binder系統(免費課程),歡迎前往韋東山老師主站http://www.100ask.org瞭解詳情。
文章目錄
1. Binder系統_c++實現
1.1 程序結構
1.2 程序結構
- 抽象共同的部分爲接口,BnHelloService實現native方法,實現提供具體的服務。BpHelloservice實現服務的代理,服務使用的實現。
- server端和client端,server端添加服務,進入循環體等待client端調用。client端得到服務,通過得到的服務,調用服務中的函數。
1.3 具體代碼
- IHelloService.h
定義IHelloservice接口,聲明BnHelloservice。
#define HELLO_SVR_CMD_SAYHELLO 0
#define HELLO_SVR_CMD_SAYHELLO_TO 1
namespace android{
class IHelloService: public IInterface
{
public:
DECLARE_META_INTERFACE(HelloService);
virtual void sayhello(viod) = 0;
virtual int sayhello_to(const char *name) = 0;
};
//繼承IHelloService接口
class BnHelloService:public BnInterface<IHelloService>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
virtual void sayhello(void);
virtual int sayhello_to(const char *name);
};
- BnHelloService.cpp
namespace android{
//收到binder調用,來解析傳過來的數據
status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0)
{
/* 解析數據,調用sayhello/sayhello_to*/
switch (code) {
case HELLO_SVR_CMD_SAYHELLO: {
sayhello();
return NO_ERROR;
} break;
case HELLO_SVR_CMD_SAYHELLO_TO: {
/*取出傳入的數據*/
int32_t policy = data.readInt32();
String16 name16 = data.readString16();
String8 name8(name16);
/*調用執行函數*/
int ret = sayhello_to(name8);
/*把返回值返回回去*/
reply->writeInt32(ret);
return NO_ERROR;
} break;
default:
return BBinder::onTransact( code, data, reply, flags);
}
}
void sayhello(void)
{
static int cnt = 0;
ALOGD("say hello : %d", cnt++);
}
int sayhello_to(const char *name)
{
static int cnt = 0;
ALOGD("say hello to %s : %d", name, cnt++);
}
Binder native實現,收到Binder的Bp端調用後,進入onTransact函數,解析數據並調用native方法。
- BpHelloService.cpp
namespace android{
class BpHelloService: public BpInterface<IHelloService>
{
public:
BpHelloService(const sp<IBinder>& impl)
: BpInterface<IHelloService>(impl)
{
}
void sayhello(void)
{
Parcel data, reply;
data.writeInt32(0);
remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}
int sayhello_to(const char *name)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(client));
data.writeInt32(audioSessionId);
remote()->transact(CREATE, data, &reply);
return interface_cast<IMediaPlayer>(reply.readStrongBinder());
}
}
IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");
}
Binder 代理端,實現了數據構造和消息發送。
- test_server.cpp
using namespace android;
void main(void)
{
/*addService*/
/*while(1){讀取數據,解析數據,根據數據調用服務函數}*/
/*打開binder驅動,mmap*/
sp<ProcessState> proc(ProcessState::self());
/*獲取BpServiceManager*/
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
/*添加服務*/
sm->addService(String16("hello"), new BnHelloService());
/*開啓循環,線程池使用場景*/
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
獲取ServiceManager的binder代理Bp,然後調用服務中的方法添加服務,爲本服務進程創建線程池。進入循環體,等待客戶端使用。
- test_client.cpp
int main(int argc, char **argv)
{
if(argc < 2){
ALOGD("Help:");
ALOGD("%s <hello>", argv[0]);
ALOGD("%s <hello> <name>",argv[0]);
return -1;
}
/*獲得service*/
/*打開binder驅動,mmap*/
sp<ProcessState> proc(ProcessState::self());
/*獲取BpServiceManager*/
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("hello"));
if(binder == 0){
ALOGD("error: can't get hello service");
return -1;
}
//interface_cast<Interface>(binder句柄),通過句柄轉化爲服務
sp<IHelloService> service = interface_cast<IHelloService>(binder);
if(argv < 3){
ALOGD("client call sayhello");
service->sayhello();
} else if(argv = 3){
ALOGD("client call sayhello_to : %s", argv[2]);
int ret = service->sayhello_to(argv[2]);
ALOGD("service sayhello_to return ret = %d", ret);
}
}
和service端一樣,先獲取BpServiceManager,然後調用sm中的方法得到服務。通過interface_cast轉化binder句柄得到服務,通過服務調用BpHelloService中的方法,再通過binder調用到BnHelloService中的方法。這部分的具體調用過程下節分析。
1.4 測試
t7-p1:/ # logcat | grep HelloService &
[1] 19137 19138
t7-p1:/ # cd system/bin/
t7-p1:/system/bin # ./test_server &
[2] 22678
t7-p1:/system/bin # 01-01 08:02:05.613 22678 22678 I HelloService: ServiceManager: 0xb6a99360
t7-p1:/system/bin # ./test_client hello
01-01 08:02:20.548 25031 25031 D HelloService: client call sayhello
01-01 08:02:20.548 22678 22678 D HelloService: HelloService :say hello : 0
t7-p1:/system/bin # ./test_client hello cuishang
01-01 08:02:25.947 25684 25684 D HelloService: client call sayhello_to : cuishang
01-01 08:02:25.947 22678 22691 D HelloService: HelloService:say hello to cuishang : 0
01-01 08:02:25.948 25684 25684 D HelloService: service sayhello_to return ret = 1
測試成功,先啓動server,然後執行client。能夠調用到server的方法。
這裏先梳理一波,相比c程序,使用了android的Binder驅動和ServiceManager,抽象出了IHelloService接口,BpHelloService和BnHelloService類,Bp(Binder proxy)屬於客戶端,Binder的服務代理。app通過調Bp進而調用到BnHelloService。BpHelloService屬於服務端,
2. Binder系統_c++實現_內部機制
2.1 獲取BpServiceManager的對象
- 無論server端還是client端首先都要,獲得BpServiceManager對象過程:
//步驟1
sp<ProcessState> proc(ProcessState::self());
//步驟2
sp<IServiceManager> sm = defaultServiceManager();
步驟1. 在Android系統中,只要涉及到Binder通訊過程都需要存在依據,也就是Android Framework經常出現的一條語句。
ProcessState::self()函數是ProcessState類中的一個靜態函數,屬於這個類,不屬於某個具體的對象。
class ProcessState : public virtual RefBase
{
public:
static sp<ProcessState> self();
...
}
具體函數:
Mutex gProcessMutex;
sp<ProcessState> gProcess;//全局變量
...
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
gProcess = new ProcessState;
return gProcess;
}
從函數中可以看到單例模式,gProcess是ProcessState類的對象,在每個進程中只有一個。
接下來看下ProcessState的構造函數:
ProcessState::ProcessState(const char *driver)
: mDriverFD(open_driver(driver))
...
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
...
{
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);
...
}
...
}
首先打開binder驅動,在binder驅動中,會爲當前進程創建binder節點,構造binder在內核空間所需要的數據結構。這部分不清楚的可以看文章 《Binder系統_驅動情景分析》
mDriverFD(open_driver(driver))
然後設置當前進程的最大線程數:
mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
然後當打開binder驅動成功,對內核空間的內存進行映射到用戶空間:
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
其中mVMStart就是用戶空間虛擬內存的首地址。當前進程就可以通過操作此地址來直接操作內核空間的內存。
所以ProcessState::self() == gProcess,ProcessState的對象,包含當前進程的binder信息。
步驟2. 獲取sm的服務。
首先分析defaultServiceManager //IServiceManager.cpp
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;
}
同樣也是一個單例模式,獲得一個IServiceManager的對象gDefaultServiceManager。
其中interface_cast:把BpBinder(mHandle=0)對象轉換爲IServiceManager接口實例BpServiceManager的對象。
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
接下來繼續分析 ProcessState::self()->getContextObject(NULL)
由步驟1分析的知ProcessState::self()爲當前進程包含binder信息ProcessState的對象。
ProcessState::getContextObject(NULL);
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
return getStrongProxyForHandle(0);
}
繼續跟蹤getStrongProxyForHandle,傳入的參數爲0:
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
...
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
...
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
...
return result;
}
繼續跟蹤b = new BpBinder(handle);
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);
}
handle = 0 = mHandle
因爲sm的binder節點handle爲0。通過interface_cast的轉化後最終得到BpServiceManager類的對象,即sm。所以BpServiceManager爲sm的代理類。
2.2 獲得BpHelloService對象
首先server端添加服務
/*添加服務*/
sm->addService(String16("hello"), new BnHelloService());
/*開啓循環,線程池使用場景*/
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
通過調用sm的方法,傳入字符串“hello”和binder本地實現類的對象,添加一個Hello服務。
然後開啓線程池使進程進入循環。
然後client端獲取服務
步驟1
sp<IBinder> binder = sm->getService(String16("hello"));
if(binder == 0){
ALOGD("error: can't get hello service");
return -1;
}
步驟2
//interface_cast<Interface>(binder句柄),通過句柄轉化爲服務
sp<IHelloService> service = interface_cast<IHelloService>(binder);
步驟1. 調用BpServiceManager的getService函數獲得一個flat_binder_object。
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep(1);
}
return NULL;
}
checkService:
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
通過 remote()->transact發送數據,經過驅動程序後傳遞到sm的svcmgr_handler函數。這部分的具體調用放到本章節第三小節中分析。
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
...
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
return 0;
...
}
do_find_service查找服務,這裏就不繼續展開了,跟着這個函數往下追很容易追到,結果是通過掃描一個列表,對名字進行匹配,然後得到一個整數,即hello service的handle值。
分析 reply.readStrongBinder();
status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
return unflatten_binder(ProcessState::self(), *this, val);
}
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
readStrongBinder(&val);
return val;
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
一直調用到unflatten_binder,由於是返回handle走的是case BINDER_TYPE_HANDLE,*out = proc->getStrongProxyForHandle(flat->handle);
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
...
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
...
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
...
return result;
}
有調用到getStrongProxyForHandle,與之前不同的是,之前handle是爲0,現在的handle是helllo service在sm中的handle值。
sp<IHelloService> service = interface_cast<IHelloService>(binder);
然後通過interface_cast 把binder轉換爲IHelloService接口(BpHelloService對象)。
2.3 代理類如何發送數據
以BpHelloService爲例:
int sayhello_to(const char *name)
{
Parcel data, reply;
步驟1
data.writeInt32(0);
data.writeString16(String16(name));
步驟2
remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
return reply.readInt32();
}
步驟1. 構造數據。
步驟2. 調用remote->transact來發送數據。
remote的來源:
class BpHelloService: public BpInterface<IHelloService>
class BpInterface : public INTERFACE, public BpRefBase
BpHelloService繼承自BpInterface,BpInterface繼承自BpRefBase。
看下BpRefBase:
class BpRefBase : public virtual RefBase
{
protected:
BpRefBase(const sp<IBinder>& o);
virtual ~BpRefBase();
virtual void onFirstRef();
virtual void onLastStrongRef(const void* id);
virtual bool onIncStrongAttempted(uint32_t flags, const void* id);
inline IBinder* remote() { return mRemote; }
inline IBinder* remote() const { return mRemote; }
private:
BpRefBase(const BpRefBase& o);
BpRefBase& operator=(const BpRefBase& o);
IBinder* const mRemote;
RefBase::weakref_type* mRefs;
std::atomic<int32_t> mState;
};
其中remote = mRemote 返回的是BpBinder的對象,調用BpBinder對象的transact函數。
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// Once a binder has died, it will never come back to life.
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
也就是調用binder中的transact發送給hello service。
下面是照抄韋東山老師畫的類圖,對於理解有很大幫助。
BpServiceManager類繼承關係:
BpBinder類繼承關係:
HelloService服務類繼承關係: