1 概述
addService的过程涉及三个模块:
- Service,service通过调用service manager的addService接口将自己注册到SM,本质上是client;
- SM,接收service的注册请求,本质上是server;
- Binder Driver,负责CS之间的数据传输和kernel中关键数据结构的建立。
2 Client(MediaPlayerService)
看了网上很多资料都是以MediaPlayerService为例的,本篇也用它来分析。
2.1 MediaPlayerService
frameworks/av/media/mediaserver/main_mediaserver.cpp
int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
sp<ProcessState> proc(ProcessState::self()); -------------1
sp<IServiceManager> sm(defaultServiceManager()); -------------2
ALOGI("ServiceManager: %p", sm.get());
InitializeIcuOrDie();
MediaPlayerService::instantiate(); -------------3
ResourceManagerService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
- 获取该进程对应的ProcessState,进程级别的数据结构,每个进程只有一个,ProcessState相关内容见TOD;
- 获取ServiceManger对应的BpServiceManager,defaultServiceManager相关内容见TOD;
- 调用MediaPlayerService的instantiate,如下:
frameworks/av/media/libmediaplayerservice/MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService()); //这行代码信息量很大
}
随后就调用了BpServiceManager的addService:
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); //"android.os.IServiceManager"
data.writeString16(name); //"media.player"
data.writeStrongBinder(service); // MediaPlayerService
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply); //code: ADD_SERVICE_TRANSACTION
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
2.1.1 BpServiceManager
需要注意的一点是BpServiceManager的继承关系,如下
-->IServiceManager-->IInterface
BpServiceManager-->BpInterface
-->BpRefBase: mRemote(BpBinder)
这种继承方式十分巧妙,一方面保证了BpServiceManager作为interface的功能,可以通过它来进行远程接口调用,另一方面保证了BpServiceManager可以拿到SM的对应的远程binder即BpBinder,基于以上两点实现RPC功能。所以:
- BpServiceManager的addService其实是重写了IServiceManager的addService;
- BpRefBase中的mRemote保存的是defaultServiceManager()时new的BpBinder,remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply), 调用了BpBinder::transact(…)。
2.1.2 new MediaPlayerService()
作为BpBinder::transact(…)的第二个参数,MediaPlayerService类的继承方式同样也很巧妙,如下:
-->IMediaPlayerService
MediaPlayerService-->BnMediaPlayerService->BnInterface
-->BBinder
MediaPlayerService整合了Binder数据结构(BBinder)和MediaPlayerService提供的接口类(IMediaPlayerService)。
总结一下BBinder和BpBinder在数据结构上的套路:
BBinder和BpBinder都继承自IBinder,前者是本地对象,后者是远程对象。
- 如果是从远程拿到的Binder,那么该数据结构会有远程Service的本地方法和对应的BpBinder,通过这些重写的本地方法再和远程service通信;
- 如果是注册服务,那么要将本service的接口类和BBinder整合后,再transact;
一句话,不管是远程还是本地,都既要对应的IBinder数据结构(找到TA),又要接口(使用TA)。
2.2 addService
回到addService,主要做了两件事:
- 准备Parcel数据;
- 调用BpBinder::transact(…)。
2.2.1 Parcel打包数据
关于Parcel的分析,见binder_context_mgr_node。这里写入的数据为:
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor()); //"android.os.IServiceManager"
data.writeString16(name); //"media.player"
data.writeStrongBinder(service); // MediaPlayerService
data.writeInt32(allowIsolated ? 1 : 0); // 0
数据分两种:
- 常规类型的数据,比如SM的token,MediaPlayerService的name,int类型等
- 写入IBinder,即传入的MediaPlayerService,此时需要将IBinder类型的数据扁平化,调用writeStrongBinder:
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
return flatten_binder(ProcessState::self(), val, this);
}
status_t flatten_binder(const sp<ProcessState>& /*proc*/,
const sp<IBinder>& binder, Parcel* out)
{
flat_binder_object obj; ------------------ 1
if (IPCThreadState::self()->backgroundSchedulingDisabled()) {
/* minimum priority for all nodes is nice 0 */
obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
} else {
/* minimum priority for all nodes is MAX_NICE(19) */
obj.flags = 0x13 | FLAT_BINDER_FLAG_ACCEPTS_FDS;
}
if (binder != NULL) {
IBinder *local = binder->localBinder(); ------------------- 2
if (!local) {
......
} else {
obj.type = BINDER_TYPE_BINDER; -------------------3
obj.binder = reinterpret_cast<uintptr_t>(local->getWeakRefs());
obj.cookie = <uintptr_t>(local);
}
} else {
......
}
return finish_flatten_binder(binder, obj, out); --------------------4
}
- 定义flat_binder_object,扁平化之后的IBinder就存放在这里;
- 注册时的IBinder是BBinder,所以返回不为空;
- 本地Binder的类型为BINDER_TYPE_BINDER,binder 保存的是MediaPlayerService的弱引用,cookie保存的是MediaPlayerService的地址。
- 将flat_binder_object数据结构写入Parcel变量。
写入完毕Parcel中的数据应该如下:
2.2.1 BpBinder::transact(…)
165 status_t status = IPCThreadState::self()->transact(
166 mHandle, code, data, reply, flags);
mHandle的值为0,是BpBinder在被new的时候的初始化参数,因为是ServiceManager对应的BpBinder,而SM的默认handle就是0。默认flags的值为0,非ONEWAY通信。
接下来调用了IPCThreadState::self()->transact
2.3 IPCThreadState::transact
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) {
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); ----------------------1
}
if (err != NO_ERROR) {
if (reply) reply->setError(err);
return (mLastError = err);
}
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
err = waitForResponse(reply); ------------------------2
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
err = waitForResponse(NULL, NULL);
}
return err;
}
- writeTransactionData对要传输的数据再次封装;
- waitForResponse其实不仅等待返回结果,真正与binder driver通信也是在这个函数。
2.3.1 writeTransactionData
IPCThreadState::transact是进入驱动之前应用中的最后一步调用,所以这时候要加上Binder Command(即BC开头的宏)——BC_TRANSACTION。
该函数构造了binder_transaction_data结构体,初始化、保存了binder事物相关的数据,其中也保存了之前的parcel data,然后再次将binder_transaction_data和BC_TRANSACTION写入到IPCThreadState的mOut成员,该成员也是一个Parcel类型数据,在IPCThreadState构造时被初始化。writeTransactionData处理后的数据封装如下图:
2.3.2 waitForResponse
分两块理解:
- talkWithDriver与binder driver通信;
- 根据binder driver的返回结果再做操作。
talkWithDriver
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
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 = (uintptr_t)mOut.data();
bwr.write_consumed = 0;
bwr.read_consumed = 0;
do {
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) --------------2
err = NO_ERROR;
else
err = -errno;
} while (err == -EINTR);
if (err >= NO_ERROR) { ------------------3
if (bwr.write_consumed > 0) {
if (bwr.write_consumed < mOut.dataSize())
mOut.remove(0, bwr.write_consumed);
else
mOut.setDataSize(0);
}
if (bwr.read_consumed > 0) {
mIn.setDataSize(bwr.read_consumed);