这一次,binder真正理解了(五) ----- Binder中Service的查询(获取)
Service的查询(获取)
概述
在上篇中,我们了解binder数据的写入,以及Client和Service进程的一次进程间通信。在前文中一直反复强调ServiceManager的功能是注册服务,和让client获取服务。到这篇文章中,大家应该对binder有了明显的认识了吧。
在 binder 架构中,Service
要先向ServiceManager
上报自身的名字(全限定名),ServiceManager
存储着Service
的名字,客户端并不知道服务的位置,所以需要跟名字服务器(ServiceManager)查询。
同样的,和上文一样我们知道我们最终使用的对象是 BpServiceManager
,这一篇我们也从这里开始分析。
注: Binder系列文章 framework 源码使用 android10 release 分支,kernel 部分使用 common 的 android-4.9-q-release 分支。
framework/native/libs/binder/
- Binder.cpp
- BpBinder.cpp
- IPCThreadState.cpp
- ProcessState.cpp
- IServiceManager.cpp
- IInterface.cpp
- Parcel.cpp
frameworks/native/include/binder/
- IInterface.h
BpServiceManager::getService
// frameworks/native/libs/binder/IServiceManager.cpp
virtual sp<IBinder> getService(const String16& name) const
{
sp<IBinder> svc = checkService(name);
if (svc != nullptr) return svc;
const bool isVendorService =
strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
const long timeout = uptimeMillis() + 5000;
if (!gSystemBootCompleted && !isVendorService) {
// Vendor code can't access system properties
char bootCompleted[PROPERTY_VALUE_MAX];
property_get("sys.boot_completed", bootCompleted, "0");
gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
}
// retry interval in millisecond; note that vendor services stay at 100ms
const long sleepTime = gSystemBootCompleted ? 1000 : 100;
int n = 0;
while (uptimeMillis() < timeout) {
n++;
ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
ProcessState::self()->getDriverName().c_str());
usleep(1000*sleepTime);
sp<IBinder> svc = checkService(name); //TAG1
if (svc != nullptr) return svc;
}
ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
return nullptr;
}
检索服务是否存在,在规定时间内循环获取服务,当服务存在则返回相应的服务。
看TAG1,我们可以看到 可以看到,实际上是调用 checkService()
来获取真正的服务。
// frameworks/native/libs/binder/IServiceManager.cpp
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder(); //TAG1
}
这边我们在前文中讲过 remote()->transact()
, remote()->transact()
调用的是BpBinder
的 transact()
函数,然后到IPCThreadState
,最后写入 binder 驱动。整个流程可以参考上篇文章。
我们先带大家看下binder_transaction
部分代码
再接着看TAG1 reply.readStrongBinder()
binder_transaction
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply){
//根据各种判定,获取以下信息:
struct binder_thread *target_thread; //目标线程
struct binder_proc *target_proc; //目标进程
struct binder_node *target_node; //目标binder节点
struct list_head *target_list; //目标TODO队列
wait_queue_head_t *target_wait; //目标等待队列
...
//分配两个结构体内存
struct binder_transaction *t = kzalloc(sizeof(*t), GFP_KERNEL);
struct binder_work *tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
//从target_proc分配一块buffer
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
for (; offp < off_end; offp++) {
switch (fp->type) {
case BINDER_TYPE_BINDER: ...
case BINDER_TYPE_WEAK_BINDER: ...
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct binder_ref *ref = binder_get_ref(proc, fp->handle,
fp->type == BINDER_TYPE_HANDLE);
...
//此时运行在servicemanager进程,故ref->node是指向服务所在进程的binder实体,
//而target_proc为请求服务所在的进程,此时并不相等。
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
else
fp->type = BINDER_TYPE_WEAK_BINDER;
fp->binder = ref->node->ptr;
fp->cookie = ref->node->cookie; //BBinder服务的地址
binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
} else {
struct binder_ref *new_ref;
//请求服务所在进程并非服务所在进程,则为请求服务所在进程创建binder_ref
new_ref = binder_get_ref_for_node(target_proc, ref->node);
fp->binder = 0;
fp->handle = new_ref->desc; //重新赋予handle值
fp->cookie = 0;
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
}
} break;
case BINDER_TYPE_FD: ...
}
}
//分别target_list和当前线程TODO队列插入事务
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
if (target_wait)
wake_up_interruptible(target_wait);
return;
}
- 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;
- 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
Parcel::readStrongBinder()
// frameworks/native/libs/binder/Parcel.cpp
status_t Parcel::readStrongBinder(sp<IBinder>* val) const
{
status_t status = readNullableStrongBinder(val);
if (status == OK && !val->get()) {
status = UNEXPECTED_NULL;
}
return status;
}
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
return unflatten_binder(ProcessState::self(), *this, val);
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, wp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->hdr.type) {
case BINDER_TYPE_BINDER:
// 当请求服务的进程与服务属于同一进程
*out = reinterpret_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_WEAK_BINDER:
if (flat->binder != 0) {
out->set_object_and_refs(
reinterpret_cast<IBinder*>(flat->cookie),
reinterpret_cast<RefBase::weakref_type*>(flat->binder));
} else {
*out = nullptr;
}
return finish_unflatten_binder(nullptr, *flat, in);
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE:
//请求服务的进程与服务属于不同进程
*out = proc->getWeakProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->unsafe_get()), *flat, in);
}
}
return BAD_TYPE;
}
-
BINDER_TYPE_BINDER
当请求服务的进程与服务属于同一进程 -
BINDER_TYPE_HANDLE
请求服务的进程与服务属于不同进程,我们这边先看下不同进程间的调用关系
ProcessState::getWeakProxyForHandle
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//查找handle对应的资源项
handle_entry* e = lookupHandleLocked(handle);
if (e != nullptr) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == nullptr || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, nullptr, 0);
if (status == DEAD_OBJECT)
return nullptr;
}
b = BpBinder::create(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
我们先查询是否存在跟这个handle
对应的BpBinder
, 当handle
值所对应的BpBinder
不存在或弱引用无效时,则创建BpBinder
对象。所以,对于同一个handle
,只会生成一个BpBinder
。
ProcessState:: handle_entry
ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
const size_t N=mHandleToObject.size();
if (N <= (size_t)handle) {
handle_entry e;
e.binder = nullptr;
e.refs = nullptr;
//从mHandleToObject的第N个位置开始,插入(handle+1-N)个e到队列中
status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
if (err < NO_ERROR) return nullptr;
}
return &mHandleToObject.editItemAt(handle);
}
根据handle值来查找对应的handle_entry。
拿到BpBinder对象,我们得到服务的整体流程至此。
总结
如果查询的服务跟自己在同一个进程,就会直接返回对应的BBinder
,拿到BBinder
后的都只是进程内函数的直接调用,不需要再通过binder
驱动。
服务查询过程,验证了我们开头的图,就是向serviceManager进程查询指定服务,当执行binder_transaction(),会区分请求的Service所属进程情况。
- 当请求服务的进程与服务属于不同进程,则为请求服务所在进程创建binder_ref对象,指向服务进程中的binder_node;
最终readStrongBinder(),返回的是BpBinder对象; - 当请求服务的进程与服务属于同一进程,则不再创建新对象,只是引用计数加1,并且修改type为BINDER_TYPE_BINDER或BINDER_TYPE_WEAK_BINDER。
最终readStrongBinder(),返回的是BBinder对象的真实子类
这个也就是我们平时在应用开发时,如果服务在同一个进程,AIDL 并不会走进程间通信,binder支持进程间通信也支持同一进程通信。
下一篇: woss项目