5.3 注册服务
5.3.2 注册C++层服务
这里不妨以MediaPlayerService服务过程为例,来说一说服务注册过程,先来看看media的整个的类关系图。
图解:
- 蓝色代表的是注册MediaPlayerService服务所涉及的类
- 绿色代表的是Binder架构中与Binder驱动通信过程中的最为核心的两个类;
- 紫色代表的是注册服务和获取服务的公共接口/父类;
1. BpServiceManager
从MediaPlayerService服务初始化开始,代码如下:
// MediaPlayerService.cpp
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
注册服务MediaPlayerService的过程, defaultServiceManager()会创建ProcessState,BpBinder以及BpServiceManager对象, 最终返回的是BpServiceManager对象。
看看BpServiceManager的addService()的处理国瓷,代码如下:
// IServiceManager.cpp
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply; //Parcel是数据通信包
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name); // name为 "media.player"
data.writeStrongBinder(service); // MediaPlayerService服务
data.writeInt32(allowIsolated ? 1 : 0); // allowIsolated= false
//此处remote()指向的是BpBinder对象
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
服务注册过程:向ServiceManager注册服务MediaPlayerService,将相关数据都封装到Parcel对象,把Parcel和code数据传递到下一层BpBinder,Parcel对象的数据填充情况如图所示
- 接口Token值: “android.os.IServiceManager“
- 服务名:“media.player“
- 服务对象:MediaPlayerService对象
把ADD_SERVICE_TRANSACTION和Parcel数据交给BpBinder来处理,经过BpBinder.transact()从对端得到的返回数据放到Parcel类型的reply数据包,并通过readExceptionCode读取对端执行过程是否发现过异常。 对于Binder服务对象经过writeStrongBinder()方法进行扁平化才能用于进程间通信, 将IBinder转换成flat_binder_object对象,该对象的成员变量type=BINDER_TYPE_BINDER,成员变量cookie记录Binder实体的指针,成员变量binder记录Binder实体的引用计数对象weakref_impl。
2. BpBinder
// BpBinder.cpp
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
向ServiceManager注册服务,此次mHandle=0, Binder平台中,针对handle=0的情况会特殊处理,可以自动找到ServiceManager进程。注册服务的code便是ADD_SERVICE_TRANSACTION,该过程的真正工作交给IPCThreadState来进行transact工作。先来看看IPCThreadState::self的过程。
3. IPCThreadState
先来看看IPCThreadState初始化过程,代码如下:
// IPCThreadState.cpp
IPCThreadState* IPCThreadState::self()
{
if (gHaveTLS) {
restart:
const pthread_key_t k = gTLS;
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
return new IPCThreadState; //初始IPCThreadState
}
if (gShutdown) return NULL;
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) { //首次进入gHaveTLS为false
if (pthread_key_create(&gTLS, threadDestructor) != 0) { //创建线程的TLS
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}
TLS是指Thread local storage(线程本地储存空间),每个线程都拥有自己的TLS,并且是私有空间,线程之间不会共享。通过pthread_getspecific/pthread_setspecific函数可以获取/设置这些空间中的内容。从线程本地存储空间中获得保存在其中的IPCThreadState对象。再来看看IPCThreadState初始化过程.
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
void IPCThreadState::clearCaller()
{
mCallingPid = getpid(); //初始化pid
mCallingUid = getuid(); //初始化uid
}
每个线程都有一个IPCThreadState,每个IPCThreadState中都有一个mIn和mOut。成员变量mProcess保存了ProcessState变量(每个进程只有一个)。
- mCallingPid和mCallingUid 设置成当前进程的pid和uid;
- mIn用来接收来自Binder设备的数据,默认大小为256字节;
- mOut用来存储发往Binder设备的数据,默认大小为256字节。
再来看看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) { // 传输数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
...
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
//等待响应
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
//oneway,则不需要等待reply的场景
err = waitForResponse(NULL, NULL);
}
return err;
}
IPCThreadState进行transact事务处理过程,会检查Parcel数据是否存在错误,比如内存不足的情况下,通信数据包并没有能封装到Parcel对象,当存在错误则直接返回。接着,flags默认是采用同步的方式,这里再增加允许应答数据中带有文件描述符号的功能。 有了前面封装好的Parcel数据, 再进行二次封装,将handle, code, parcel数据一并打包封装到binder_transaction_data结构体, 这个结构体在Binde驱动里面也有完全一样的结构体,经过这样封装的数据,驱动层并可以正确的识别,这里需要注意的是sender_pid和sender_euid的初值默认为0,而非当前进程的pid和uid。 将这些数据再加上通信协议BC_TRANSACTION,都写入到数据类型为Parcel的mOut对象。
服务注册过程采用的是同步的Binder调用,传入reply对象,跟Binder驱动交互,然后等待从数据传回的数据。接下来,重点看看writeTransactionData和waitForResponse过程。
(1)IPC.writeTransactionData
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
binder_transaction_data tr;
tr.target.ptr = 0;
tr.target.handle = handle; // handle = 0
tr.code = code; // code = ADD_SERVICE_TRANSACTION
tr.flags = binderFlags; // binderFlags = 0
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
// data为记录Media服务信息的Parcel对象
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize(); // mDataSize
tr.data.ptr.buffer = data.ipcData(); //mData地址
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); //mObjectsSize
tr.data.ptr.offsets = data.ipcObjects(); //mObjects地址
} else if (statusBuffer) {
...
} else {
return (mLastError = err);
}
mOut.writeInt32(cmd); //协议BC_TRANSACTION
mOut.write(&tr, sizeof(tr)); //写入binder_transaction_data数据
return NO_ERROR;
}
其中handle的值用来标识目的端,注册服务过程的目的端为service manager,此处handle=0所对应的是binder_context_mgr_node对象,正是service manager所对应的binder实体对象。binder_transaction_data结构体是binder驱动通信的数据结构,该过程最终是把Binder请求码BC_TRANSACTION和binder_transaction_data结构体写入到mOut。对于binder_transaction_data数据的核心成员,如图5-2所示。
- handle = 0
- code = ADD_SERVICE_TRANSACTION
- data组成:
- 接口Token值 = “android.os.IServiceManager“
- 服务名 = “media.player“
- 服务对象 = MediaPlayerService对象
把BC_TRANSACTION协议和binder_transaction_data数据写入到mOut对象。
(2)IPC.waitForResponse
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
...
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE:
if (!reply && !acquireResult) goto finish;
break;
case BR_DEAD_REPLY: ...
case BR_FAILED_REPLY: ...
case BR_ACQUIRE_RESULT: ...
case BR_REPLY: ...
goto finish;
default:
err = executeCommand(cmd);
if (err != NO_ERROR) goto finish;
break;
}
}
...
return err;
}
在waitForResponse是直接跟Binder驱动打交道的过程,通过talkWithDriver来跟Binder驱动进行数据交互。 首先经过Binder驱动处理后,首先返回回来的BR_TRANSACTION_COMPLETE协议,reply不为空则会继续等待,直到收到Binder驱动返回的BR_REPLY协议或者是数据出在错误。 而另一个端目标进程收到当前进程发送的BC_TRANSACTION事务后,经过驱动转换为BR_TRANSACTION事务。将服务注册到ServiceManager进程,再然后发送BC_REPLY给驱动, 驱动处理后向当前进程发送BR_REPLY命令。 先来看看talkWithDriver()的过程。
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
...
binder_write_read bwr;
//当mDataSize <= mDataPos,则有数据可读
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data(); // mData地址
if (doReceive && needRead) {
//接收数据缓冲区信息的填充。如果以后收到数据,就直接填在mIn中。
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
//当读缓冲和写缓冲都为空,则直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//通过ioctl不停的读写操作,跟Binder Driver进行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
...
} while (err == -EINTR);
...
return err;
}
talkWithDriver,顾名思义,就是用于跟驱动交谈,交谈就需要听和说两个过程,对应到软件工程来说就是读与写的操作。读写之前先需要准备好读写的数据格式,binder_write_read结构体用来与Binder设备交换数据的结构,通过ioctl与mDriverFD通信,是真正与Binder驱动进行数据读写交互的过程。 在执行一次读写之前,需要先把要读和写的数据都封装到binder_write_read结构体用,当读写数据区的大小都为零,则本次交谈可以直接结束。有一种场景,只需要把自己的写缓存区的数据传入到驱动,而不关心驱动返回回来的数据, 那么可通过设置参数doReceive为false来做到,默认情况下doReceive等于true。
再来回顾下,整个过程的数据封装流程,如图所示。
- 首先,addService()过程,将服务名和服务对象封装到Parcel对象, 跟着ADD_SERVICE_TRANSACTION一并交给handle=0的BpBinder
- 其次,writeTransactionData()过程, 将步骤1的数据都整合到binder_transaction_data,跟着BC_TRANSACTION协议一并写入到mOut
- 最后,talkWithDriver()过程,将步骤2的数据都整合到mOut对象,再加上mIn对象一并写入到binder_write_read结构体, 把该结构体以命令BINDER_WRITE_READ的方式向Binder驱动发送ioctl来交互。
可见,经过整个过程从最上至下的传递,最为核心的数据块保存在Parcel结构体。
4. Binder Driver
本节大致说下Binder Driver的主要工作内容,后面章节会详细说明。 通过ioctl()系统调用进入到Binder驱动, 反向不断拆解用户空间传递过来的数据。
- binder_ioctl()过程解析ioctl参数BINDER_WRITE_READ,则调用binder_ioctl_write_read()方法;
- binder_ioctl_write_read()过程将用户空间binder_write_read结构体拷贝到内核空间, 写缓存中存在数据,则调用binder_thread_write()方法;
- binder_thread_write()过程解析到传输协议为BC_TRANSACTION,则调用binder_transaction()方法;
- binder_transaction()过程将用户空间binder_transaction_data结构体拷贝到内核空间,内核创建一个binder_transaction结构体,
binder_transaction()过程根据target.handle为0,所找到目标实体就是binder_context_mgr_node,所对应的是servicemanager进程。于是便在接收端servicemanager进程开辟一块buffer,然后将Parcel数据拷贝到该buffer。此次通信为同步Binder调用,会将服务所在的线程以及接收端进程等信息都会记录下来。是驱动处理这个过程最为精华的部分,还是很有必要先来说说其功能,代码非常关键,这里先贴一下,代码如下:
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply){
struct binder_transaction *t;
struct binder_work *tcomplete;
if (reply) {
...
}else {
if (tr->target.handle) {
...
} else {
// handle=0则找到servicemanager实体
target_node = binder_context_mgr_node;
}
//target_proc为servicemanager进程
target_proc = target_node->proc;
}
if (target_thread) {
...
} else {
//找到servicemanager进程的todo队列
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
t = kzalloc(sizeof(*t), GFP_KERNEL);
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
//非oneway的通信方式,把当前thread保存到transaction的from字段
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
t->sender_euid = task_euid(proc->tsk);
t->to_proc = target_proc; //此次通信目标进程为servicemanager进程
t->to_thread = target_thread;
t->code = tr->code; //此次通信code = ADD_SERVICE_TRANSACTION
t->flags = tr->flags; // 此次通信flags = 0
t->priority = task_nice(current);
//从servicemanager进程中分配buffer
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
...
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
//根据binder查询binder实体对象
struct binder_node *node = binder_get_node(proc, fp->binder);
if (node == NULL) {
//服务所在进程 创建binder_node实体
node = binder_new_node(proc, fp->binder, fp->cookie);
...
}
//创建servicemanager进程binder_ref
ref = binder_get_ref_for_node(target_proc, node);
...
//调整type为HANDLE类型
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->binder = 0;
fp->handle = ref->desc; //设置handle值
fp->cookie = 0;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE, &thread->todo);
} break;
case :...
}
//将BINDER_WORK_TRANSACTION添加到目标队列,本次通信的目标队列为target_proc->todo
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
//将BINDER_WORK_TRANSACTION_COMPLETE添加到当前线程的todo队列
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
//唤醒等待队列,本次通信的目标队列为target_proc->wait
if (target_wait)
wake_up_interruptible(target_wait);
return;
}
binder_transaction()过程,会在服务所在进程创建binder_node, 在ServiceManager进程创建binder_ref,创建binder_ref过程来决定当前新的handle值, 该值从从1开始不断递增的。 注册的服务是MediaPlayerService,该对象经过writeStrongBinder()处理后扁平化为flat_binder_object对象,其类型为BINDER_TYPE_BINDER。binder_transaction()拆解过程,查询发起端进程是否为该服务创建过Binder实体对象,如果没有则需要新建Binder实体对象。然后在目标接收进程servicemanager创建指向该实体对象的Binder引用对象,并调整扁平化对象的handle值为刚创建的Binder引用对象中的值。 服务注册过程是在服务所在进程创建binder_node,在servicemanager进程创建binder_ref。对于同一个binder_node,每个进程只会创建一个binder_ref对象。
向当前线程todo队列添加BINDER_WORK_TRANSACTION_COMPLETE事务,表示驱动层已接收到用户空间发送的事务; 向servicemanager的todo添加BINDER_WORK_TRANSACTION事务,接下来进入ServiceManager进程。
小节5.2已介绍过ServiceManager进程启动后成为守护进程,等待其他进程通过binder发送请求, 服务进程将binder_transaction_data转换为binder_transaction结构体数据,ServiceManager进程再根据binder_transaction数据生成相应的binder_transaction_data结构体数据,回到ServiceManager进程用户空间收到数据则调用binder_parse来解析,根据BR_TRANSACTION协议,进入到svcmgr_handler过程,注册服务则对应do_add_service()方法。过程如图所示
5. ServiceManager
ServiceManager进程收到对端发送过程的Binder数据后调用binder_parse方法来处理,会调用svcmgr_handler()根据是注册服务,再进入do_add_service()方法,如果对底层不感兴趣的同学,只需要知道服务进程调用addService()方法,那么在整个过程不发生异常的情况下,则会执行service_manager中的do_add_service()方法。
如果是你从事系统相关工作,那么往往需要分析的就是异常情况,所以知道其整个流程还是有必要的,先来看看binder_parse(),代码如下。
// servicemanager/binder.c
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
...
while (ptr < end) {
uint32_t cmd = *(uint32_t *) ptr; //指向readbuf
switch(cmd) {
case BR_TRANSACTION: {
struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
if (func) { //func是指svcmgr_handler()函数
...
bio_init_from_txn(&msg, txn); //将binder_transaction_data信息解析成binder_io
res = func(bs, txn, &msg, &reply); //执行svcmgr_handler(), 见下文
if (txn->flags & TF_ONE_WAY) {
binder_free_buffer(bs, txn->data.ptr.buffer);
} else {
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res); //发送应答数据, 见下文
}
}
break;
}
...
}
}
return r;
}
上述方法主要工作是执行svcmgr_handler(),然后再发送应答数据给对端进程。
// service_manager.c
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
...
switch(txn->code) {
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len); //服务名
handle = bio_get_ref(msg); //服务实体在servicemanager中的handle
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
//注册指定服务, 见下文
if (do_add_service(bs, s, len, handle, txn->sender_euid,
allow_isolated, txn->sender_pid))
return -1;
break;
...
}
bio_put_uint32(reply, 0); //没有数据需要写入reply
return 0;
}
将服务名和服务实体在servicemanager进程中的handle值,一并写入到传入到do_add_service()方法
// service_manager.c
int do_add_service(struct binder_state *bs,
const uint16_t *s, size_t len,
uint32_t handle, uid_t uid, int allow_isolated,
pid_t spid)
{
struct svcinfo *si;
if (!handle || (len == 0) || (len > 127))
return -1;
//权限检查
if (!svc_can_register(s, len, spid)) {
return -1;
}
//服务检索
si = find_svc(s, len);
if (si) {
if (si->handle) {
svcinfo_death(bs, si); //服务已注册时释放相应的服务,对应BC_RELEASE
}
si->handle = handle;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); //内存拷贝服务信息
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist; // svclist保存所有已注册的服务
svclist = si;
}
//发送BC_ACQUIRE, 增加强引用计数
binder_acquire(bs, handle);
//发送BC_REQUEST_DEATH_NOTIFICATION,注册死亡通知
binder_link_to_death(bs, handle, &si->death);
return 0;
}
注册服务的过程,handle不能为0,由于0在全局有着特殊的意义,代表着servicemanager服务;服务名的长度也是有限制的,不允许服务名长度超过127个字节; 还有权限检查,并不是所有的进程都有权限向servicemanager进程注册服务, 必须同时满足应用uid小于10000,且具备注册服务的selinux权限要求。
先根据服务名在servicemanager进程的svclist列表来查询是否存在服务名等于”media.player”的svcinfo结构体,如果存在则先向驱动发送协议BC_RELEASE来释放该服务,并更新handle值;如果不存在,则分配内存创建新的svcinfo结构体,并填充handle,服务名等信息,以及加入到服务列表svclist。
发送BC_ACQUIRE,增加强引用计数保证目标服务不会提前被释放;发送BC_REQUEST_DEATH_NOTIFICATION,注册死亡通知,当目标服务所在进程被杀后会通知servicemanager进程,执行svcinfo_death(),发送BC_RELEASE用于释放对应服务的引用计数。
6. 小结
服务注册核心工作:在服务所在进程创建binder_node,在ServiceManager进程创建binder_ref。 其中binder_transaction(),将buffer区域中类型为BINDER_TYPE_BINDER的flat_binder_object数据转为变为BINDER_TYPE_HANDLE, 依据fp->binder, fp->cookie在当前进程创建binder_node结构体, 并在对端进程(此处为servicemanager进程)来创建binder_ref结构体, 在创建binder_ref结构体的过程会为其分配handle值; 并且修改其类型为BINDER_TYPE_HANDLE,以及清零fp->binder和fp->cookie。
- 每个进程binder_proc所记录的binder_ref的handle值是从1开始递增的;
- 所有进程binder_proc所记录的handle=0的binder_ref都指向ServiceManager
- 同一个服务的binder_node在不同进程的binder_ref的handle值可以不同;
Media服务注册的过程涉及到MediaPlayerService(作为Client进程)和Service Manager(作为Service进程),通信流程图如下所示:
过程分析:
- MediaPlayerService进程调用
ioctl()
向Binder驱动发送IPC数据,该过程可以理解成一个事务binder_transaction
(记为T1
),执行当前操作的线程binder_thread(记为thread1
),则T1->from_parent=NULL,T1->from =thread1
,thread1->transaction_stack=T1。其中IPC数据内容包含:- Binder协议为BC_TRANSACTION;
- Handle等于0;
- RPC代码为ADD_SERVICE;
- RPC数据为”media.player”。
-
Binder驱动收到该Binder请求,生成
BR_TRANSACTION
命令,选择目标处理该请求的线程,即ServiceManager的binder线程(记为thread2
),则 T1->to_parent = NULL,T1->to_thread =thread2
。并将整个binder_transaction数据(记为T2
)插入到目标线程的todo队列; -
Service Manager的线程
thread2
收到T2
后,调用服务注册函数将服务”media.player”注册到服务目录中。当服务注册完成后,生成IPC应答数据(BC_REPLY
),T2->form_parent = T1,T2->from = thread2, thread2->transaction_stack = T2。 - Binder驱动收到该Binder应答请求,生成
BR_REPLY
命令,T2->to_parent = T1,T2->to_thread = thread1, thread1->transaction_stack = T2。 在MediaPlayerService收到该命令后,知道服务注册完成便可以正常使用。
先通过一幅图来说说,media服务启动过程是如何向servicemanager注册服务的。
5.3.3 注册Java层服务
在Android系统开机过程中,Zygote启动时会有一个虚拟机注册过程,该过程调用AndroidRuntime.cpp中的startReg方法来完成jni方法的注册, gRegJNI是一个全局的数组,记录所有需要注册的jni方法。 其中一项REG_JNI(register_android_os_Binder),建立Java与JNI之间的关联,以便提供JNI与Java相互访问的功能。 Java层注册服务,最为核心的逻辑其实还是C++注册服务的过程,如图所示。
gBinderOffsets记录着Binder类, gBinderProxyOffsets记录着BinderProxy类,除了图中的其实还有gBinderInternalOffsets记录BinderInternal,这些映射都是为了用于JNI方法之间调用Java方法来提供通道。 Binder的REG_JNI过程,还有另一个功能是建立Java调用JNI提供通道, 其中gBinderMethods,gBinderProxyOffsets,gBinderInternalMethods依次分别记录Binder,BinderProxy, BinderInternal类中Java与JNI的映射关系;
1. ServiceManager
以WindowManagerService服务的注册过程为例, 代码如下所示。
// SystemServer.java
private void startOtherServices() {
...
ServiceManager.addService(Context.WINDOW_SERVICE, wm);
...
}
其中WINDOW_SERVICE值为”window“,wm代表的是WindowManagerService的实例化对象。
// ServiceManager.java
public static void addService(String name, IBinder service, boolean allowIsolated) {
try {
//先获取SMP对象,则执行注册服务操作
getIServiceManager().addService(name, service, allowIsolated);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
前面小节5.2.2介绍了C++层的defaultServiceManager等价于new BpServiceManager(new BpBinder(0)), 这里Java层的getIServiceManager()等价于new ServiceManagerProxy(new BinderProxy())。可见Java层逻辑跟C++层极为相近,事实也的确如此,Java注册服务的过程只是在Java层做了一个封装,将Java转换为C++后,交给C++层负责完成服务注册的核心逻辑。
2. 获取ServiceManager的Java层代理
// ServiceManager.java
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
BinderInternal.java中有一个native方法getContextObject(),JNI调用后执行的便是如下方法。
// android_util_binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b); //见下文
}
前面小节5.2.2已介绍过ProcessState::self()->getContextObject()等价于new BpBinder(0)。 再经过javaObjectForIBinder转换, 根据BpBinder(C++)生成BinderProxy(Java)对象.
// android_util_binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
AutoMutex _l(mProxyLock);
jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
if (object != NULL) { //第一次object为null
jobject res = jniGetReferent(env, object);
if (res != NULL) {
return res;
}
android_atomic_dec(&gNumProxyRefs);
val->detachObject(&gBinderProxyOffsets);
env->DeleteGlobalRef(object);
}
//创建BinderProxy对象
object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
if (object != NULL) {
//BinderProxy.mObject成员变量记录BpBinder对象,
env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
val->incStrong((void*)javaObjectForIBinder);
jobject refObject = env->NewGlobalRef(
env->GetObjectField(object, gBinderProxyOffsets.mSelf));
//将BinderProxy对象信息附加到BpBinder的成员变量mObjects
val->attachObject(&gBinderProxyOffsets, refObject,
jnienv_to_javavm(env), proxy_cleanup);
sp<DeathRecipientList> drl = new DeathRecipientList;
drl->incStrong((void*)javaObjectForIBinder);
//BinderProxy.mOrgue成员变量记录死亡通知对象
env->SetLongField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jlong>(drl.get()));
android_atomic_inc(&gNumProxyRefs);
incRefsCreated(env);
}
return object;
}
主要工作是创建BinderProxy对象, 然后进行如下设置:
- 通过BinderProxy.mObject记录BpBinder对象地址,实现了proxy拥有了native对象的引用
- 通过BpBinder的成员变量mObjects记录BinderProxy对象信息, 实现了native对象需要保存proxy对象的弱引用,当proxy还存在的时候,可以检索到同一个proxy。
- BinderProxy.mOrgue记录死亡通知对象DeathRecipientList
由此,可知ServiceManagerNative.asInterface(new BinderProxy()) 等价于new ServiceManagerProxy(new BinderProxy()),再来看看asInterface的过程。
// ServiceManagerNative.java
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) { //obj为BpBinder
return null;
}
//由于obj为BpBinder,该方法默认返回null
IServiceManager in = (IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj); //见下文
}
class ServiceManagerProxy implements IServiceManager {
public ServiceManagerProxy(IBinder remote) {
mRemote = remote; //将BinderProxy保存到mRemote
}
}
由此,可知ServiceManagerNative.asInterface(new BinderProxy())等价于new ServiceManagerProxy(new BinderProxy()). mRemote为BinderProxy对象,该BinderProxy对象的成员变量mObject记录着BpBinder(0),其作为binder代理端,指向大管家serviceManager进程的服务。
ServiceManager.getIServiceManager最终等价于new ServiceManagerProxy(new BinderProxy()),此处ServiceManagerProxy简称为SMP。framework层的ServiceManager的调用实际的工作确实交给SMP的成员变量BinderProxy;而BinderProxy通过jni方式,最终会调用BpBinder对象;可见上层binder架构的核心功能依赖native架构的服务来完成的。
3. SMP.addService
// ServiceManagerNative.java
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service); //见下文
data.writeInt(allowIsolated ? 1 : 0);
//mRemote为BinderProxy,见下文
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle();
data.recycle();
}
先来看看Java层的writeStrongBinder方法
// Parcel.java
public writeStrongBinder(IBinder val){
nativewriteStrongBinder(mNativePtr, val); //此处为Native调用
}
nativewriteStrongBinder此为Native调用所对应android_os_Parcel_writeStrongBinder方法,Parcel对象中的mNativePtr是在其init()过程赋值,记录C++的Parcel对象。
// android_os_Parcel.cpp
static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
if (parcel != NULL) {
//将java层Parcel转换为native层Parcel,见下文
const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
if (err != NO_ERROR) {
signalExceptionForError(env, clazz, err);
}
}
}
ibinderForJavaObject将Binder(Java)转换为Binder(C++)对象。
// android_util_Binder.cpp
sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
if (obj == NULL) return NULL;
//Java层的Binder对象
if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
JavaBBinderHolder* jbh = (JavaBBinderHolder*)
env->GetLongField(obj, gBinderOffsets.mObject);
return jbh != NULL ? jbh->get(env, obj) : NULL; //见下文
}
//Java层的BinderProxy对象
if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
return (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
}
return NULL;
}
根据Binde(Java)生成JavaBBinderHolder(C++)对象. 主要工作是创建JavaBBinderHolder对象,并把JavaBBinderHolder对象地址保存到Binder.mObject成员变量.
// android_util_Binder.cpp
sp<JavaBBinder> get(JNIEnv* env, jobject obj)
{
AutoMutex _l(mLock);
sp<JavaBBinder> b = mBinder.promote();
if (b == NULL) {
b = new JavaBBinder(env, obj); //首次进来,创建JavaBBinder对象
mBinder = b;
}
return b;
}
//JavaBBinder的初始化
JavaBBinder(JNIEnv* env, jobject object)
: mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
{
android_atomic_inc(&gNumLocalRefs);
incRefsCreated(env);
}
创建JavaBBinder对象,该对象承于BBinder对象。再将JavaBBinder保存在Holder有一个成员变量mBinder,这是一个wp类型的,可能会被垃圾回收器给回收,所以每次使用前,都需要先判断是否存在。
data.writeStrongBinder(service)最终等价于parcel->writeStrongBinder(new JavaBBinder(env, obj)), 而对于writeStrongBinder()过程,前面小节5.2已介绍过。
再回到SMP.addService()过程,则接下来进入transact。
4. BinderProxy.transact
// Binder.java
public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
//用于检测Parcel大小是否大于800k
Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
return transactNative(code, data, reply, flags); //Native方法, 见下文
}
transactNative()所对应的方法为android_os_BinderProxy_transact
//android_util_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
jint code, jobject dataObj, jobject replyObj, jint flags)
{
...
//java Parcel转为native Parcel
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
...
//gBinderProxyOffsets.mObject中保存的是new BpBinder(0)对象
IBinder* target = (IBinder*)env->GetLongField(obj, gBinderProxyOffsets.mObject);
...
//此处便是BpBinder::transact(), 经过native层进入Binder驱动程序
status_t err = target->transact(code, *data, reply, flags);
return JNI_FALSE;
}
Java层的BinderProxy.transact()最终交由C++层的BpBinder的transact()来完成。可见,Java层注册服务的过程主要是需要将Java世界的东西转换到C++层,然后调用C++层祝注册服务的方法。
总结下, Java层的addService的核心过程,其主干代码等价于如下。
public void addService(String name, IBinder service, boolean allowIsolated)
throws RemoteException {
...
Parcel data = Parcel.obtain(); //此处还需要将java层的Parcel转为Native层的Parcel
data->writeStrongBinder(new JavaBBinder(env, obj));
BpBinder::transact(ADD_SERVICE_TRANSACTION, *data, reply, 0); //与Binder驱动交互
...
}
注册服务过程就是通过BpBinder来发送ADD_SERVICE_TRANSACTION命令,与实现与binder驱动进行数据交互。
微信公众号 Gityuan | 微博 weibo.com/gityuan | 博客 留言区交流