編輯:關於Android編程
一、說明
Android系統中應用很廣泛的但也是最難理解的就是Binder機制了,從APP組被調到系統平台組後感覺需要學的東西更多了,思考的方式也有所改變,從是什麼轉變到為什麼(背後的設計思想和實現細節),初次接觸Framework感覺就是在於各種服務打交道,例如ActivityManagerService、WindowManagerService、PowerManagerService等等。要想短時間內就把這些都屢清楚是挺困難的一件事。但是萬變不離其宗,它們背後的設計思想應該差異不大,所以由簡入繁,先攻克其中較為簡單的一點,其他的就可以迎刃而解了。下面就以MediaService為例展開源碼(基於Android M 6.0版本)的分析,理解了Binder就能夠在很大程度上理解程序的運行流程。先簡單理解一下Binder通信模型,Binder框架定義了四個角色:Server,Client,ServiceManager(簡稱SMgr)以及Binder驅動。其中Server,Client,SMgr運行於用戶空間,驅動運行於內核空間。這四個角色的關系和互聯網類似:Server是服務器,Client是客戶終端,SMgr是域名服務器(DNS),驅動是路由器。
二、MediaService探究
MediaService是一個應用程序,其中我們只分析MediaPlayerService。
MediaService的源碼文件在:frameworks/av/media/mediaserver/main_mediaserver.cpp
int main(int argc __unused, char** argv)
{
......
sp proc(ProcessState::self());//獲得一個ProcessState實例
sp sm = defaultServiceManager();//得到一個ServiceManager對象
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();//初始化MediaPlayerService服務
ResourceManagerService::instantiate();
......
ProcessState::self()->startThreadPool();//像是啟動Process的線程池?
IPCThreadState::self()->joinThreadPool();//然後將自己加入到剛才的線程池?
}
sp,究竟是smart pointer還是strong pointer呢?就把它當做一個普通的指針看待,即sp<IServiceManager> –>IServiceManager*。sp是google為了方便C/C++程序員管理指針的分配和釋放的一套方法,類似JAVA的什麼WeakReference之類的。以後的分析中,sp就看成是XXX*就可以了。
2.1 ProcessState
第一個調用的函數是ProcessState::self(),然後賦值給了proc變量,程序運行完,proc會自動delete內部的內容,所以就自動釋放了先前分配的資源。
ProcessState位置在frameworks/native/libs/binder/ProcessState.cpp
spProcessState::self() { Mutex::Autolock _l(gProcessMutex);//鎖保護 if (gProcess != NULL) { return gProcess;//第一次進來肯定不走這兒 } gProcess = new ProcessState;//創建一個ProcessState對象 return gProcess;//這裡返回的是指針,但是函數返回的是sp ,所以把sp 看成是XXX*是可以的 } //再來看ProcessState構造函數,這個構造函數看來很重要 ProcessState::ProcessState() : mDriverFD(open_driver())//Android很多代碼都是這麼寫的,函數很重要,在下面分析。 , mVMStart(MAP_FAILED)//映射內存的起始地址 , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) , mExecutingThreadsCount(0) , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) , mThreadPoolStarted(false) , mThreadPoolSeq(1) { if (mDriverFD >= 0) { // XXX Ideally, there should be a specific define for whether we // have mmap (or whether we could possibly have the kernel module // availabla). #if !defined(HAVE_WIN32_IPC) // 為這個Binder提供一個虛擬地址空間塊來接收處理 //BINDER_VM_SIZE 定義為((2*1024*1024) - (4096 *2)) 2M-8K //將fd映射為內存,這樣內存的memcpy等操作就相當於write/read(fd)了 mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0); if (mVMStart == MAP_FAILED) { // *sigh* ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n"); close(mDriverFD); mDriverFD = -1; } #else mDriverFD = -1; #endif } LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened. Terminating."); } //open_driver,就是打開/dev/binder這個設備,這個是android在內核中搞的一個專門用於完成 //進程間通訊而設置的一個虛擬的設備。BTW,說白了就是內核的提供的一個機制,這個和我們用socket加NET_LINK方式和內核通訊是一個道理。 static int open_driver() { int fd = open("/dev/binder", O_RDWR); if (fd >= 0) { fcntl(fd, F_SETFD, FD_CLOEXEC); int vers = 0; status_t result = ioctl(fd, BINDER_VERSION, &vers); if (result == -1) { ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno)); close(fd); fd = -1; } if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) { ALOGE("Binder driver protocol does not match user space protocol!"); close(fd); fd = -1; } //#define DEFAULT_MAX_BINDER_THREADS 15 size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; //通過ioctl方式告訴內核,這個fd支持最大線程數是15個。 result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); } } else { ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno)); } return fd; }
到這裡Process::self就分析完了,這裡主要做了兩件事情:
(1)、打開/dev/binder設備,這樣的話就相當於和內核binder機制有了交互的通道
(2)、映射fd到內存,設備的fd傳進去後,估計這塊內存是和binder設備共享的
接下來,就到調用defaultServiceManager()地方了。
2.2 defaultServiceManager
defaultServiceManager位置在frameworks/native/libs/binder/IServiceManager.cpp中
spdefaultServiceManager() { if (gDefaultServiceManager != NULL) return gDefaultServiceManager; //又是一個單例,設計模式中叫singleton。 { AutoMutex _l(gDefaultServiceManagerLock); while (gDefaultServiceManager == NULL) { //真正的gDefaultServiceManager是在這裡創建的 gDefaultServiceManager = interface_cast ( ProcessState::self()->getContextObject(NULL)); if (gDefaultServiceManager == NULL) sleep(1); } } return gDefaultServiceManager; } //注: /*gDefaultServiceManager = interface_cast ( ProcessState::self()->getContextObject(NULL)); ProcessState::self,肯定返回的是剛才創建的gProcess,然後調用它的getContextObject,注意傳進去的是NULL,即0*/ //回到ProcessState類, sp ProcessState::getContextObject(const sp & /*caller*/) { return getStrongProxyForHandle(0); } //進入到getStrongProxyForHandle //注意這個參數的命名,handle。搞過windows的應該比較熟悉這個名字, //這是對資源的一種標示,其實說白了就是某個數據結構,保存在數組中,然後handle是它在這個數組中的索引。 sp ProcessState::getStrongProxyForHandle(int32_t handle) { sp result; AutoMutex _l(mLock); //確實,從數組中查找對應索引的資源,lookupHandleLocked這個就不說了,內部會返回一個handle_entry handle_entry* e = lookupHandleLocked(handle); //下面是 handle_entry 的結構 /* struct handle_entry { IBinder* binder; RefBase::weakref_type* refs;//這個不知道是什麼 }; */ if (e != NULL) { //如果目前沒有我們所查找的,就創建一個新的bpbinder, //或者我們無法獲得這個當前的弱引用。可以在getweakproxyforhandle()中查看更多關於這個的信息。 IBinder* b = e->binder;//第一次進來,肯定為空 if (b == NULL || !e->refs->attemptIncWeak(this)) { if (handle == 0) { //上下文管理器的特殊情況 //上下文管理器是我們創建一個BpBinder proxy代理在沒有持有一個引用的情況下的唯一對象。 //進行一次虛擬處理來確保上下文管理器在我們創建第一個本地引用之前已經被注冊。 //如果上下文管理器不是當前這個就已經為BpBinder創建了一個本地引用, //那麼這個驅動將不會提供該引用給這個上下文管理器,並且這個驅動API不會返回任何狀態 // Note that this is not race-free if the context manager // dies while this code runs. // // TODO: add a driver API to wait for context manager, or // stop special casing handle 0 for context manager and add // a driver API to get a handle to the context manager with // proper reference counting. Parcel data; status_t status = IPCThreadState::self()->transact( 0, IBinder::PING_TRANSACTION, data, NULL, 0); if (status == DEAD_OBJECT) return NULL; } b = new BpBinder(handle); //在這裡創建了一個新的BpBinder e->binder = b; if (b) e->refs = b->getWeakRefs(); result = b; } else { // This little bit of nastyness is to allow us to add a primary // reference to the remote proxy when this team doesn't have one // but another team is sending the handle to us. result.force_set(b); e->refs->decWeak(this); } } return result;//返回剛才創建的BpBinder。 } //到這裡,是不是有點迷糊了?函數調用太深的時候,就容易忘記。 /*我們是從gDefaultServiceManager = interface_cast ( ProcessState::self()->getContextObject(NULL)); 開始搞的,現在,這個函數調用將變成 gDefaultServiceManager = interface_cast (new BpBinder(0));*/
BpBinder又是個什麼東東?Android名字起得太眼花缭亂了。
還是繼續把層層深入的函數調用棧化繁為簡。先看看BpBinder的構造函數。
2.3 BpBinder
BpBinder位置在frameworks/native/libs/binder/BpBinder.cpp中。
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)//注意,接上述內容,這裡調用的時候傳入的是0,
/*SMgr提供的Binder比較特殊,它沒有名字也不需要注冊,
其次這個Binder的引用在所有Client中都固定為0而無須通過其它手段獲得。
也就是說,一個Server若要向SMgr注冊自己Binder就必需通過0這個引用號和SMgr的Binder通信。
類比網絡通信,0號引用就好比域名服務器的地址,你必須預先手工或動態配置好。
要注意這裡說的Client是相對SMgr而言的,一個應用程序可能是個提供服務的Server,但對SMgr來說它仍然是個Client。*/
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);//竟然到IPCThreadState::self()
}
//這裡一塊說說,IPCThreadState::self估計應該又是一個singleton吧?
//該文件位置在frameworks/native/libs/binder/IPCThreadState.cpp
IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS) {//第一次進來為false
restart:
const pthread_key_t k = gTLS;
//TLS是Thread Local Storage的意思,不懂得自己去google下它的作用吧。這裡只需要
//知道這種空間每個線程有一個,而且線程間不共享這些空間,好處是?
//就可以免去同步了。在這個線程,我就用這個線程的東西,反正別的線程獲取不到其他線程TLS中的數據。
//從線程本地存儲空間中獲得保存在其中的IPCThreadState對象
//這段代碼寫法很晦澀,只有pthread_getspecific,那麼肯定有地方調用pthread_setspecific。
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState;
}
#ifdef _MTK_ENG_BUILD_
if (gShutdown) {
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(gTLS);
ALOGD("IPCThreadState 0x%p, gTLS:%d gHaveTLS:%d\n", &st, gTLS, gHaveTLS);
return NULL;
}
#else
if (gShutdown) return NULL;
#endif
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
if (pthread_key_create(&gTLS, threadDestructor) != 0) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;//少見的goto語句,直接跳轉到restart 去創建IPCThreadState
}
//這裡是構造函數,在構造函數裡邊pthread_setspecific
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(gettid()),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
//mIn,mOut是兩個Parcel,干嘛用的啊?把它看成是命令的buffer吧。
mOut.setDataCapacity(256);
}
new BpBinder就算完了。到這裡,我們創建了些什麼呢?
(1)ProcessState有了。
(2)IPCThreadState有了,而且是主線程的。
(3)BpBinder有了,內部handle值為0
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));
終於回到原點了!
interface_cast,我第一次接觸的時候,把它看做類似的static_cast一樣的東西,然後死活也搞不明白 BpBinder*指針怎麼能強轉為IServiceManager*,跟蹤進入interface_cast
IInterface.h位於frameworks/native/include/binder/IInterface.h
templateinline sp interface_cast(const sp & obj) { return INTERFACE::asInterface(obj); } 所以,上面等價於: inline sp interface_cast(const sp & obj) { return IServiceManager::asInterface(obj); } 看來,只能跟到IServiceManager了。 IServiceManager.h位於frameworks/native/include/binder/IServiceManager.h 看看它是如何定義的:
2.4 IServiceManager
class IServiceManager : public IInterface
{
//ServiceManager,字面上理解就是Service管理類,管理什麼?增加服務,查詢服務等
//這裡僅列出增加服務addService函數
public:
DECLARE_META_INTERFACE(ServiceManager);
virtual status_t addService( const String16& name,
const sp& service,
bool allowIsolated = false) = 0;
/*DECLARE_META_INTERFACE(ServiceManager)??
和MFC類似,有DELCARE肯定有IMPLEMENT,
這兩個宏DECLARE_META_INTERFACE和IMPLEMENT_META_INTERFACE(INTERFACE, NAME)都在剛才的IInterface.h中定義。
我們先看看DECLARE_META_INTERFACE這個宏往IServiceManager加了什麼?*/
//下面是DECLARE宏
#define DECLARE_META_INTERFACE(INTERFACE) \
static const android::String16 descriptor; \
static android::sp asInterface( \
const android::sp& obj); \
virtual const android::String16& getInterfaceDescriptor() const; \
I##INTERFACE(); \
virtual ~I##INTERFACE();
//我們把它兌現到IServiceManager就是:
static const android::String16 descriptor;//增加一個描述字符串
static android::sp< IServiceManager > asInterface(const android::sp&
obj) //增加一個asInterface函數
virtual const android::String16& getInterfaceDescriptor() const;//增加一個get函數估計其返回值就是descriptor這個字符串
IServiceManager (); \
virtual ~IServiceManager();//增加構造和虛析購函數...
//下面是IMPLEMENT宏的定義
#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::asInterface( \
const android::sp& obj) \
{ \
android::sp intr; \
if (obj != NULL) { \
intr = static_cast( \
obj->queryLocalInterface( \
I##INTERFACE::descriptor).get()); \
if (intr == NULL) { \
intr = new Bp##INTERFACE(obj); \
} \
} \
return intr; \
} \
I##INTERFACE::I##INTERFACE() { } \
I##INTERFACE::~I##INTERFACE() { }
//IMPLEMENT宏兌現到IServiceManager
見IServiceManager.cpp。位於frameworks/native/libs/binder/IServiceManager.cpp
//下面是這個宏的定義的使用
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");
//趕緊兌現一下IMPLEMENT宏吧
const
android::String16 IServiceManager::descriptor(“android.os.IServiceManager”);
const android::String16& IServiceManager::getInterfaceDescriptor() const
{
return IServiceManager::descriptor;//返回上面那個android.os.IServiceManager
}
android::sp IServiceManager::asInterface(
const android::sp& obj)
{
android::sp intr;
if (obj != NULL) {
intr = static_cast(
obj->queryLocalInterface(IServiceManager::descriptor).get());
if (intr == NULL) {
intr = new BpServiceManager(obj);
}
}
return intr;
}
IServiceManager::IServiceManager () { }
IServiceManager::~ IServiceManager() { }
/*asInterface是這麼搞的,趕緊分析下吧,還是不知道interface_cast怎麼把BpBinder*轉成了IServiceManager
我們剛才解析過的interface_cast(new BpBinder(0)),
原來就是調用asInterface(new BpBinder(0))*/
android::sp IServiceManager::asInterface(
const android::sp& obj)
{
android::sp intr;
if (obj != NULL) {
....
intr = new BpServiceManager(obj);
//終於看到和IServiceManager相關的東西了,看來實際返回的是BpServiceManager(new BpBinder(0));
}
}
return intr;
}
BpServiceManager是個什麼東東?p是什麼個意思?
2.5 BpServiceManager
p是proxy即代理的意思,Bp就是BinderProxy,BpServiceManager,就是SM的Binder代理。既然是代理,那肯定希望對用戶是透明的,那就是說頭文件裡邊不會有這個Bp的定義,接下來看。
BpServiceManager就在剛才的IServiceManager.cpp中定義。
class BpServiceManager : public BpInterface{ //這種繼承方式,表示同時繼承BpInterface和IServiceManager, //這樣IServiceManger的addService必然在這個類中實現 public: //注意構造函數參數的命名 impl,難道這裡使用了Bridge模式?真正完成操作的是impl對象? //這裡傳入的impl就是new BpBinder(0) BpServiceManager(const sp & impl) : BpInterface (impl) { } ...... virtual status_t addService(const String16& name, const sp & 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; } ...... //基類BpInterface的構造函數見frameworks/native/include/binder/IInterface.h //(經過兌現後)這裡的參數又叫remote,真是害人不淺。 inline BpInterface ::BpInterface(const sp & remote) : BpRefBase(remote) { } };
Binder.cpp位於frameworks/native/libs/binder/Binder.cpp
BpRefBase::BpRefBase(const sp& o) : mRemote(o.get()), mRefs(NULL), mState(0) //o.get(),這個是sp類的獲取實際數據指針的一個方法,你只要知道 //它返回的是sp 中xxx* 指針就行 { extendObjectLifetime(OBJECT_LIFETIME_WEAK); //mRemote就是剛才的BpBinder(0) if (mRemote) { mRemote->incStrong(this); // Removed on first IncStrong(). mRefs = mRemote->createWeak(this); // Held for our entire lifetime. } }
好了,到這裡,我們知道了:
sp<IServiceManager> sm = defaultServiceManager(); 返回的實際是BpServiceManager,它的remote對象是BpBinder,傳入的那個handle參數是0。
現在重新回到MediaService。
int main(int argc __unused, char** argv)
{
......
sp proc(ProcessState::self());//獲得一個ProcessState實例
sp sm = defaultServiceManager();//得到一個ServiceManager對象
//上面的講解已經完了
MediaPlayerService::instantiate();//初始化MediaPlayerService服務
//這裡值得推敲!
......
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
到這裡,我們把binder設備打開了,得到一個BpServiceManager對象,這表明我們可以和SM打交道了。
2.6 MediaPlayerService
那下面我們看看後續又干了什麼?以MediaPlayerService為例。
它位於frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
/*傳進去服務的名字,傳進去new出來的對象*/
}
//defaultServiceManager返回的是剛才創建的BpServiceManager調用它的addService函數。
MediaPlayerService::MediaPlayerService()
{
ALOGV("MediaPlayerService created");
MM_LOGI("created");
mNextConnId = 1;
mBatteryAudio.refCount = 0;
for (int i = 0; i < NUM_AUDIO_DEVICES; i++) {
mBatteryAudio.deviceOn[i] = 0;
mBatteryAudio.lastTime[i] = 0;
mBatteryAudio.totalTime[i] = 0;
}
// speaker is on by default
mBatteryAudio.deviceOn[SPEAKER] = 1;
// reset battery stats
// if the mediaserver has crashed, battery stats could be left
// in bad state, reset the state upon service start.
BatteryNotifier& notifier(BatteryNotifier::getInstance());
notifier.noteResetVideo();
notifier.noteResetAudio();
MediaPlayerFactory::registerBuiltinFactories();
}
MediaPlayerService從BnMediaPlayerService派生
見frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
class MediaPlayerService : public BnMediaPlayerService
MediaPlayerService從BnMediaPlayerService派生,BnXXX,BpXXX,快暈了。
Bn 是Binder Native的含義,是和Bp相對的,Bp的p是proxy代理的意思,那麼另一端一定有一個和代理打交道的東西,這個就是Bn。
講到這裡會有點亂喔。先分析下,到目前為止都構造出來了什麼。
BpServiceManager
BnMediaPlayerService
這兩個東西不是相對的兩端,從BnXXX就可以判斷,BpServiceManager對應的應該是BnServiceManager,BnMediaPlayerService對應的應該是BpMediaPlayerService。
我們現在是創建了BnMediaPlayerService,想把它加入到系統的中去。
我們創建一個新的Service—BnMediaPlayerService,想把它告訴ServiceManager。
那我怎麼和ServiceManager通訊呢?利用BpServiceManager。所以嘛,我們調用了BpServiceManager的addService函數!
為什麼要搞個ServiceManager來呢?這個和Android機制有關系。所有Service都需要加入到ServiceManager來管理。同時也方便了Client來查詢系統存在哪些Service,ServiceManager就相當於我們的DNS域名服務器。沒看見我們傳入了字符串嗎?”media.player”就相當於我們的網絡域名,這樣就可以通過Human Readable的字符串來查找Service了。
2.7 addService
addService是調用的BpServiceManager的函數。前面略去沒講,現在我們看看。
virtual status_t addService(const String16& name, const sp& service, bool allowIsolated) { Parcel data, reply; //data是發送到BnServiceManager的命令包 //先把Interface名字寫進去,也就是什麼android.os.IServiceManager data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); //再把新service的名字寫進去 叫media.player data.writeString16(name); //把新服務service—>就是MediaPlayerService寫到命令中 data.writeStrongBinder(service); data.writeInt32(allowIsolated ? 1 : 0); //調用remote的transact函數 status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); return err == NO_ERROR ? reply.readExceptionCode() : err; }
remote(){ return mRemote; }
見frameworks/native/include/binder/Binder.h
class BpRefBase : public virtual RefBase
{
protected:
BpRefBase(const sp& 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;
volatile int32_t mState;
};
};
這裡的mRemote就是最初創建的BpBinder..
到那裡去看看:
//BpBinder的位置在frameworks/native/libs/binder/BpBinder.cpp
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) {
//又繞回去了,調用IPCThreadState的transact。
//注意:這裡的mHandle為0,code是ADD_SERVICE_TRANSACTION,data是命令包
//reply是回復包,flags=0
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
//再看看IPCThreadState的transact函數吧
//見frameworks/native/libs/binder/IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck();
flags |= TF_ACCEPT_FDS;
//......
if (err == NO_ERROR) {
//調用writeTransactionData 發送數據
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
//......等回復
err = waitForResponse(NULL, NULL);
}
......
return err;
}
//再進一步,瞧瞧writeTransactionData
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;
tr.target.ptr = 0; /* Don't pass uninitialized stack data to a remote process */
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
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_transaction_data,然後
//寫到mOut中,mOut是命令的緩沖區,也是一個Parcel
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
//僅僅寫到了Parcel中,Parcel好像沒和/dev/binder設備有什麼關聯啊?
//那只能在另外一個地方寫到binder設備中去了。
return NO_ERROR;
}
//就是在waitForResponse中
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
uint32_t cmd;
int32_t err;
while (1) {
//talkWithDriver,應該是這裡了
if ((err=talkWithDriver()) < NO_ERROR) break;
err = mIn.errorCheck();
if (err < NO_ERROR) break;
if (mIn.dataAvail() == 0) continue;
//這裡開始操作mIn了,看來talkWithDriver中
//把mOut發出去,然後從driver中讀到數據放到mIn中了。
cmd = (uint32_t)mIn.readInt32();
}
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
......
return err;
}
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
binder_write_read bwr;
......
//中間東西太復雜了,不就是把mOut數據和mIn接收數據的處理後賦值給bwr嗎?
status_t err;
do {
......
//用ioctl來讀寫
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else {
err = -errno;
}
if (mProcess->mDriverFD <= 0) {
err = -EBADF;
}
} while (err == -EINTR);
if (err >= NO_ERROR) {
......
//到這裡,回復數據就在bwr中了,bwr接收回復數據的buffer就是mIn提供的
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
return NO_ERROR;
}
return err;
}
好了,到這裡,我們發送addService的流程就徹底走完了。
BpServiceManager發送了一個addService命令到BnServiceManager,然後收到回復。
先繼續我們的main函數。
int main(int argc __unused, char** argv)
{
......
sp proc(ProcessState::self());//獲得一個ProcessState實例
sp sm = defaultServiceManager();//得到一個ServiceManager對象
//該函數內部調用addService,把MediaPlayerService信息 add到ServiceManager中
MediaPlayerService::instantiate();//初始化MediaPlayerService服務
......
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
這裡有個容易搞暈的地方:
MediaPlayerService是一個BnMediaPlayerService,那麼它是不是應該等著
BpMediaPlayerService來和他交互呢?但是我們沒看見MediaPlayerService有打開binder設備的操作啊!
這個嘛,到底是繼續addService操作的另一端BnServiceManager還是先說
BnMediaPlayerService呢?
還是先說BnServiceManager吧。順便把系統的Binder架構說說。
2.8 BnServiceManager
上面說了,defaultServiceManager返回的是一個BpServiceManager,通過它可以把命令請求發送到binder設備,而且handle的值為0。那麼,系統的另外一端肯定有個接收命令的,那又是誰呢?
很可惜啊,BnServiceManager不存在,但確實有一個程序完成了BnServiceManager的工作,那就是service.exe(如果在windows上一定有exe後綴,叫service的名字太多了,這裡加exe就表明它是一個程序)
位置在frameworks/native/cmds/servicemanager/service_manager.c中。
int main(int argc, char **argv)
{
struct binder_state *bs;
//應該是打開binder設備吧?
bs = binder_open(128*1024);
if (!bs) {
ALOGE("failed to open binder driver\n");
return -1;
}
//成為manager
if (binder_become_context_manager(bs)) {
ALOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
......
//處理BpServiceManager發過來的命令
binder_loop(bs, svcmgr_handler);
return 0;
}
//看看binder_open是不是和我們猜得一樣?
//見frameworks/native/cmds/servicemanager/binder.c
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;
struct binder_version vers;
bs = malloc(sizeof(*bs));
......
bs->fd = open("/dev/binder", O_RDWR);//確實如此
......
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
......
return bs;
fail_map:
close(bs->fd);
fail_open:
free(bs);
return NULL;
}
//再看看binder_become_context_manager
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);//把自己設為MANAGER
}
//binder_loop 肯定是從binder設備中讀請求,寫回復的這麼一個循環吧?
void binder_loop(struct binder_state *bs, binder_handler func)
{
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {//果然是循環
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
break;
}
//收到請求了,解析命令
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
......
}
}
//這個...後面還要說嗎??
//恩,最後有一個類似handleMessage的地方處理各種各樣的命令。這個就是
//svcmgr_handler,就在在frameworks/native/cmds/servicemanager/service_manager.c中
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
struct svcinfo *si;
uint16_t *s;
size_t len;
uint32_t handle;
uint32_t strict_policy;
int allow_isolated;
......
s = bio_get_string16(msg, &len);
......
switch(txn->code) {
......
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
if (s == NULL) {
return -1;
}
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
......
}
//其中,do_add_service真正添加BnMediaService信息
int do_add_service(struct binder_state *bs,
const uint16_t *s, size_t len,
uint32_t handle, uid_t uid, int allow_isolated,
pid_t spid)
{
struct svcinfo *si;
......
si = find_svc(s, len);//s是一個list
if (si) {
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
str8(s, len), handle, uid);
return -1;
}
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist;
svclist = si; //這個svclist是一個列表,保存了當前注冊到ServiceManager中的信息
}
binder_acquire(bs, handle);
//這個嗎。當這個Service退出後,我希望系統通知我一下,好釋放上面malloc出來的資源。大概就是干這個事情的。
binder_link_to_death(bs, handle, &si->death);
return 0;
}
對於addService來說,看來ServiceManager把信息加入到自己維護的一個服務列表中了。
2.9 ServiceManager存在的意義
為何需要一個這樣的東西呢?
原來,Android系統中Service信息都是先add到ServiceManager中,由ServiceManager來集中管理,這樣就可以查詢當前系統有哪些服務。而且,Android系統中某個服務例如MediaPlayerService的客戶端想要和MediaPlayerService通訊的話,必須先向ServiceManager查詢MediaPlayerService的信息,然後通過ServiceManager返回的東西再來和MediaPlayerService交互。
畢竟,要是MediaPlayerService身體不好,老是掛掉的話,客戶的代碼就麻煩了,就不知道後續新生的MediaPlayerService的信息了,所以只能這樣:
MediaPlayerService向SM注冊
MediaPlayerClient查詢當前注冊在SM中的MediaPlayerService的信息
根據這個信息,MediaPlayerClient和MediaPlayerService交互
另外,ServiceManager的handle標示是0,所以只要往handle是0的服務發送消息了,最終都會被傳遞到ServiceManager中去。
三、 MediaService的運行
上一節的知識,我們知道了:
defaultServiceManager得到了BpServiceManager,然後MediaPlayerService 實例化後,調用BpServiceManager的addService函數
這個過程中,是service_manager收到addService的請求,然後把對應信息放到自己保存的一個服務list中
到這兒,我們可看到,service_manager有一個binder_looper函數,專門等著從binder中接收請求。雖然service_manager沒有從BnServiceManager中派生,但是它肯定完成了BnServiceManager的功能。
同樣,我們創建了MediaPlayerService即BnMediaPlayerService,那它也應該:
打開binder設備
也搞一個looper循環,然後坐等請求service
service,這個和網絡編程中的監聽socket的工作很像嘛!
好吧,既然MediaPlayerService的構造函數沒有看到顯示的打開binder設備,那麼我們看看它的父類即BnXXX又到底干了些什麼呢?
3.1 MediaPlayerService打開binder
見frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
class MediaPlayerService : public BnMediaPlayerService
{
// MediaPlayerService從BnMediaPlayerService派生
......
}
//而BnMediaPlayerService從BnInterface和IMediaPlayerService同時派生
見frameworks/av/include/media/IMediaPlayerService.h
class BnMediaPlayerService: public BnInterface{ public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); }; //看起來,BnInterface似乎更加和打開設備相關。 //見frameworks/native/include/binder/IInterface.h template class BnInterface : public INTERFACE, public BBinder { public: virtual sp queryLocalInterface(const String16& _descriptor); virtual const String16& getInterfaceDescriptor() const; protected: virtual IBinder* onAsBinder(); }; //兌現後變成 class BnInterface : public IMediaPlayerService, public BBinder BBinder?BpBinder?是不是和BnXXX以及BpXXX對應的呢?如果是,為什麼又叫BBinder呢? BBinder::BBinder() : mExtras(NULL) { //沒有打開設備的地方啊? }
回想下,我們的Main_MediaService程序,有哪裡打開過binder嗎?
int main(int argc __unused, char** argv)
{
......
//對啊,我在ProcessState中不是打開過binder了嗎?
sp proc(ProcessState::self());
sp sm = defaultServiceManager();
MediaPlayerService::instantiate();
......
}
3.2 looper
原來打開binder設備的地方是和進程相關的,一個進程打開一個就可以了。那麼,我在哪裡進行類似的消息循環looper操作呢?
......
//難道是下面兩個?
ProcessState::self()->startThreadPool();//像是啟動Process的線程池?
IPCThreadState::self()->joinThreadPool();//然後將自己加入到剛才的線程池?
//看看startThreadPool吧
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp t = new PoolThread(isMain);//isMain是TRUE
//創建線程池,然後run起來,和java的Thread何其像也。
t->run(name.string());
}
}
//PoolThread從Thread類中派生,那麼此時會產生一個線程嗎?看看PoolThread和Thread的構造吧
class PoolThread : public Thread
{
public:
PoolThread(bool isMain)
: mIsMain(isMain)
{
}
......
};
//Thread的構造見system/core/libutils/Threads.cpp
Thread::Thread(bool canCallJava)//canCallJava默認值是true
: mCanCallJava(canCallJava),
mThread(thread_id_t(-1)),
mLock("Thread::mLock"),
mStatus(NO_ERROR),
mExitPending(false), mRunning(false)
#ifdef HAVE_ANDROID_OS
, mTid(-1)
#endif
{
}
//這個時候還沒有創建線程呢。然後調用PoolThread::run,實際調用了基類的run。
status_t Thread::run(const char* name, int32_t priority, size_t stack)
{
......
bool res;
if (mCanCallJava) {
res = createThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
} else {
res = androidCreateRawThreadEtc(_threadLoop,
this, name, priority, stack, &mThread);
}
......
return NO_ERROR;
}
//createThreadEtc見system/core/include/utils/AndroidThreads.h
inline bool createThreadEtc(thread_func_t entryFunction,
void *userData,
const char* threadName = "android:unnamed_thread",
int32_t threadPriority = PRIORITY_DEFAULT,
size_t threadStackSize = 0,
thread_id_t *threadId = 0)
{
return androidCreateThreadEtc(entryFunction, userData, threadName,
threadPriority, threadStackSize, threadId) ? true : false;
}
//終於,在run函數中,創建線程了。從此主線程執行
IPCThreadState::self()->joinThreadPool();
//新開的線程執行_threadLoop
//我們先看看_threadLoop
int Thread::_threadLoop(void* user)
{
Thread* const self = static_cast(user);
sp strong(self->mHoldSelf);
wp weak(strong);
self->mHoldSelf.clear();
......
do {
bool result;
......
if (result && !self->exitPending()) {
result = self->threadLoop();//調用自己的threadLoop
}
} else {
result = self->threadLoop();
}
......
return 0;
}
//我們是PoolThread對象,所以調用PoolThread的threadLoop函數
virtual bool threadLoop()
{
IPCThreadState* ipc = IPCThreadState::self();
//mIsMain為true。
//而且注意,這是一個新的線程,所以必然會創建一個
//新的IPCThreadState對象(記得線程本地存儲嗎?TLS),然後
if(ipc)
ipc->joinThreadPool(mIsMain);
//IPCThreadState::self()->joinThreadPool(mIsMain);
return false;
}
//主線程和工作線程都調用了joinThreadPool,看看這個干嘛了!
void IPCThreadState::joinThreadPool(bool isMain)
{
mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
set_sched_policy(mMyThreadId, SP_FOREGROUND);
status_t result;
do {
processPendingDerefs();
// now get the next command to be processed, waiting if necessary
result = getAndExecuteCommand();
......
// Let this thread exit the thread pool if it is no longer
// needed and it is not the main process thread.
if(result == TIMED_OUT && !isMain) {
break;
}
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
//看到沒?有loop了,但是好像是有兩個線程都執行了這個!這裡有兩個消息循環?
//getAndExecuteCommand中調用了executeCommand
status_t IPCThreadState::getAndExecuteCommand()
{
status_t result;
int32_t cmd;
result = talkWithDriver();
if (result >= NO_ERROR) {
size_t IN = mIn.dataAvail();
if (IN < sizeof(int32_t)) return result;
cmd = mIn.readInt32();
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount++;
pthread_mutex_unlock(&mProcess->mThreadCountLock);
result = executeCommand(cmd);
pthread_mutex_lock(&mProcess->mThreadCountLock);
mProcess->mExecutingThreadsCount--;
pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
pthread_mutex_unlock(&mProcess->mThreadCountLock);
set_sched_policy(mMyThreadId, SP_FOREGROUND);
}
return result;
}
//下面看看executeCommand
status_t IPCThreadState::executeCommand(int32_t cmd)
{
BBinder* obj;
RefBase::weakref_type* refs;
status_t result = NO_ERROR;
switch ((uint32_t)cmd) {
case BR_TRANSACTION:
{
binder_transaction_data tr;
result = mIn.read(&tr, sizeof(tr));
//來了一個命令,解析成BR_TRANSACTION,然後讀取後續的信息
Parcel reply;
status_t error;
if (tr.target.ptr) {
//這裡用的是BBinder。
if (reinterpret_cast(
tr.target.ptr)->attemptIncStrong(this)) {
error = reinterpret_cast(tr.cookie)->transact(tr.code, buffer,
&reply, tr.flags);
reinterpret_cast(tr.cookie)->decStrong(this);
} else {
error = UNKNOWN_TRANSACTION;
}
}
}
//讓我們看看BBinder的transact函數干嘛了
//見frameworks/native/libs/binder/Binder.cpp
status_t BBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
status_t err = NO_ERROR;
switch (code) {
case PING_TRANSACTION:
reply->writeInt32(pingBinder());
break;
default:
//就是調用自己的onTransact函數嘛
err = onTransact(code, data, reply, flags);
break;
}
if (reply != NULL) {
reply->setDataPosition(0);
}
return err;
}
//BnMediaPlayerService從BnInterface派生,BnInterface從BBinder派生,所以會調用到它的onTransact函數
//終於水落石出了,讓我們看看BnMediaPlayerServcice的onTransact函數。
status_t BnMediaPlayerService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
// BnMediaPlayerService從BBinder和IMediaPlayerService派生,所有IMediaPlayerService
//看到下面的switch沒?所有IMediaPlayerService提供的函數都通過命令類型來區分
switch (code) {
case CREATE: {
CHECK_INTERFACE(IMediaPlayerService, data, reply);
//create是一個虛函數,由MediaPlayerService來實現!!
//見frameworks/av/media/libmediaplayerservice/MediaPlayerService.h
//MediaPlayerService從BnMediaPlayerService派生
sp client =
interface_cast(data.readStrongBinder());
int audioSessionId = data.readInt32();
sp player = create(client, audioSessionId);
reply->writeStrongBinder(IInterface::asBinder(player));
return NO_ERROR;
} break;
......
}
}
其實,到這裡,我們就明白了。BnXXX的onTransact函數收取命令,然後派發到派生類的函數,由他們完成實際的工作。
說明:
這裡有點特殊,startThreadPool和joinThreadPool完後確實有兩個線程,主線程和工作線程,而且都在做消息循環。為什麼要這麼做呢?他們參數isMain都是true。不知道google搞什麼。難道是怕一個線程工作量太多,所以搞兩個線程來工作?這種解釋應該也是合理的。
網上有人測試過把最後一句屏蔽掉,也能正常工作。但是難道主線程退出了,程序還能不退出嗎?這個…管它的,反正知道有兩個線程在那處理就行了。
四、 MediaPlayerClient
這節講講MediaPlayerClient怎麼和MediaPlayerService交互。
使用MediaPlayerService的時候,先要創建它的BpMediaPlayerService。我們看看一個例子
見frameworks/av/media/libmedia/IMediaDeathNotifier.cpp
// establish binder interface to MediaPlayerService /*static*/const spIMediaDeathNotifier::getMediaPlayerService() { ALOGV("getMediaPlayerService"); Mutex::Autolock _l(sServiceLock); if (sMediaPlayerService == 0) { sp sm = defaultServiceManager(); sp binder; do { //向SM查詢對應服務的信息,返回binder binder = sm->getService(String16("media.player")); if (binder != 0) { break; } ALOGW("Media player service not published, waiting..."); usleep(500000); // 0.5 s } while (true); if (sDeathNotifier == NULL) { sDeathNotifier = new DeathNotifier(); } binder->linkToDeath(sDeathNotifier); //通過interface_cast,將這個binder轉化成BpMediaPlayerService //注意,這個binder只是用來和binder設備通訊用的, //實際上和IMediaPlayerService的功能一點關系都沒有。 //還記得我說的Bridge模式嗎? //BpMediaPlayerService用這個binder和BnMediaPlayerService通訊。 sMediaPlayerService = interface_cast (binder); } ALOGE_IF(sMediaPlayerService == 0, "no media player service!?"); return sMediaPlayerService; }
為什麼反復強調這個Bridge?其實也不一定是Bridge模式,但是我真正想說明的是:
Binder其實就是一個和binder設備打交道的接口,而上層IMediaPlayerService只不過把它當做一個類似socket使用罷了。我以前經常把binder和上層類IMediaPlayerService的功能混到一起去。所以有一點請注意:
4.1 Native層
剛才那個getMediaPlayerService代碼是C++層的,但是整個使用的例子確實JAVA->JNI層的調用。如果我要寫一個純C++的程序該怎麼辦?
int main()
{
getMediaPlayerService();//直接調用這個函數能獲得BpMediaPlayerService嗎?
//不能,為什麼?因為我還沒打開binder驅動吶!但是你在JAVA應用程序裡邊卻有google已經替你封裝好了。
//所以,純native層的代碼,必須也得像下面這樣處理:
sp proc(ProcessState::self());//這個其實不是必須的,因為
//好多地方都需要這個,所以自動也會創建.
getMediaPlayerService();
//還得起消息循環吶,否則如果Bn那邊有消息通知你,你怎麼接受得到呢?
ProcessState::self()->startThreadPool();
//至於主線程是否也需要調用消息循環,就看個人而定了。不過一般是等著接收其他來源的消息,例如socket發來的命令,然後控制MediaPlayerService就可以了。
}
五、實現自己的Service
好了,我們學習了這麼多Binder的東西,那麼想要實現一個自己的Service該咋辦呢?
如果是純C++程序的話,肯定得類似main_MediaService那樣干了。
int main()
{
sp proc(ProcessState::self());
sp sm = defaultServiceManager();
sm->addService(“service.name”,new XXXService());
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
//看看XXXService怎麼定義呢?
//我們需要一個Bn,需要一個Bp,而且Bp不用暴露出來。那麼就在BnXXX.cpp中一起實現好了。
//另外,XXXService提供自己的功能,例如getXXX調用
5.1 定義XXX接口
XXX接口是和XXX服務相關的,例如提供getXXX,setXXX函數,和應用邏輯相關。
需要從IInterface派生
class IXXX: public IInterface
{
public:
DECLARE_META_INTERFACE(XXX);//申明宏
virtual getXXX() = 0;
virtual setXXX() = 0;
}//這是一個接口。
5.2 定義BnXXX和BpXXX
為了把IXXX加入到Binder結構,需要定義BnXXX和對客戶端透明的BpXXX。
其中BnXXX是需要有頭文件的。BnXXX只不過是把IXXX接口加入到Binder架構中來,而不參與實際的getXXX和setXXX應用層邏輯。
這個BnXXX定義可以和上面的IXXX定義放在一塊。分開也行。
class BnXXX: public BnInterface{ public: virtual status_t onTransact( uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0); //由於IXXX是個純虛類,而BnXXX只實現了onTransact函數,所以BnXXX依然是一個純虛類 };
有了DECLARE,那我們在某個CPP中IMPLEMNT它吧。那就在IXXX.cpp中吧。
IMPLEMENT_META_INTERFACE(XXX, "android.xxx.IXXX");//IMPLEMENT宏
status_t BnXXX::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_XXX: {
CHECK_INTERFACE(IXXX, data, reply);
//讀請求參數
//調用虛函數getXXX()
return NO_ERROR;
} break; //SET_XXX類似
BpXXX也在這裡實現吧。
class BpXXX: public BpInterface{ public: BpXXX (const sp & impl) : BpInterface< IXXX >(impl) { } vitural getXXX() { Parcel data, reply; data.writeInterfaceToken(IXXX::getInterfaceDescriptor()); data.writeInt32(pid); remote()->transact(GET_XXX, data, &reply); return; } //setXXX類似 }
至此,Binder就算分析完了,大家看完後,應該能做到以下幾點:
如果需要寫自己的Service的話,總得知道系統是怎麼個調用你的函數。有2個線程在那不停得從binder設備中收取命令,然後調用你的函數。這是個多線程問題。
如果需要跟蹤bug的話,得知道從Client端調用的函數,是怎麼最終傳到到遠端的Service。這樣,對於一些函數調用,Client端跟蹤完了,我就知道轉到Service去看對應函數調用了。反正是同步方式。也就是Client一個函數調用會一直等待到Service返回為止。
Android Studio與SVN版本控制程序的協作使用指南
AndroidStudio 的SVN 安裝和使用方法與我以前用的其他IDE 都有很大差別,感覺特麻煩,網上相關資料很少,貌似現在 Git 比較流行,之前有用過 githu
Android 實現藍牙客戶端與服務器端通信
一、首先說明:藍牙通信必須用手機測試,因為avd裡沒有相關的硬件,會報錯!好了,看看最後的效果圖:二、概述:1.判斷是否支持BluetoothBluetoothAdapt
android 版本檢測 Android程序的版本檢測與更新實現介紹
做個網站的安卓客戶端,用戶安裝到自己手機上,如果我出了新版本怎麼辦呢?要有版本更新功能。 本來版本檢測最好可以自動進行。但如果每次開啟程序,都要先檢測一輪,是一種浪費,畢
Android(Lollipop/5.0) Material Design(一) 簡介
使用Material Design 需要api21,即Lollipop/5.0以上 Material Design 為應用提供了:一個新的主題,一些組合Vi