一、前言
我们在前文讨论了Service
是怎么添加到ServiceManager
的,说完了添加,我们来看下获取的过程,由于过程中很多东西都是一样的,所以获取的分析过程就稍显容易。
针对Service
的获取,我们还是从Native层入手,对象还是SurfaceFlinger
。
二、源码分析
2.1 Surface
系统中的getService
我们找一下SurfaceFlinger
在native层中的使用,找到这样一段逻辑:
frameworks\native\libs\gui\SurfaceComposerClient.cpp
c++
bool ComposerService::connectLocked() {
const String16 name("SurfaceFlinger");
mComposerService = waitForService<ISurfaceComposer>(name);
if (mComposerService == nullptr) {
return false; // fatal error or permission problem
}
return true;
}
template<typename INTERFACE>
sp<INTERFACE> waitForService(const String16& name) {
const sp<IServiceManager> sm = defaultServiceManager();
return interface_cast<INTERFACE>(sm->waitForService(name));
}
我们在之前的分析中已经知道,defaultServiceManager
最终返回的是ServiceManagerShim
,最终起作用的是BpServiceManager
,而waitForService
实质上是getService
实现的。接下来,我们还是进入BpServiceManager
看下后续的逻辑:
2.2 BpServiceManager
的getService
BpServiceManager
是由aidl
生成的,其checkService
方法为:
c++
::android::binder::Status BpServiceManager::getService(const ::std::string &name,::android::sp<::android::IBinder> *_aidl_return)
{
::android::Parcel _aidl_data;
_aidl_data.markForBinder(remoteStrong());
::android::Parcel _aidl_reply;
::android::status_t _aidl_ret_status = ::android::OK;
::android::binder::Status _aidl_status;
_aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
_aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
_aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_getService, _aidl_data, &_aidl_reply, 0);
_aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
_aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
if (((_aidl_ret_status) != (::android::OK)))
{
goto _aidl_error;
}
return _aidl_status;
}
这里remote()
代表的是BpBinder(0)
,然后直接进行transact
,我们知道这会经过IPCThreadState
,然后进入内核层,与addService
一致,然后进入ServiceManager
进程,最后由BnServiceManager
来处理事务。
中间通信过程基本同addService
,我们来看BnServiceManager
的逻辑:
2.3 BnServiceManager
的onTransact
c++
case BnServiceManager::TRANSACTION_getService:
{
::std::string in_name;
//读取name
::android::sp<::android::IBinder> _aidl_return;
_aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
//调用真正实现
::android::binder::Status _aidl_status(getService(in_name, &_aidl_return));
_aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
//将获取到的IBinder对象写入reply
_aidl_ret_status = _aidl_reply->writeStrongBinder(_aidl_return);
}
-
1、首先获取
Service
的name
-
2、调用
ServiceManager
的getService
真正实现 -
3、写入
reply
我们来看下真正的getService
实现:
frameworks\native\cmds\servicemanager\ServiceManager.cpp
c++
Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
*outBinder = tryGetService(name, true);
// returns ok regardless of result for legacy reasons
return Status::ok();
}
sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
auto ctx = mAccess->getCallingContext();
sp<IBinder> out;
Service* service = nullptr;
if (auto it = mNameToService.find(name); it != mNameToService.end()) {
service = &(it->second);
if (!service->allowIsolated) {
//...
}
out = service->binder;
}
return out;
}
还记得我们之前存储的Map
吗?这里我们从Map
中通过Name
取出了我们需要的IBinder
对象,也就是BpBinder
对象,这个对象中含有handle
值。
拿到BpBinder
之后,我们需要返回给对端,回到刚才的writeStrongBinder
方法,这次内部的分支要发生变化了:
2.3.1 BpBinder
与writeStrongBinder
我们看下Parcel
中的实现:
c++
status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
if (isForRpc()) {
//...
}
flat_binder_object obj;
obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
if (binder != nullptr) {
BBinder *local = binder->localBinder();
if (!local) {
BpBinder *proxy = binder->remoteBinder();
const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
obj.hdr.type = BINDER_TYPE_HANDLE;
obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
obj.handle = handle;
obj.cookie = 0;
} else {
//...
}
} else {
//...
}
obj.flags |= schedBits;
status_t status = writeObject(obj, false);
if (status != OK) return status;
return finishFlattenBinder(binder);
}
这次我们的local
为空,然后给flat_binder_object
赋值,此时类型为BINDER_TYPE_HANDLE
,handle
值为我们设置进去的那个,既然flat_binder_object
有所调整,Binder驱动中的逻辑也会有所调整,首先是binder_transaction
:
2.3.2 binder_transaction
的变化
此时binder_transaction
中的type发生变化,对应的case有所调整:
c++
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct flat_binder_object *fp
fp = to_flat_binder_object(hdr);
//调用binder_translate_handle
ret = binder_translate_handle(fp, t, thread);
if (ret < 0 ||
binder_alloc_copy_to_buffer(&target_proc->alloc,
t->buffer,
object_offset,
fp, sizeof(*fp))) {
//...
}
} break;
其对flat_binder_object
的使用变成了binder_translate_handle
:
c++
static int binder_translate_handle(struct flat_binder_object *fp,
struct binder_transaction *t,
struct binder_thread *thread)
{
struct binder_proc *proc = thread->proc;
struct binder_proc *target_proc = t->to_proc;
struct binder_node *node;
struct binder_ref_data src_rdata;
int ret = 0;
//获取Binder节点
node = binder_get_node_from_ref(proc, fp->handle,
fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata);
if (node->proc == target_proc) {
//如果调用和目标是同个进程
//我们这里不是同个进程
//...
} else {
struct binder_ref_data dest_rdata;
//增加引用计数,更新handle值
ret = binder_inc_ref_for_node(target_proc, node,
fp->hdr.type == BINDER_TYPE_HANDLE,
NULL, &dest_rdata);
fp->binder = 0;
fp->handle = dest_rdata.desc;
fp->cookie = 0;
}
done:
binder_put_node(node);
return ret;
}
-
1、首先获取
handle
对应的Binder节点 -
2、如果调用和目标不是同个进程,对Binder节点引用计数+1
-
3、更新返回handle值
ServiceManager
中保存着Service
的引用,也就是handle
,通过这个handle
,Binder驱动找到了其对应的Binder节点,然后修改对该节点的引用,因为调用getService
之后,代表有一个新的地方引用了该对象,在修改完引用之后,将handle
更新,最后将flat_binder_object
再写入到客户端进程中。
2.4 回到BpServiceManager
我们回头再看下,回到getService
中,我们想要的是_aidl_return
,我们已经知道readNullableStrongBinder
就是根据handle
创建BpBinder
,最后,我们拿到了Service
的代理,那就是BpBinder
。
2.5 接口的实现
拿到BpBinder
之后,用户进程是不能直接使用的,因为没有用户进程想要的接口,这时interface_cast
就起作用了,经过interface_cast
之后,BpBinder
就变成了BpSurfaceComposer
。
三、总结
通过ServiceManager
获取Service
的过程,也是一个IPC
过程,其中,ServiceManager
持有Service
的句柄handle
,在经过Binder通信之后,handle
被更新,对应Binder节点的引用计数增加,然后返回给用户进程,用户进程拿到handle
之后,将其初始化为BpBinder
,然后将BpBinder
转换为实现了接口的Bp类,从此用户进程就可以通过此Bp类进行快乐的IPC
通信了~
由于getService
本身也是IPC
通信,所以我们能看到很多地方会做缓存,只需要获取一次就够了。