在這篇文章中,我們將深入剖析一下如何向系統註冊Service。
在第一篇文章的例子中,ExampleService通過如下語句向系統註冊服務。
// File: ExampleService.cpp<br />int r = defaultServiceManager()->addService(String16("byn.example"), new ExampleService());
在上一篇文章中,我們已經知道通過調用defaultServiceManager()全域函數可以獲得當前進程的ServiceManager代理對象的引用。在深入剖析addService()方法之前,讓我們先瞭解一下ServiceManager是如何啟動的。首先來看一下它的原始碼:
// File: frameworks/base/cmds/servicemanager/service_manager.c<br />int main(int argc, char **argv)<br />{<br /> struct binder_state *bs;<br /> void *svcmgr = BINDER_SERVICE_MANAGER;</p><p> bs = binder_open(128*1024);</p><p> if (binder_become_context_manager(bs)) {<br /> LOGE("cannot become context manager (%s)/n", strerror(errno));<br /> return -1;<br /> }</p><p> svcmgr_handle = svcmgr;<br /> binder_loop(bs, svcmgr_handler);<br /> return 0;<br />}<br />
ServiceManager本身是一個系統進程,是Android核心程式。從它的main函數來看,它首先調用binder_open()函數開啟binder裝置(/dev/binder),接著調用binder_become_context_manager()函數,將自己變為系統服務的“管理員”。我們看一下binder_become_context_manager()函數的原始碼:
// File: frameworks/base/cmds/servicemanager/service_manager.c<br />int binder_become_context_manager(struct binder_state *bs)<br />{<br /> return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);<br />}
可以看到以BINDER_SET_CONTEXT_MGR為參數進行ioctl系統調用,就可以將自身設定成系統服務的“管理員”,即ServiceManager。
最後,ServiceManager調用binder_loop進入到迴圈狀態,並提供了一個回呼函數svcmgr_handler(),等待使用者的請求。
現在讓我們剖析一下向系統註冊Service的過程吧。首先,調用defaultServiceManager()全域函數獲得的是ServiceManager代理對象的引用,所以這裡的調用的addService方法是代理對象的方法,而不是真正的ServiceManager的addService方法。讓我們看一下它的原始碼:
// File: frameworks/base/libs/binder/IServiceManager.cpp<br />class BpServiceManager : public BpInterface<IServiceManager><br />{<br />public:<br /> ......<br /> virtual status_t addService(const String16& name, const sp<IBinder>& service)<br /> {<br /> Parcel data, reply;<br /> data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());<br /> data.writeString16(name);<br /> data.writeStrongBinder(service);<br /> status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);<br /> return err == NO_ERROR ? reply.readInt32() : err;<br /> }<br /> ......<br />}
這裡是以ADD_SERVICE_TRANSACTION為命令代碼調用的transact()方法。因為ServiceManager代理對象BpServiceManager繼承自BpBinder,所以這裡調用的是BpBinder::transact(),我們看一下它的原始碼:
// File: frameworks/base/libs/binder/BpBinder.cpp<br />status_t BpBinder::transact(<br /> uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)<br />{<br /> // Once a binder has died, it will never come back to life.<br /> if (mAlive) {<br /> status_t status = IPCThreadState::self()->transact(<br /> mHandle, code, data, reply, flags);<br /> if (status == DEAD_OBJECT) mAlive = 0;<br /> return status;<br /> }</p><p> return DEAD_OBJECT;<br />}
我們看到該方法是通過調用IPCThreadState類的同名方法繼續傳遞請求。這裡需要解釋一下IPCThreadState類的作用。
每個進程中有且僅有一個IPCThreadState對象,它的作用是維護當前進程中所有對binder裝置(/dev/binder)的I/O操作,也就是說一個進程要想通過binder機制與另外一個進程進行通訊,最終都是要通過IPCThreadState對象來完成的。有了IPCThreadState這層封裝之後,應用程式就不需要通過ioctl同binder裝置直接打交道了。下面讓我們來看一下IPCThreadState類的transact方法的原始碼:
// File: frameworks/base/libs/binder/IPCThreadState.cpp<br />status_t IPCThreadState::transact(int32_t handle,<br /> uint32_t code, const Parcel& data,<br /> Parcel* reply, uint32_t flags)<br />{<br /> status_t err = data.errorCheck();</p><p> flags |= TF_ACCEPT_FDS;</p><p> IF_LOG_TRANSACTIONS() {<br /> TextOutput::Bundle _b(alog);<br /> alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "<br /> << handle << " / code " << TypeCode(code) << ": "<br /> << indent << data << dedent << endl;<br /> }</p><p> if (err == NO_ERROR) {<br /> LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),<br /> (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");<br /> err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);<br /> }</p><p> if (err != NO_ERROR) {<br /> if (reply) reply->setError(err);<br /> return (mLastError = err);<br /> }</p><p> if ((flags & TF_ONE_WAY) == 0) {<br /> if (reply) {<br /> err = waitForResponse(reply);<br /> } else {<br /> Parcel fakeReply;<br /> err = waitForResponse(&fakeReply);<br /> }</p><p> IF_LOG_TRANSACTIONS() {<br /> TextOutput::Bundle _b(alog);<br /> alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "<br /> << handle << ": ";<br /> if (reply) alog << indent << *reply << dedent << endl;<br /> else alog << "(none requested)" << endl;<br /> }<br /> } else {<br /> err = waitForResponse(NULL, NULL);<br /> }</p><p> return err;<br />}
這裡調用了writeTransactionData()方法來完成請求,我們再看一下writeTransactionData()方法的定義:
// File: frameworks/base/libs/binder/IPCThreadState.cpp<br />status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,<br /> int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)<br />{<br /> binder_transaction_data tr;</p><p> tr.target.handle = handle;<br /> tr.code = code;<br /> tr.flags = binderFlags;</p><p> const status_t err = data.errorCheck();<br /> if (err == NO_ERROR) {<br /> tr.data_size = data.ipcDataSize();<br /> tr.data.ptr.buffer = data.ipcData();<br /> tr.offsets_size = data.ipcObjectsCount()*sizeof(size_t);<br /> tr.data.ptr.offsets = data.ipcObjects();<br /> } else if (statusBuffer) {<br /> tr.flags |= TF_STATUS_CODE;<br /> *statusBuffer = err;<br /> tr.data_size = sizeof(status_t);<br /> tr.data.ptr.buffer = statusBuffer;<br /> tr.offsets_size = 0;<br /> tr.data.ptr.offsets = NULL;<br /> } else {<br /> return (mLastError = err);<br /> }</p><p> mOut.writeInt32(cmd);<br /> mOut.write(&tr, sizeof(tr));</p><p> return NO_ERROR;<br />}
最終是在這裡將命令和資料封裝好之後寫入待發送的隊列(mOut.writeInt32(cmd),mOut.write(&tr, sizeof(tr)))。回到IPCThreadState類的transact()方法。writeTransactionData()方法返回之後,會通過調用waitForResponse()方法發送請求並等待返回結果。而waitForResponse()方法會調用IPCThreadState::talkWithDriver()方法發送請求並取回傳回值。我們看一下talkWithDriver()方法的原始碼:
// File: frameworks/base/libs/binder/IPCThreadState.cpp<br />status_t IPCThreadState::talkWithDriver(bool doReceive)<br />{<br /> LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");</p><p> binder_write_read bwr;</p><p> // Is the read buffer empty?<br /> const bool needRead = mIn.dataPosition() >= mIn.dataSize();</p><p> // We don't want to write anything if we are still reading<br /> // from data left in the input buffer and the caller<br /> // has requested to read the next data.<br /> const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;</p><p> bwr.write_size = outAvail;<br /> bwr.write_buffer = (long unsigned int)mOut.data();</p><p> // This is what we'll read.<br /> if (doReceive && needRead) {<br /> bwr.read_size = mIn.dataCapacity();<br /> bwr.read_buffer = (long unsigned int)mIn.data();<br /> } else {<br /> bwr.read_size = 0;<br /> }</p><p> IF_LOG_COMMANDS() {<br /> TextOutput::Bundle _b(alog);<br /> if (outAvail != 0) {<br /> alog << "Sending commands to driver: " << indent;<br /> const void* cmds = (const void*)bwr.write_buffer;<br /> const void* end = ((const uint8_t*)cmds)+bwr.write_size;<br /> alog << HexDump(cmds, bwr.write_size) << endl;<br /> while (cmds < end) cmds = printCommand(alog, cmds);<br /> alog << dedent;<br /> }<br /> alog << "Size of receive buffer: " << bwr.read_size<br /> << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;<br /> }</p><p> // Return immediately if there is nothing to do.<br /> if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;</p><p> bwr.write_consumed = 0;<br /> bwr.read_consumed = 0;<br /> status_t err;<br /> do {<br /> IF_LOG_COMMANDS() {<br /> alog << "About to read/write, write size = " << mOut.dataSize() << endl;<br /> }<br />#if defined(HAVE_ANDROID_OS)<br /> if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)<br /> err = NO_ERROR;<br /> else<br /> err = -errno;<br />#else<br /> err = INVALID_OPERATION;<br />#endif<br /> IF_LOG_COMMANDS() {<br /> alog << "Finished read/write, write size = " << mOut.dataSize() << endl;<br /> }<br /> } while (err == -EINTR);</p><p> IF_LOG_COMMANDS() {<br /> alog << "Our err: " << (void*)err << ", write consumed: "<br /> << bwr.write_consumed << " (of " << mOut.dataSize()<br /><< "), read consumed: " << bwr.read_consumed << endl;<br /> }</p><p> if (err >= NO_ERROR) {<br /> if (bwr.write_consumed > 0) {<br /> if (bwr.write_consumed < (ssize_t)mOut.dataSize())<br /> mOut.remove(0, bwr.write_consumed);<br /> else<br /> mOut.setDataSize(0);<br /> }<br /> if (bwr.read_consumed > 0) {<br /> mIn.setDataSize(bwr.read_consumed);<br /> mIn.setDataPosition(0);<br /> }<br /> IF_LOG_COMMANDS() {<br /> TextOutput::Bundle _b(alog);<br /> alog << "Remaining data size: " << mOut.dataSize() << endl;<br /> alog << "Received commands from driver: " << indent;<br /> const void* cmds = mIn.data();<br /> const void* end = mIn.data() + mIn.dataSize();<br /> alog << HexDump(cmds, mIn.dataSize()) << endl;<br /> while (cmds < end) cmds = printReturnCommand(alog, cmds);<br /> alog << dedent;<br /> }<br /> return NO_ERROR;<br /> }</p><p> return err;<br />}
talkWithDriver()方法會將待發送的請求(之前已經存放在mOut對象中)封裝到一個binder_write_read類型的結構體bwr中,並調用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)完成發送請求。接下來的工作就由核心空間來完成了。此進程當前會阻塞在ioctl這裡,直到有傳回值返回。由此可見,通過binder機制進行的IPC通訊是一個同步過程。這一點非常重要。
用戶端的程式我們暫時先分析到這裡,現在讓我們看看服務端在收到這一請求之後都會做哪些處理。
前面提到,ServiceManager的main函數中註冊了回呼函數svcmgr_handler(),因此上面的請求通過binder裝置發送到ServiceManager這一端的時候,該函數會被調用。我們看一下它的原始碼:
// File: frameworks/base/cmds/servicemanager/service_manager.c<br />int svcmgr_handler(struct binder_state *bs,<br /> struct binder_txn *txn,<br /> struct binder_io *msg,<br /> struct binder_io *reply)<br />{<br /> struct svcinfo *si;<br /> uint16_t *s;<br /> unsigned len;<br /> void *ptr;</p><p> LOGI("[BYN]target=%p code=%d pid=%d uid=%d/n",<br /> txn->target, txn->code, txn->sender_pid, txn->sender_euid);</p><p> if (txn->target != svcmgr_handle)<br /> return -1;</p><p> s = bio_get_string16(msg, &len);</p><p> if ((len != (sizeof(svcmgr_id) / 2)) ||<br /> memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {<br /> fprintf(stderr,"invalid id %s/n", str8(s));<br /> return -1;<br /> }</p><p> switch(txn->code) {<br /> case SVC_MGR_GET_SERVICE:<br /> case SVC_MGR_CHECK_SERVICE:<br /> s = bio_get_string16(msg, &len);<br /> ptr = do_find_service(bs, s, len);<br /> if (!ptr)<br /> break;<br /> bio_put_ref(reply, ptr);<br /> return 0;</p><p> case SVC_MGR_ADD_SERVICE:<br /> s = bio_get_string16(msg, &len);<br /> ptr = bio_get_ref(msg);<br /> if (do_add_service(bs, s, len, ptr, txn->sender_euid))<br /> return -1;<br /> break;</p><p> case SVC_MGR_LIST_SERVICES: {<br /> unsigned n = bio_get_uint32(msg);</p><p> si = svclist;<br /> while ((n-- > 0) && si)<br /> si = si->next;<br /> if (si) {<br /> bio_put_string16(reply, si->name);<br /> return 0;<br /> }<br /> return -1;<br /> }<br /> default:<br /> LOGE("unknown code %d/n", txn->code);<br /> return -1;<br /> }</p><p> bio_put_uint32(reply, 0);<br /> return 0;<br />}
由於調用的是addService服務,所以會走到SVC_MGR_ADD_SERVICE分支,調用do_add_service()函數。我們看一下它的原始碼:
// File: frameworks/base/cmds/servicemanager/service_manager.c<br />int do_add_service(struct binder_state *bs,<br /> uint16_t *s, unsigned len,<br /> void *ptr, unsigned uid)<br />{<br /> struct svcinfo *si;<br />// LOGI("add_service('%s',%p) uid=%d/n", str8(s), ptr, uid);</p><p> if (!ptr || (len == 0) || (len > 127))<br /> return -1;</p><p> if (!svc_can_register(uid, s)) {<br /> LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED/n",<br /> str8(s), ptr, uid);<br /> return -1;<br /> }</p><p> si = find_svc(s, len);<br /> if (si) {<br /> if (si->ptr) {<br /> LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED/n",<br /> str8(s), ptr, uid);<br /> return -1;<br /> }<br /> si->ptr = ptr;<br /> } else {<br /> si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));<br /> if (!si) {<br /> LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY/n",<br /> str8(s), ptr, uid);<br /> return -1;<br /> }<br /> si->ptr = ptr;<br /> si->len = len;<br /> memcpy(si->name, s, (len + 1) * sizeof(uint16_t));<br /> si->name[len] = '/0';<br /> si->death.func = svcinfo_death;<br /> si->death.ptr = si;<br /> si->next = svclist;<br /> svclist = si;<br /> }</p><p> binder_acquire(bs, ptr);<br /> binder_link_to_death(bs, ptr, &si->death);<br /> return 0;<br />}
這裡首先判斷一下是否有許可權註冊服務(svc_can_register(uid, s)),如果可以的話,再判斷該服務是否已經註冊過;如果沒有註冊過的話,就構造一個svcinfo對象,並將它添加到svclist鏈表中。最後通知binder裝置:有一個新的Service註冊進來。
伺服器端返回之後,用戶端被解除阻塞(ioctl系統調用),然後逐層返回,從而完成了註冊服務的請求。