Binder是Android系統中實現處理序間通訊的核心機制,其本質是一種Proxy模式的具體實現,就像COM,CORBA一樣。
Proxy模式的基本思想是用戶端程式通過某種方式得到伺服器端的代理對象,所有對伺服器端的服務要求都發送給該代理對象,該代理對象負責同伺服器端進行通訊。從用戶端的角度看,訪問代理對象就如同訪問其它本機物件一樣;伺服器代理對象則屏蔽了所有的處理序間通訊細節。
本文計劃給出一個具體的例子,然後以這個例子為基礎,深入剖析一下Android系統的綁定機制。
執行個體:新增加一個系統服務ExampleService,該服務可以接受一個整形參數,將其值加上100並返回。用戶端應用程式使用此服務計算1+100的值。
代碼1: 系統服務ExampleService的具體實現
// File: ExampleService.h<br />#ifndef ANDROID_EXAMPLE_SERVICE_H<br />#define ANDROID_EXAMPLE_SERVICE_H<br />#include <utils/threads.h><br />#include <utils/RefBase.h><br />#include <binder/IInterface.h><br />#include <binder/BpBinder.h><br />#include <binder/Parcel.h></p><p>namespace android {<br /> class ExampleService : public BBinder<br /> {<br /> mutable Mutex mLock;<br /> int32_t mNextConnId;<br /> public:<br /> static int instantiate();<br /> ExampleService();<br /> virtual ~ExampleService();<br /> virtual status_t onTransact(uint32_t, const Parcel&, Parcel*, uint32_t);<br />};<br />}; //namespace<br />#endif
// File: ExampleService.cpp<br />#include "ExampleService.h"<br />#include <binder/IServiceManager.h><br />#include <binder/IPCThreadState.h></p><p>namespace android {</p><p> static struct sigaction oldact;<br /> static pthread_key_t sigbuskey;</p><p> int ExampleService::instantiate()<br /> {<br /> LOGE("ExampleService instantiate");<br /> // 調用ServiceManager的addService方法進行系統服務註冊,這樣用戶端程式就可以通過ServiceManager獲得此服務的代理對象,從而請求其提供的服務<br /> int r = defaultServiceManager()->addService(String16("byn.example"), new ExampleService());<br /> LOGE("ExampleService r = %d/n", r);<br /> return r;<br /> }</p><p> ExampleService::ExampleService()<br /> {<br /> LOGV("ExampleService created");<br /> mNextConnId = 1;<br /> pthread_key_create(&sigbuskey, NULL);<br /> }</p><p> ExampleService::~ExampleService()<br /> {<br /> pthread_key_delete(sigbuskey);<br /> LOGV("ExampleService destroyed");<br /> }<br /> // 每個系統服務都繼承自BBinder類,都應重寫BBinder的onTransact虛函數。當使用者發送請求到達Service時,系統架構會調用Service的onTransact函數<br /> status_t ExampleService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)<br /> {<br /> switch(code)<br /> {<br /> case 0: {<br /> pid_t pid = data.readInt32();<br /> int num = data.readInt32();<br /> num = num + 100;<br /> reply->writeInt32(num);<br /> return NO_ERROR;<br /> }<br /> break;<br /> default:<br /> return BBinder::onTransact(code, data, reply, flags);<br /> }<br /> }<br />}; //namespace
# File: Android.mk<br />LOCAL_PATH:= $(call my-dir)<br />include $(CLEAR_VARS)<br />LOCAL_SRC_FILES:= /<br />ExampleService.cpp<br />LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)<br />LOCAL_SHARED_LIBRARIES := /<br />libutils libbinder<br />LOCAL_PRELINK_MODULE := false<br />LOCAL_MODULE := libExample</p><p>include $(BUILD_SHARED_LIBRARY)
在/framework/android/src/frameworks/base下面建立一個檔案夾ExampleService,將以上三個檔案複製到該檔案夾中。
代碼2:啟動ExampleService的應用程式
// File: ExampleServer.cpp<br />#include <sys/types.h><br />#include <unistd.h><br />#include <grp.h><br />#include <binder/IPCThreadState.h><br />#include <binder/ProcessState.h><br />#include <binder/IServiceManager.h><br />#include <utils/Log.h><br />#include <private/android_filesystem_config.h><br />#include "../ExampleService/ExampleService.h"</p><p>using namespace android;</p><p>int main(int argc, char** argv)<br />{<br /> sp<ProcessState> proc(ProcessState::self());// 要想使用Binder機制,必須要建立一個ProcessState對象<br /> sp<IServiceManager> sm = defaultServiceManager();<br /> LOGI("ServiceManager: %p", sm.get());<br /> ExampleService::instantiate();<br /> ProcessState::self()->startThreadPool();<br /> IPCThreadState::self()->joinThreadPool();<br /> return 0;<br />}
# File: Android.mk<br />LOCAL_PATH:= $(call my-dir)<br />include $(CLEAR_VARS)<br />LOCAL_SRC_FILES:= /<br />ExampleServer.cpp<br />LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)<br />LOCAL_SHARED_LIBRARIES := /<br />libutils libbinder libExample<br />LOCAL_PRELINK_MODULE := false<br />LOCAL_MODULE := ExampleServer</p><p>include $(BUILD_EXECUTABLE)
在/framework/android/src/frameworks/base下面建立一個檔案夾ExampleServer,將以上兩個檔案複製到該檔案夾中。
代碼3:使用ExampleService的用戶端應用程式
// File: Example.h<br />#ifndef ANDROID_BYN_EXAMPLE_H<br />#define ANDROID_BYN_EXAMPLE_H</p><p>namespace android<br />{<br /> class Example {<br /> public:<br /> void add100(int n);<br /> private:<br /> static const void getExampleService();<br /> };<br />}; //namespace<br />#endif // ANDROID_BYN_EXAMPLE_H
// File: Example.cpp<br />#include <binder/IServiceManager.h><br />#include <binder/IPCThreadState.h><br />#include "Example.h"</p><p>namespace android<br />{<br /> sp<IBinder> binder;<br /> void Example::add100(int n)<br /> {<br /> getExampleService();<br /> Parcel data, reply;<br /> int answer;</p><p> data.writeInt32(getpid());<br /> data.writeInt32(n);<br /> LOGE("BpExampleService::create remote()->transact()/n");<br /> binder->transact(0, data, &reply);<br /> answer = reply.readInt32();<br /> printf("answner=%d/n", answer);<br /> return;<br /> }</p><p> const void Example::getExampleService()<br /> {<br /> sp<IServiceManager> sm = defaultServiceManager();<br /> binder = sm->getService(String16("byn.example"));<br /> LOGE("Example::getExampleService %p/n",sm.get());<br /> if (binder == 0) {<br /> LOGW("ExampleService not published, waiting...");<br /> return;<br /> }<br /> }<br />}; //namespace</p><p>using namespace android;</p><p>int main(int argc, char** argv)<br />{<br /> Example* p = new Example();<br /> p->add100(1);<br /> return 0;<br />}
# File: Example<br />LOCAL_PATH:= $(call my-dir)<br />include $(CLEAR_VARS)<br />LOCAL_SRC_FILES:= /<br />Example.cpp<br />LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)<br />LOCAL_SHARED_LIBRARIES := /<br />libutils libbinder libExample<br />LOCAL_PRELINK_MODULE := false<br />LOCAL_MODULE := Example</p><p>include $(BUILD_EXECUTABLE)
在/framework/android/src/frameworks/base下面建立一個檔案夾Example,將以上三個檔案複製到該檔案夾中。
Build整個Android系統,這裡一共會在系統中產生三個檔案,分別是
/system/lib/libExample.so
/system/bin/ExampleServer
/system/bin/Example
然後啟動我們新添加的ExampleService系統服務,並啟動用戶端程式驗證運行結果。
$> adb shell
# cd /system/bin
# ./ExampleServer &
# ./Example
answer=101
在接下來的幾篇文章中,我們會以這個例子為基礎,深入分析一下Android系統中Binder機制的各個部分。
參考文獻:
1. 雲中漫步部落格:http://my.unix-center.net/~Simon_fu/
2. 如何撰寫自己的第一個核心服務--高煥堂:http://www.android1.net/Topic.aspx?BoardID=21&TopicID=990