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通信相关。