ServiceManager的getService流程

1、 getIServiceManager获取servicemanager服务

sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
a、 BinderInternal.getContextObject()是个什么
跟踪到base/core/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);
}

先看第一行,ProcessState是一个单例,从名字看和进程状态相关,路径为native/libs/binder/ProcessState.cpp
getStrongProxyForHandle(0)中默认传入为0,servicemanager的handler为0,在该函数中会传入handler创建BpBinder对象并返回。
接下来调用javaObjectForIBinder,其中有判断是不是一个Binder对象,显然不是。然后判断是不是存在BinderProxy,也不满足。所以创建一个新的BinderProxy,其中mObject指向BpBinder对象,BpBinder对象也保存BinderProxy对象的一个引用并返回BinderProxy对象。至此,可以得知BinderInternal.getContextObject()返回的实际就是一个BinderProxy对象。
b、 接下来分析ServiceManagerNative.asInterface(BinderProxy对象)
由于BinderProxy.queryLocalInterface会返回null,所以此处会返回ServiceManagerProxy对象,mRemote为BinderProxy对象。


2、 接下来分析ServiceManagerProxy的getService

a、 创建两个parcel对象,一个是用于保存传输的数据,一个用于保存返回的数据,实际是创建两个native层的parcel对象,然后将”android.os.IServiceManager”和service name保存到传输数据的parcel对象中mData中,通过mData+mDataPos来定位,用0隔开。
b、 来到重头戏mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0),从前面知道mRemote是BinderProxy对象。直接跳到android_util_Binder.cpp 中的android_os_BinderProxy_transact函数:

IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);

这个target指针就是之前说的BpBinder对象,所以实际就是调用BpBinder的transact

status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);

IPCThreadState也是个单例,保存线程相关信息,在它的transact中有两个重要调用
writeTransactionData和waitForResponse。
先来分析writeTransactionData,这里创建了一个binder_transaction_data结构体,然后把之前保存parcel中的数据填入这个结构体中,这里以指针的方式传递。注意到这里有offsets_size和data.ptr.offsets,这两个一起用来指向flat_binder_object结构体在mData的指针位置。接下来,把cmd和这个binder_transaction_data结构体填充到parcel mOut中。
waitForResponse中会调用talkWithDriver,该函数的作用就是将mOut的data传递给内核。在这里,又创建了一个结构体binder_write_read,并用write_buffer保存data的数据。最后通过如下方法完成与内核的通信

ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0

这里的mDriverFD实际是binder驱动的设备描述符,我们看下ProcessState的初始化就可以得知其来源

ProcessState::ProcessState(const char *driver)
    : mDriverName(String8(driver))
, mDriverFD(open_driver(driver))

open_driver(driver)完成如下几个工作:
1)、open(driver, O_RDWR | O_CLOEXEC)打开设备获取设备描述符
2)、ioctl(fd, BINDER_VERSION, &vers);告知binder版本号
3)、ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);告知内核支持的最大线程数量,这里默认是15,加上原来初始化一个线程,最多同时支持16个binder调用。
然后在ProcessState的构造函数中,完成与内核的内存映射

mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);

从BINDER_VM_SIZE我们可以得知,为什么Binder调用对数据传递的大小有限制了

#define BINDER_VM_SIZE ((2 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

3、 内核驱动drivers/android/binder.c

a、 binder_ioctl方法
其中有两个结构体binder_proc和binder_thread,与之对应的就是ProcessState和IPCThreadState,binder_proc中用红黑树保存binder_thread。传递数据用的cmd是BINDER_WRITE_READ,所以调用binder_ioctl_write_read
b、 binder_ioctl_write_read方法
这里出现了binder_write_read,与native的binder_write_read是一致的。然后

copy_from_user(&bwr, ubuf, sizeof(bwr))

完成从用户缓存区到内核的一次数据拷贝,由于这是一次write操作,所以bwr.write_size > 0,接下来调用binder_thread_write
c、 binder_thread_write方法
由于之前writeTransactionData传入的cmd为BC_TRANSACTION,所以case走到BC_TRANSACTION创建binder_transaction_data,之前有把cmd和binder_transaction_data放到mOut中,然后将mOut的数据放到binder_thread_write的write_buffer中。接着调用copy_from_user填充其内部信息,调用binder_transaction
d、 binder_transaction方法
这里reply为0,所以直接来到tr->target.handle,这个handler实际就指的servicemanager的handler,也就是0。看到target_node的赋值

target_node = context->binder_context_mgr_node;

