上一篇文章中我們討論瞭如何向系統註冊Service。本篇文章我們將討論如何使用這個已註冊的系統Service。
在本系列文章的第一篇中,客戶端應用程序使用如下兩條語句取得了ExampleService代理對象的引用。
- sp<IServiceManager> sm = defaultServiceManager();
- binder = sm->getService(String16("byn.example"));
第一句我們之前已經詳細解釋過了,全局函數defaultServiceManager()返回的是ServiceManager代理對象的引用。第二句話以ExampleService的方法名爲參數調用getService()方法,返回的是ExampleService代理對象的引用。這個過程和上一篇文章介紹的addService的過程是非常類似的,這裏就不詳細展開了。
客戶應用程序獲得了ExampleService代理對象的引用之後,通過如下語句調用服務:
- data.writeInt32(getpid());
- data.writeInt32(n);
- binder->transact(0, data, &reply);
第一句話寫入當前進程的進程ID,這裏只是爲了輸出log用,沒有實際意義;
第二句話寫入參數n;
最後一句話調用ExampleService代理對象的transact方法發送請求。第一個參數0是請求代碼(code),如果一個服務提供了多個API接口,那麼服務器端就通過這個參數區分調用的是哪一個API;第二個參數打包後的調用參數;最後一個參數保存返回值。因爲ExampleService代理對象繼承自BpBinder,所以這裏調用的是BpBinder::transact()方法,進而調用IPCThreadState::transact()方法。這個過程在上一篇文章中已經介紹過。
現在我們重點剖析一下服務器端的情況。
服務器端在向系統註冊服務之後,首先調用ProcessState::self()->startThreadPool()方法啓動一個線程池;然後調用IPCThreadState::self()->joinThreadPool()方法進入一個無限循環,等待其它進程的服務請求。我們看一下joinThreadPool方法的源代碼:
-
- void IPCThreadState::joinThreadPool(bool isMain)
- {
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL/n", (void*)pthread_self(), getpid());
-
- mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
-
- status_t result;
- do {
- int32_t cmd;
-
-
- if (mIn.dataPosition() >= mIn.dataSize()) {
- size_t numPending = mPendingWeakDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- RefBase::weakref_type* refs = mPendingWeakDerefs[i];
- refs->decWeak(mProcess.get());
- }
- mPendingWeakDerefs.clear();
- }
-
- numPending = mPendingStrongDerefs.size();
- if (numPending > 0) {
- for (size_t i = 0; i < numPending; i++) {
- BBinder* obj = mPendingStrongDerefs[i];
- obj->decStrong(mProcess.get());
- }
- mPendingStrongDerefs.clear();
- }
- }
-
-
- result = talkWithDriver();
- if (result >= NO_ERROR) {
- size_t IN = mIn.dataAvail();
- if (IN < sizeof(int32_t)) continue;
- cmd = mIn.readInt32();
- IF_LOG_COMMANDS() {
- alog << "Processing top-level Command: "
- << getReturnString(cmd) << endl;
- }
-
-
- result = executeCommand(cmd);
- }
-
-
-
-
-
- int my_id;
- #ifdef HAVE_GETTID
- my_id = gettid();
- #else
- my_id = getpid();
- #endif
- if (!set_sched_policy(my_id, SP_FOREGROUND)) {
-
- setpriority(PRIO_PROCESS, my_id, ANDROID_PRIORITY_NORMAL);
- }
-
-
-
- if(result == TIMED_OUT && !isMain) {
- break;
- }
- } while (result != -ECONNREFUSED && result != -EBADF);
-
- LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%p/n",
- (void*)pthread_self(), getpid(), (void*)result);
-
- mOut.writeInt32(BC_EXIT_LOOPER);
- talkWithDriver(false);
- }
在joinThreadPool()方法中,通過調用talkWithDriver方法與binder設備進行通信,通常Service進程會阻塞在這裏;一旦客戶請求到來,該方法返回,並調用後面的executeCommand()方法進行處理。我們看一下executeCommand()方法的源代碼:
-
- status_t IPCThreadState::executeCommand(int32_t cmd)
- {
- BBinder* obj;
- RefBase::weakref_type* refs;
- status_t result = NO_ERROR;
-
- switch (cmd) {
- case BR_ERROR:
- result = mIn.readInt32();
- break;
-
- case BR_OK:
- break;
-
- case BR_ACQUIRE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- LOG_ASSERT(refs->refBase() == obj,
- "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
- obj->incStrong(mProcess.get());
- IF_LOG_REMOTEREFS() {
- LOG_REMOTEREFS("BR_ACQUIRE from driver on %p", obj);
- obj->printRefs();
- }
- mOut.writeInt32(BC_ACQUIRE_DONE);
- mOut.writeInt32((int32_t)refs);
- mOut.writeInt32((int32_t)obj);
- break;
-
- case BR_RELEASE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- LOG_ASSERT(refs->refBase() == obj,
- "BR_RELEASE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
- IF_LOG_REMOTEREFS() {
- LOG_REMOTEREFS("BR_RELEASE from driver on %p", obj);
- obj->printRefs();
- }
- mPendingStrongDerefs.push(obj);
- break;
-
- case BR_INCREFS:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
- refs->incWeak(mProcess.get());
- mOut.writeInt32(BC_INCREFS_DONE);
- mOut.writeInt32((int32_t)refs);
- mOut.writeInt32((int32_t)obj);
- break;
-
- case BR_DECREFS:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
-
-
-
-
-
-
- mPendingWeakDerefs.push(refs);
- break;
-
- case BR_ATTEMPT_ACQUIRE:
- refs = (RefBase::weakref_type*)mIn.readInt32();
- obj = (BBinder*)mIn.readInt32();
-
- {
- const bool success = refs->attemptIncStrong(mProcess.get());
- LOG_ASSERT(success && refs->refBase() == obj,
- "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
- refs, obj, refs->refBase());
-
- mOut.writeInt32(BC_ACQUIRE_RESULT);
- mOut.writeInt32((int32_t)success);
- }
- break;
-
- case BR_TRANSACTION:
- {
- binder_transaction_data tr;
- result = mIn.read(&tr, sizeof(tr));
- LOG_ASSERT(result == NO_ERROR,
- "Not enough command data for brTRANSACTION");
- if (result != NO_ERROR) break;
-
- Parcel buffer;
- buffer.ipcSetDataReference(
- reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
- tr.data_size,
- reinterpret_cast<const size_t*>(tr.data.ptr.offsets),
- tr.offsets_size/sizeof(size_t), freeBuffer, this);
-
- const pid_t origPid = mCallingPid;
- const uid_t origUid = mCallingUid;
-
- mCallingPid = tr.sender_pid;
- mCallingUid = tr.sender_euid;
-
-
-
- Parcel reply;
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BR_TRANSACTION thr " << (void*)pthread_self()
- << " / obj " << tr.target.ptr << " / code "
- << TypeCode(tr.code) << ": " << indent << buffer
- << dedent << endl
- << "Data addr = "
- << reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer)
- << ", offsets addr="
- << reinterpret_cast<const size_t*>(tr.data.ptr.offsets) << endl;
- }
- if (tr.target.ptr) {
- sp<BBinder> b((BBinder*)tr.cookie);
- const status_t error = b->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
-
- } else {
- const status_t error = the_context_object->transact(tr.code, buffer, &reply, 0);
- if (error < NO_ERROR) reply.setError(error);
- }
-
-
-
-
- if ((tr.flags & TF_ONE_WAY) == 0) {
- LOG_ONEWAY("Sending reply to %d!", mCallingPid);
- sendReply(reply, 0);
- } else {
- LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
- }
-
- mCallingPid = origPid;
- mCallingUid = origUid;
-
- IF_LOG_TRANSACTIONS() {
- TextOutput::Bundle _b(alog);
- alog << "BC_REPLY thr " << (void*)pthread_self() << " / obj "
- << tr.target.ptr << ": " << indent << reply << dedent << endl;
- }
-
- }
- break;
-
- case BR_DEAD_BINDER:
- {
- BpBinder *proxy = (BpBinder*)mIn.readInt32();
- proxy->sendObituary();
- mOut.writeInt32(BC_DEAD_BINDER_DONE);
- mOut.writeInt32((int32_t)proxy);
- } break;
-
- case BR_CLEAR_DEATH_NOTIFICATION_DONE:
- {
- BpBinder *proxy = (BpBinder*)mIn.readInt32();
- proxy->getWeakRefs()->decWeak(proxy);
- } break;
-
- case BR_FINISHED:
- result = TIMED_OUT;
- break;
-
- case BR_NOOP:
- break;
-
- case BR_SPAWN_LOOPER:
- mProcess->spawnPooledThread(false);
- break;
-
- default:
- printf("*** BAD COMMAND %d received from Binder driver/n", cmd);
- result = UNKNOWN_ERROR;
- break;
- }
-
- if (result != NO_ERROR) {
- mLastError = result;
- }
-
- return result;
- }
這裏,函數會根據一系列枚舉值作相應的處理。在binder協議中:
BR_XXX等宏爲BinderDriverReturnProtocol,表示Binder驅動返回協議。
BC_XXX等宏爲BinderDriverCommandProtocol,表示Binder驅動命令協議。
因爲這裏是收到命令請求後要做相應的處理,所以這裏的宏都是以BR開頭的。這裏會走到BR_TRANSACTION這個分支,調用BBinder的transact()方法做處理(b->transact(tr.code, buffer, &reply, 0))。我們看一下BBinder::transact()方法的源代碼:
-
- 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:
- err = onTransact(code, data, reply, flags);
- break;
- }
-
- if (reply != NULL) {
- reply->setDataPosition(0);
- }
-
- return err;
- }
我們看到調用的是虛函數onTransact()。因爲ExampleService類繼承自BBinder類,並改寫了onTransact()方法,所以這裏會調用到ExampleService::onTransact()方法。
- status_t ExampleService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
- {
- switch(code)
- {
- case 0: {
- pid_t pid = data.readInt32();
- int num = data.readInt32();
- num = num + 100;
- reply->writeInt32(num);
- return NO_ERROR;
- }
- break;
- default:
- return BBinder::onTransact(code, data, reply, flags);
- }
- }
看到這裏首先根據請求代碼作相應的處理。還記得我們發送請求時用的是代碼0,所以這裏會走到"case0"這個分支。程序先順序讀出兩個參數:進程ID和被加數,將被加數加上100之後返回。至此,服務器端完成了客戶端的服務請求。
我們將總共四篇文章涉及到的主要類用下面的類圖作一總結:
說明:
1. Android系統使用binder機制實現進程間通信(IPC),這裏主要涉及到以下幾個類:
1.1 IBinder是Android系統對binder機制的抽象,任何一個向系統註冊的Service都必須繼承IBinder接口(如:ExampleService繼承BBinder,而BBinder繼承IBinder)
1.2 IInterface我們在這一系列文章裏沒有過多涉及。它的目的是進一步抽象binder機制。比如要使用我們的ExampleService,客戶端應用程序必須顯式調用IPCThreadState::transaction()方法,對用戶來說還是不太友好。如果我們定義一個新的類IExampleServiceInterface繼承Interface,在這個類中定義add100()接口,ExampleService的代理對象也擁有該接口,那麼客戶端應用程序直接調用代理對象的add100()方法就好了,這樣做對用戶更友好。比如ServiceManager就是這樣實現的(IServiceManager繼承IInterface)。客戶端調用的是addService接口而不是transaction方法。
1.3 ProcessState類是一個singleton類型,每個進程只能創建一個實例,它的作用是管理當前進程中的所有Service代理對象(BpBinder對象)。任何一個使用binder機制的進程都必須創建一個該類的實例。
1.4 IPCThreadState類是processState類的友元類,它的作用是封裝對binder設備的I/O操作。客戶端通過調用它的transact()方法完成發送請求;服務器端調用他的joinThreadState()方法等待客戶端的服務請求。
2. Android的binder機制本質上是Proxy模式的一個具體實現。
3. ServiceManager是整個Android系統的Service管理員,任何一個系統Service首先要向它註冊才能提供服務。註冊時,首先要獲得它的代理對象(BpServiceManager),然後通過調用它的addService()方法完成註冊。客戶端通過調用它的getService()獲取系統服務的代理兌現。ServiceManager在系統中始終對應句柄0。
4. 客戶端通過調用IPCThreadState的transaction方法發送請求;服務器端通過改寫BBinder的onTransaction()方法實現接受請求。
(全文完)