3.4 getService()分析
clinet中获取service接口的调用如下:
sp<ISampleService> sampleSrv;
if(getService(String16("SampleService"), &sampleSrv) != NO_ERROR){
ALOGE("get SampleService fail");
return 0;
}
getService()实现如下:
template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != NULL) {
*outService = interface_cast<INTERFACE>(sm->getService(name));
if ((*outService) != NULL) return NO_ERROR;
}
return NAME_NOT_FOUND;
}
这其中获取ServiceManager接口的动作,前面已经分析过了。之后有两个动作:
1,sm->getService(name)获取到一个sp<IBinder>对象。
2,从获取的BpBinder指针中构造出BpSampleService对象。
第二步是很清楚的,就是调用了BpSampleService::interface_cast<ISampleService>(sp<IBinder>)。我们主要需要研究一下第一步的细节。
3.4.1 BpServiceManager::getService()
BpServiceManager::getService()是调用了checkService()函数
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep(1);
}
return NULL;
}
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();
}
checkService()中之写入了InterfaceToken和servicename,然后就开始了transact()了。
这边的transact因为没有写入object,流程和PING_TRANSACTION的基本一样了。我们直接到ServiceManager端看看具体的处理。
3.4.2 ServiceManager处理CHECK_SERVICE_TRANSACTION
command和ADD_SERVICE一样在svcmgr_handler()中处理
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
//获取service name。
s = bio_get_string16(msg, &len);
//查找对应的service。
ptr = do_find_service(bs, s, len, txn->sender_euid);
if (!ptr)
break;
bio_put_ref(reply, ptr);
return 0;
主要看下do_find_service()
void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
{
//根据service name找到对应的svcinfo结点。
struct svcinfo *si;
si = find_svc(s, len);
// ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
if (si && si->ptr) {
if (!si->allow_isolated) {
// If this service doesn't allow access from isolated processes,
// then check the uid to see if it is isolated.
unsigned appid = uid % AID_USER;
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
return 0;
}
}
//返回结点中的ptr,这个ptr是binder中对应的binder_ref.desc。
return si->ptr;
} else {
return 0;
}
}
我们看到了最终返回的是SampleService在ServiceManager这边对应的binder_ref的desc信息,之后这个信息被写入到write buffer中:
void bio_put_ref(struct binder_io *bio, void *ptr)
{
//构造了一个binder_object,也就是一个flat_binder_object。
struct binder_object *obj;
if (ptr)
obj = bio_alloc_obj(bio);
else
obj = bio_alloc(bio, sizeof(*obj));
if (!obj)
return;
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->type = BINDER_TYPE_HANDLE;
obj->pointer = ptr;
obj->cookie = 0;
}
之后进入binder_send_reply(),在这里,我们write了BC_FREE_BUFFER,还有一组BC_REPLY信息,BC_REPLY信息中,是在bio_put_ref()中构造的binder_object。
带着这些信息,我们进入到binder中,首先在binder_thread_write()中处理BC_FREE_BUFFER,这边的处理和之前的PING_TRANSACTION基本一致,没有object,释放掉binder_buffer就可以了。
然后处理BC_REPLY,主要在binder_transaction()函数中,这里和addService处理差异在于reply信息是一个object,而不是一个数据,我们看下组织binder_transaction的部分:
//remote binder object, means BpBinder。
case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
struct binder_ref *ref = binder_get_ref(proc, fp->handle);
if (ref == NULL) {
binder_user_error("%d:%d got transaction with invalid handle, %ld\n",
proc->pid,
thread->pid, fp->handle);
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
if (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
//如果传给service所在的进程,转换为BINDER_TYPE_BINDER类型的object。
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);
trace_binder_transaction_ref_to_node(t, ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> node %d u%p\n",
ref->debug_id, ref->desc, ref->node->debug_id,
ref->node->ptr);
} else {//传入到其他client进程,为目标进程建立新的binder_ref,并传回这个新的binder_ref的信息。
struct binder_ref *new_ref;
new_ref = binder_get_ref_for_node(target_proc, ref->node);//第一次会建立一个新的binder_ref。
if (new_ref == NULL) {
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
fp->handle = new_ref->desc;//用目标进程desc替换。
binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
trace_binder_transaction_ref_to_ref(t, ref,
new_ref);
binder_debug(BINDER_DEBUG_TRANSACTION,
" ref %d desc %d -> ref %d desc %d (node %d)\n",
ref->debug_id, ref->desc, new_ref->debug_id,
new_ref->desc, ref->node->debug_id);
}
} break;
在这里,binder会为client进程建立一个新的binder_ref出来,他会在当前进程中得到一个唯一的desc也就是handle值,注意desc值0是保留给了ServiceManager,最终我们把这个handle回填到data中。
3.4.3 client端处理返回信息
client在IPCThreadState::waitForResponse()处理BR_REPLY,数据传递给Parcel reply中,最终调用得到了sp<IBinder>对象。
reply.readStrongBinder();
我们看看readStrongBinder()里面做了什么:
sp<IBinder> Parcel::readStrongBinder() const
{
sp<IBinder> val;
unflatten_binder(ProcessState::self(), *this, &val);
return val;
}
status_t unflatten_binder(const sp<ProcessState>& proc,
const Parcel& in, sp<IBinder>* out)
{
const flat_binder_object* flat = in.readObject(false);
if (flat) {
switch (flat->type) {
case BINDER_TYPE_BINDER:
*out = static_cast<IBinder*>(flat->cookie);
return finish_unflatten_binder(NULL, *flat, in);
case BINDER_TYPE_HANDLE:
//查找对应的BpBinder对象。
*out = proc->getStrongProxyForHandle(flat->handle);
return finish_unflatten_binder(
static_cast<BpBinder*>(out->get()), *flat, in);
}
}
return BAD_TYPE;
}
最终还是调用了getStrongproxyForHandle()来获取了sp<IBinder>,参数的handle就是在binder中的binder_ref.desc。
getStrongproxyForHandle()中创建BpBinder的动作,我们就不在看了,我们看一下如果不是首次调用的情况下的处理:
} 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.
//force_set()函数和直接赋值的差异在于它会强制调用RefBase.onFirstRef(),对这里来说
//也就是会出发BpBinder.onFirstRef()。
result.force_set(b);
e->refs->decWeak(this);
}
这段代码中主要注意一下result.fore_set(b)这行代码,这里又强制触发了一次RefBase.onFirstRef(),调用的目的是对binder中的binder_ref增加了一次引用。
但是这里有个问题:
force_set对于binder_ref又增加了一次reference,但是因为他们用的都是同意BpBinder,最终只会调用一次onLastStrongRef()去decrease strong reference,这样会导致ref的增减不同步,可能是会有问题的。(加了debug信息确认,的确是会出现这样的问题的。)
至此,getService()部分分析完毕,我们看到了service的传递主要是依赖binder对于binder_ref的管理,binder_ref.desc决定了在user层的handle,user层又使用handle去建立了一个BpBinder,所有的service访问结构都是使用这个BpBinder构造出BpXXX对象来操作service接口。
3.5 sayHello()调用分析
这部分我们分析下client端调用SampleService的sayHello()接口的流程,看看client端是如何把信息投递到service进程中去的。
3.5.1 sayHello() client调用
virtual int sayHello(const String8& clientName){
Parcel data,reply;
data.writeInterfaceToken(ISampleService::getInterfaceDescriptor());