6.3 Client端获取服务代理

以上分析了Java系统服务的创建和注册过程,本节分析Client端如何使用Service。

如果Client端需要使用Java系统服务,通常使用SDK提供的getSystemService接口。本节以getSystemService接口为例,详细分析Client是如何获取Server端的Proxy对象的。Java系统服务有很多,但其使用方法是一致的。这里仍以power服务为例,代码如下:


PowerManager pm=(PowerManager)this.

getSystemService(Context.POWER_SERVICE);


其中this是一个Context类型的对象,参数Context.POWER_SERVICE是要请求的服务名power。getSystemService方法位于Context的实现类ContextImpl中,代码如下:


public Object getSystemService(String name){

ServiceFetcher fetcher=SYSTEM_SERVICE_MAP.get(name);

return fetcher==null?null:fetcher.getService(this);

}


getSystemService根据Service的名字从SYSTEM_SERVICE_MAP中取出一个ServiceFetcher类型的对象,并通过该对象返回指定的Service。

SYSTEM_SERVICE_MAP是一个HashMap的存储结构,以Service名字为键,以ServiceFetcher类型的元素为值。SYSTEM_SERVICE_MAP在ContextImpl类加载时,由static代码块调用registerService方法填充,代码如下:


static{//静态代码块

……//省略部分registerService过程

registerService(POWER_SERVICE, new ServiceFetcher(){

public Object createService(ContextImpl ctx){

//调用ServiceManager的方法,返回IBinder类型的对象引用

IBinder b=ServiceManager.getService(POWER_SERVICE);

//调用IPowerManager的Stub上的asInterface方法

IPowerManager service=IPowerManager.Stub.asInterface(b);

return new PowerManager(service, ctx.mMainThread.getHandler());

}});

}


这里在静态代码块中初始化并保存了Service的引用。power服务是在ServiceFetcher类的匿名对象的createService方法中获取的。其核心工作由三步组成:

1)获取服务的Proxy。通过ServiceManager的getService方法返回一个IBinder类型的对象引用。

2)以这个引用为参数调用Stub的asInterface构造IPowerManager。

3)以IPowerManager为参数构造PowerManager对象返回给调用方。

这里出现了IBinder和IPowerManager类型,看来已经用到了Binder机制。接下来详细分析这三步。

6.3.1 获取服务的BinderProxy

ServiceManager. getService用于获取服务的BinderProxy,其代码如下:


public static IBinder getService(String name){

try{

/首先查找该Service是否已经在缓存中/

IBinder service=sCache.get(name);

if(service!=null){

return service;

}else{

/这里才是真正返回Service的地方/

return getIServiceManager().getService(name);

}

}catch(RemoteException e){

Log.e(TAG,"error in getService",e);

}

return null;

}


getService首先调用getIServiceManager方法。在上文中已经分析过该方法的返回值是ServiceManagerProxy,因此调用ServiceManager.getService实际上是调用了ServiceManagerProxy.getService方法。

接下来分析ServiceManagerProxy如何获取Service的BinderProxy,代码如下:


public IBinder getService(String name)throws RemoteException{

Parcel data=Parcel.obtain();

Parcel reply=Parcel.obtain();

data.writeInterfaceToken(IServiceManager.descriptor);

data.writeString(name);

//mRemote即servicemanager在Java层的BinderProxy

mRemote.transact(GET_SERVICE_TRANSACTION, data, reply,0);

IBinder binder=reply.readStrongBinder();

reply.recycle();

data.recycle();

return binder;

}


mRemote是在构造ServiceManagerProxy的时候传入构造函数的参数,即servicemanager在Java层的BinderProxy,其对应Native层的BpBinder(0),这部分内容在上文中已经分析过,不赘述。

getService中的工作可以分成以下两步:

1)通过mRemote.transact方法进行Binder通信,该过程跟Native层getService方法的流程是一样的。

2)在reply中,通过readStrongBinder方法读取返回数据,这里的返回数据即要请求的服务。

接下来分析readStrongBinder方法读取返回的服务,该方法定义于frameworks/base/core/java/android/os/Parcel.java中,在其内部调用了Native方法nativeReadStrongBinder,该方法的JNI层实现方法位于android_os_Parcel.cpp中,其代码如下:


static jobject android_os_Parcel_readStrongBinder(JNIEnv*env,

jclass clazz, jint nativePtr)

{

Parcelparcel=reinterpret_cast<Parcel>(nativePtr);

if(parcel!=NULL){

return javaObjectForIBinder(env, parcel->readStrongBinder());

}

return NULL;

}


android_os_Parcel_readStrongBinder方法首先从Native层的parcel对象中读取Binder数据,然后以该数据为参数调用javaObjectForIBinder方法。javaObjectForIBinder在6.2.1节中已经分析过,其将Native层的BpBinder与Java层的BinderProxy做了关联,而关联信息由gBinderProxyOffsets结构体提供,与前文的区别是这里获取的是服务的BinderProxy。BinderProxy对象主要与Binder通信相关。