这一次,binder真正理解了(五) ----- Binder中Service的查询(获取)

tech2024-03-31  67

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支持进程间通信也支持同一进程通信。

最新回复(0)