Generate AudioFlinger Service
media_server程序会启动AudioFlinger服务。相关代码如下:
AudioFlinger::instantiate()函数会调用IServiceManager::addService远程调用。
AudioFlinger继承自BnAudioFlinger,BnAudioFlinger是一个BnInterface模板类的实例。
BnInterface继承自BBinder。
根据BnInterface的实现,我们看到传递给IServiceManager::addService的参数是一个AudioFlinger实例的地址。BBinder继承自IBinder,它的transact()函数调用onTransact虚函数(多态)。
最重要的虚函数是onTransact()。BnAudioFlinger实现了该虚函数。在本文的例子中我们只需要关注SET_MODE分支。
media_server会通过IPCThreadState::joinThreadPool进入一个循环,就像service_manager,它会通过调用talkWithDriver()函数等待其他进程传入数据。
……
// now get the next command to be processed, waiting if necessary
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);
}
……
} while (result != -ECONNREFUSED && result != -EBADF);
mOut.writeInt32(BC_EXIT_LOOPER);
talkWithDriver(false);
}
假设你想要实现你自己的IFunnyTest服务,必须遵循以下步骤:
- 实现你自己的BnFunnyTest类;
- 在执行你的服务的进程中,调用IPCThreadState::joinThreadPool()函数
RPC Call IServiceManager::addService
当我们调用IServiceManager::addService时,实际上调用的是BpServiceManager::addService。
Parcel类型很简单。我们可以把它认为是一块连续的缓冲区。注意,参数service是指向BBinder对象(AudioFlinger从Bn继承来)的指针。
flatten_binder会生成一个Binder命令。因为BBinder是一个本地的binder对象,因此该代码分支标为红色。
obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != NULL) {
IBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
if (proxy == NULL) {
LOGE("null proxy");
}
const int32_t handle = proxy ? proxy->handle() : 0;
obj.type = BINDER_TYPE_HANDLE;
obj.handle = handle;
obj.cookie = NULL;
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = local->getWeakRefs();
obj.cookie = local;
}
} else {
obj.type = BINDER_TYPE_BINDER;
obj.binder = NULL;
obj.cookie = NULL;
}
return finish_flatten_binder(binder, obj, out);
}
注意红色的代码行。本地地址被放入到一个包(以后会用到)中。在该addService远程调用的包构造完成后,BpServiceManager::addService()将会调用BpBinder的transact()函数。
BpBinder调用IPCThreadState::transact来根据mHandle启动一个针对binder对象的(处理)事务。在本文的例子中,mHandle为0。
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;
}
IPCThreadState::transact首先调用writeTransactionData函数为binder内核驱动构造一个transaction结构。注意以下几行,它对于binder内核驱动识别事务(transaction)目标非常重要
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;
}
然后waitForResponse()通过talkWithDriver()函数去调用BINDER_WRITE_READ的ioctl()。
于是到现在为止,事务数据已经发送到了binder内核驱动。
小结:
Proxy(代理)对象会为RPC调用生成必需的包,然后调用BINDER_WRITE_READ将包写入binder内核驱动。该包为格式化的。对于RPC调用,它是BC_TRANSACTION类型的包。
假设你要实现你自己的IFunnyTest的服务,你必须要:
- 在服务运行的进程中调用IServiceManager::addService()函数将服务注册到servier_manger。