在这篇文章中,我们将深入剖析一下如何向系统注册Service。
在第一篇文章的例子中,ExampleService通过如下语句向系统注册服务。
在上一篇文章中,我们已经知道通过调用defaultServiceManager()全局函数可以获得当前进程的ServiceManager代理对象的引用。在深入剖析addService()方法之前,让我们先了解一下ServiceManager是如何启动的。首先来看一下它的源代码:
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
LOGE("cannot become context manager (%s)/n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
ServiceManager本身是一个系统进程,是Android核心程序。从它的main函数来看,它首先调用binder_open()函数打开binder设备(/dev/binder),接着调用binder_become_context_manager()函数,将自己变为系统服务的“管理员”。我们看一下binder_become_context_manager()函数的源代码:
可以看到以BINDER_SET_CONTEXT_MGR为参数进行ioctl系统调用,就可以将自身设置成系统服务的“管理员”,即ServiceManager。
最后,ServiceManager调用binder_loop进入到循环状态,并提供了一个回调函数svcmgr_handler(),等待用户的请求。
现在让我们剖析一下向系统注册Service的过程吧。首先,调用defaultServiceManager()全局函数获得的是ServiceManager代理对象的引用,所以这里的调用的addService方法是代理对象的方法,而不是真正的ServiceManager的addService方法。让我们看一下它的源代码:
这里是以ADD_SERVICE_TRANSACTION为命令代码调用的transact()方法。因为ServiceManager代理对象BpServiceManager继承自BpBinder,所以这里调用的是BpBinder::transact(),我们看一下它的源代码:
return DEAD_OBJECT;
}
我们看到该方法是通过调用IPCThreadState类的同名方法继续传递请求。这里需要解释一下IPCThreadState类的作用。
每个进程中有且仅有一个IPCThreadState对象,它的作用是维护当前进程中所有对binder设备(/dev/binder)的I/O操作,也就是说一个进程要想通过binder机制与另外一个进程进行通信,最终都是要通过IPCThreadState对象来完成的。有了IPCThreadState这层封装之后,应用程序就不需要通过ioctl同binder设备直接打交道了。下面让我们来看一下IPCThreadState类的transact方法的源代码:
flags |= TF_ACCEPT_FDS;
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
<< handle << " / code " << TypeCode(code) << ": "
<< indent << data << dedent << endl;
}
if (err == NO_ERROR) {
LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
(flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
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);
}
IF_LOG_TRANSACTIONS() {
TextOutput::Bundle _b(alog);
alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
<< handle << ": ";
if (reply) alog << indent << *reply << dedent << endl;
else alog << "(none requested)" << endl;
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
这里调用了writeTransactionData()方法来完成请求,我们再看一下writeTransactionData()方法的定义:
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
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(size_t);
tr.data.ptr.offsets = data.ipcObjects();
} else if (statusBuffer) {
tr.flags |= TF_STATUS_CODE;
*statusBuffer = err;
tr.data_size = sizeof(status_t);
tr.data.ptr.buffer = statusBuffer;
tr.offsets_size = 0;
tr.data.ptr.offsets = NULL;
} else {
return (mLastError = err);
}
mOut.writeInt32(cmd);
mOut.write(&tr, sizeof(tr));
return NO_ERROR;
}
最终是在这里将命令和数据封装好之后写入待发送的队列(mOut.writeInt32(cmd),mOut.write(&tr, sizeof(tr)))。回到IPCThreadState类的transact()方法。writeTransactionData()方法返回之后,会通过调用waitForResponse()方法发送请求并等待返回结果。而waitForResponse()方法会调用IPCThreadState::talkWithDriver()方法发送请求并取回返回值。我们看一下talkWithDriver()方法的源代码:
binder_write_read bwr;
// Is the read buffer empty?
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
// We don't want to write anything if we are still reading
// from data left in the input buffer and the caller
// has requested to read the next data.
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (long unsigned int)mOut.data();
// This is what we'll read.
if (doReceive && needRead) {
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (long unsigned int)mIn.data();
} else {
bwr.read_size = 0;
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
if (outAvail != 0) {
alog << "Sending commands to driver: " << indent;
const void* cmds = (const void*)bwr.write_buffer;
const void* end = ((const uint8_t*)cmds)+bwr.write_size;
alog << HexDump(cmds, bwr.write_size) << endl;
while (cmds < end) cmds = printCommand(alog, cmds);
alog << dedent;
}
alog << "Size of receive buffer: " << bwr.read_size
<< ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
}
// Return immediately if there is nothing to do.
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
IF_LOG_COMMANDS() {
alog << "About to read/write, write size = " << mOut.dataSize() << endl;
}
#if defined(HAVE_ANDROID_OS)
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
else
err = -errno;
#else
err = INVALID_OPERATION;
#endif
IF_LOG_COMMANDS() {
alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
}
} while (err == -EINTR);
IF_LOG_COMMANDS() {
alog << "Our err: " << (void*)err << ", write consumed: "
<< bwr.write_consumed << " (of " << mOut.dataSize()
<< "), read consumed: " << bwr.read_consumed << endl;
}
if (err >= NO_ERROR) {
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < (ssize_t)mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);
mIn.setDataPosition(0);
}
IF_LOG_COMMANDS() {
TextOutput::Bundle _b(alog);
alog << "Remaining data size: " << mOut.dataSize() << endl;
alog << "Received commands from driver: " << indent;
const void* cmds = mIn.data();
const void* end = mIn.data() + mIn.dataSize();
alog << HexDump(cmds, mIn.dataSize()) << endl;
while (cmds < end) cmds = printReturnCommand(alog, cmds);
alog << dedent;
}
return NO_ERROR;
}
return err;
}
talkWithDriver()方法会将待发送的请求(之前已经存放在mOut对象中)封装到一个binder_write_read类型的结构体bwr中,并调用ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)完成发送请求。接下来的工作就由内核空间来完成了。此进程当前会阻塞在ioctl这里,直到有返回值返回。由此可见,通过binder机制进行的IPC通信是一个同步过程。这一点非常重要。
客户端的程序我们暂时先分析到这里,现在让我们看看服务端在收到这一请求之后都会做哪些处理。
前面提到,ServiceManager的main函数中注册了回调函数svcmgr_handler(),因此上面的请求通过binder设备发送到ServiceManager这一端的时候,该函数会被调用。我们看一下它的源代码:
LOGI("[BYN]target=%p code=%d pid=%d uid=%d/n",
txn->target, txn->code, txn->sender_pid, txn->sender_euid);
if (txn->target != svcmgr_handle)
return -1;
s = bio_get_string16(msg, &len);
if ((len != (sizeof(svcmgr_id) / 2)) ||
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
fprintf(stderr,"invalid id %s/n", str8(s));
return -1;
}
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
ptr = do_find_service(bs, s, len);
if (!ptr)
break;
bio_put_ref(reply, ptr);
return 0;
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
ptr = bio_get_ref(msg);
if (do_add_service(bs, s, len, ptr, txn->sender_euid))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
unsigned n = bio_get_uint32(msg);
si = svclist;
while ((n-- > 0) && si)
si = si->next;
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
default:
LOGE("unknown code %d/n", txn->code);
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
由于调用的是addService服务,所以会走到SVC_MGR_ADD_SERVICE分支,调用do_add_service()函数。我们看一下它的源代码:
if (!ptr || (len == 0) || (len > 127))
return -1;
if (!svc_can_register(uid, s)) {
LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED/n",
str8(s), ptr, uid);
return -1;
}
si = find_svc(s, len);
if (si) {
if (si->ptr) {
LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED/n",
str8(s), ptr, uid);
return -1;
}
si->ptr = ptr;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY/n",
str8(s), ptr, uid);
return -1;
}
si->ptr = ptr;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '/0';
si->death.func = svcinfo_death;
si->death.ptr = si;
si->next = svclist;
svclist = si;
}
binder_acquire(bs, ptr);
binder_link_to_death(bs, ptr, &si->death);
return 0;
}
这里首先判断一下是否有权限注册服务(svc_can_register(uid, s)),如果可以的话,再判断该服务是否已经注册过;如果没有注册过的话,就构造一个svcinfo对象,并将它添加到svclist链表中。最后通知binder设备:有一个新的Service注册进来。
服务器端返回之后,客户端被解除阻塞(ioctl系统调用),然后逐层返回,从而完成了注册服务的请求。