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
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
) {
char bootCompleted
[PROPERTY_VALUE_MAX
];
property_get("sys.boot_completed", bootCompleted
, "0");
gSystemBootCompleted
= strcmp(bootCompleted
, "1") == 0 ? true
: false
;
}
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
);
if (svc
!= nullptr
) return svc
;
}
ALOGW("Service %s didn't start. Returning NULL", String8(name
).string());
return nullptr
;
}
检索服务是否存在,在规定时间内循环获取服务,当服务存在则返回相应的服务。 看TAG1,我们可以看到 可以看到,实际上是调用 checkService() 来获取真正的服务。
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();
}
这边我们在前文中讲过 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;
struct list_head
*target_list;
wait_queue_head_t
*target_wait;
...
struct binder_transaction
*t
= kzalloc(sizeof(*t
), GFP_KERNEL
);
struct binder_work
*tcomplete
= kzalloc(sizeof(*tcomplete
), GFP_KERNEL
);
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
);
...
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
;
binder_inc_node(ref
->node
, fp
->type
== BINDER_TYPE_BINDER
, 0, NULL);
} else {
struct binder_ref
*new_ref
;
new_ref
= binder_get_ref_for_node(target_proc
, ref
->node
);
fp
->binder
= 0;
fp
->handle
= new_ref
->desc
;
fp
->cookie
= 0;
binder_inc_ref(new_ref
, fp
->type
== BINDER_TYPE_HANDLE
, NULL);
}
} break;
case BINDER_TYPE_FD
: ...
}
}
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()
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_entry
* e
= lookupHandleLocked(handle
);
if (e
!= nullptr
) {
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 {
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
;
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支持进程间通信也支持同一进程通信。