这下要看看binder_context_mgr_node的来源了,在binder_ioctl_set_ctx_mgr函数中有给binder_context_mgr_node赋值,那么它什么时候被调用呢?收到cmd为BINDER_SET_CONTEXT_MGR时,它会被调用。原来是service_manager在main函数中有通知binder驱动,我就是这个binder_context_mgr_node对应的进程。
接下来创建了一个binder_transaction结构体,目的是将binder_transaction_data的数据拷贝目标进程的内核缓冲区中,其work.type为BINDER_WORK_TRANSACTION。这里又再一次出现offsets_size和data.ptr.offsets,表示的是binder偏移,这个在addService中用到,这里会创建binder本地对象和binder引用对象并生成handler。还有另外一个binder_work结构体,在调用binder_enqueue_work后将其添加到了源线程的队列中处理,源线程将会接收到BINDER_WORK_TRANSACTION_COMPLETE。那么binder_transaction结构体的用处呢?
来看下binder_proc_transaction函数就明白了,完成了三个主要功能
1)、获取目标线程

扫描二维码关注公众号,回复: 1822390 查看本文章
thread = binder_select_thread_ilocked(proc);

2)、将binder_transaction结构体内部成员binder_work加到目标线程队列中

binder_enqueue_work_ilocked(&t->work, target_list);

3)、唤醒目标线程

binder_wakeup_thread_ilocked(proc, thread, !oneway /* sync */);

e、 binder_thread_read方法
这个方法已经运行到目标线程的内核缓存区了。service_manager在main函数中通过ioctl已经调用了该方法。线程从wait状态被唤醒,获取在thread中list元素,即binder_work。之前传入的type为BINDER_WORK_TRANSACTION,所以通过如下方式获取binder_transaction,container_of的作用是根据结构体内部成员找到该结构体的首地址。

t = container_of(w, struct binder_transaction, work);

然后就是解析binder_transaction的数据到binder_transaction_data中,且cmd = BR_TRANSACTION,并通过

copy_to_user(ptr, &tr, sizeof(tr)

将binder_transaction_data放到binder_write_read结构体的buffer中,由于内存映射,所以service_manager将会收到这个数据。


4、 service_manager.c

a、 它是个native的服务,初始化比较简单,直接来到binder_parse
由于接收到是cmd是BR_TRANSACTION,所以会调用回调函数svcmgr_handler,之前写入parcel的为GET_SERVICE_TRANSACTION值为1,对应这里的SVC_MGR_GET_SERVICE。接着就是调用do_find_service。
b、 do_find_service函数
主要功能是从svclist表中找到service name一致的svcinfo,然后返回该svcinfo的handler,实际这个handler就是addService的时候,binder驱动分配给binder的唯一标识。然后这个handler会用binder_io封装。然后调用binder_send_reply。
c、 binder_send_reply函数
将binder_io填入到data结构体中,type为BINDER_TYPE_HANDLE,并调用binder_write发送数据给binder驱动。


5、 drivers/android/binder.c

又回到了binder驱动,前面的流程大致相同,但是这里传入的是BC_REPLY,那么我们来看下binder_transaction的replay处理。
in_reply_to = thread->transaction_stack;
注意现在在servicemanager的内核缓冲区中,transaction_stack及n_reply_to->to_thread是在binder_thread_read方法被赋值的,所以前面if条件不满足。这里需要去获取target_thread,只有知道目标线程是谁,才能把数据返回给对应的进程。

target_thread = binder_get_txn_from_and_acq_inner(in_reply_to);
target_proc = target_thread->proc;

接下来的处理就与之前的分析类似了,唤醒target_thread,cmd为BR_REPLY,在binder_thread_read中通过copy_to_user,在IPCThreadState的waitForResponse中处理,将数据读取到mIn中。


6、 从Parcel中提取Binder代理

waitForResponse中的talkWithDriver会接收到数据,即mIn.data()中接收到数据。所以流程会走到BR_REPLY,此处创建binder_transaction_data结构体,并将data中的数据拷贝到该结构体。由于replay不为空,所以
reply->ipcSetDataReference
将结构体赋值给replay这个parcel对象。
接下来通过如下方法获取BpBinder。
IBinder binder = reply.readStrongBinder();
我们来看下parcel.cpp中最终返回BpBinder的方法unflatten_binder
这里的flat->type在service_manager中已经赋值为BINDER_TYPE_HANDLE,所以接下来执行如下语句

*out = proc->getWeakProxyForHandle(flat->handle);
return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->unsafe_get()), *flat, in);

第一个方法会返回一个BpBinder对象,而第二个方法仅仅是return了NO_ERROR。
而在javaObjectForIBinder中返回是包裹了这个BpBinder对象的BinderProxy对象。至此getService流程结束。

猜你喜欢

转载自blog.csdn.net/rhythmjay/article/details/80538588