我们注册系统初始化的时候,会注册service到ServiceManager,那么我们从源码的角度分析addService和getService到底发生了什么?ServiceManager 本身的方法并不多,代码行数也简单。
/** @hide */
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static IServiceManager sServiceManager;
//缓存的String到IBinder(远程服务)的Map队列。
private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
//获取远端的ServiceManager。注意是跨进程的。现在拿到的只是本进程的代理对象而已。因为你是没法直接操作到远程的ServiceManager的,获取这个远程ServiceManager的代理比较简单,这个是最原始的。实际返回的是
// ServiceManagerProxy,关键是构造这个ServiceManagerProxy需要用到一个Ibinder对象。这里我们直接用了本地方法。 public static final native IBinder getContextObject();我简单分析下为啥这个方法能够直接拿到ServiceManager的Ibiner对象。此方法的本地实现在android_util_Binder.cpp中。
//*static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
//{
//实际调用的是getContextObject(null)。
//sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
//getStrongProxyForHandle(0) 此方法对于Binder 为0会直接实例化一个方法,而不会寻址。
//{
// return getStrongProxyForHandle(0);
//}
// sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
// return javaObjectForIBinder(env, b);
//}*
//好了可以理解为BinderInternal.getContextObject()直接拿到0号Binder了。
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
// 根据name去获取这个IBinder。(可以理解IBinder通过他的transact接口具备远程交互能力的java对象,实际的实现还是在native方法里面。)
public static IBinder getService(String name) {
try {
//从缓存获取,看是否存在。
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
//从ServiceManagerProxy获取。我们分析下ServiceManagerProxy的getService方法。
//public IBinder getService(String name) throws RemoteException {
//Parcel data = Parcel.obtain();
//Parcel reply = Parcel.obtain();
//data.writeInterfaceToken(IServiceManager.descriptor);
//data.writeString(name);
//mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
//IBinder binder = reply.readStrongBinder();
//reply.recycle();
//data.recycle();
// return binder;
//}
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
/**
* Place a new @a service called @a name into the service
* manager.
*
* @param name the name of the new service
* @param service the service object
*/
public static void addService(String name, IBinder service) {
try {
getIServiceManager().addService(name, service, false);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
/**
* Place a new @a service called @a name into the service
* manager.
*
* @param name the name of the new service
* @param service the service object
* @param allowIsolated set to true to allow isolated sandboxed processes
* to access this service
*/
public static void addService(String name, IBinder service, boolean allowIsolated) {
try {
getIServiceManager().addService(name, service, allowIsolated);
} catch (RemoteException e) {
Log.e(TAG, "error in addService", e);
}
}
/**
* Retrieve an existing service called @a name from the
* service manager. Non-blocking.
*/
public static IBinder checkService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().checkService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in checkService", e);
return null;
}
}
/**
* Return a list of all currently running services.
*/
public static String[] listServices() throws RemoteException {
try {
return getIServiceManager().listServices();
} catch (RemoteException e) {
Log.e(TAG, "error in listServices", e);
return null;
}
}
/**
* This is only intended to be called when the process is first being brought
* up and bound by the activity manager. There is only one thread in the process
* at that time, so no locking is done.
*
* @param cache the cache of service references
* @hide
*/
public static void initServiceCache(Map<String, IBinder> cache) {
if (sCache.size() != 0) {
throw new IllegalStateException("setServiceCache may only be called once");
}
sCache.putAll(cache);
}
}
在这里我分析了如果获取getService方法,总结一下,就是先拿到ServiceManger的客户端java代理,通过他就能够直接获取各种Service。