概述
ServiceManager作为Android进程间通信binder机制中的重要角色,运行在native层,由c++语言实现,任何Service被使用之前,例如播放音乐的MediaService,例如管理activity的ActivityManagerService,均要向SM注册,同时客户端使用某个service时,也需要向ServiceManager查询该Service是否注册过了。
ServiceManager作用
它的实现是service_manager.c。而java中的ServiceManager.java仅仅是service_manager.c的封装。这里,我们不讨论service_manager.c是如何向下与Binder driver通信的,也不讨论注册、查找service的具体逻辑。而是从java层面,也就是Android FrameWork层面讨论是如何使用ServceManager.java服务的。
ServiceManager.java的源码很简单,如下:
public final class ServiceManager {
private static final String TAG = "ServiceManager";
private static IServiceManager sServiceManager;
private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
/**
* Returns a reference to a service with the given name.
*
* @param name the name of the service to get
* @return a reference to the service, or <code>null</code> if the service doesn't exist
*/
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
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.
* @return an array of all currently running services, or <code>null</code> in
* case of an exception
*/
public static String[] listServices() {
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);
}
}
有如下功能
1、提供addService()方法,向native层注册服务
2、提供getService()方法,从native层获取服务
3、维护了缓存Map
其实getService()就是从native层获取Binder,获取后通过Stub.asInterface()方法转化为BinderProxy,通过BinderProxy就可以通过其调用远端方法了。这部分知识我们是比较熟悉的,在通过AIDL自定义Service时,用到的就是这部分知识。这里我们先认为native层对我们是不透明的,只要了解到通过addService()和getService()就可以向native注册服务或从native层获取服务。想了解native是如何实现注册和获取服务的同学可以看这两篇文章:
Android Framework学习(十)之向ServiceManager注册Native层服务
Android Framework学习(十一)之从ServiceManager获取Native层服务
我们这里暂时不讨论
App端
从本人总结的的上一篇文章Android SystemServer解析中我们可以了解到,通过getSystemService()获取远端服务代理时,最终是通过ServiceFetcher.createService()方法创建XXManager,XXManager中封装了用于访问远端服务的BinderProxy,那么,这里我们探究下XXManager中的BinderProxy是如何而来的。其实我们猜也能猜到一定是通过ServiceManager.getService()获取的,我们来证实这一过程。
先挑一个最常用的ActivityManager,ActivityManager封装了对远端访问的业务方法,那么在这些方法中必然是通过调用BinderProxy来实现的,我们举两个例子:
@Deprecated
public List<RunningTaskInfo> getRunningTasks(int maxNum)
throws SecurityException {
try {
return ActivityManagerNative.getDefault().getTasks(maxNum, 0);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
可以看到是通过调用ActivityManagerNative.getDefault().getTasks()方法,说明ActivityManagerNative.getDefault()返回的
BinderProxy,我们跟进去看:
ActivityManagerNative.getDefault()
/**
* Retrieve the system's default/global activity manager.
*/
static public IActivityManager getDefault() {
return gDefault.get();
}
看看getDefault()是什么:
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
if (false) {
Log.v("ActivityManager", "default service binder = " + b);
}
IActivityManager am = asInterface(b);
if (false) {
Log.v("ActivityManager", "default service = " + am);
}
return am;
}
};
果不其然,是从ServiceManager中获取的IBinder,并转换为BinderProxy。
再看一个XXManager,BluetoothManager,其中有一个逻辑方法getConnectedSevices()如下:
public List<BluetoothDevice> getConnectedDevices(int profile) {
if (DBG) Log.d(TAG,"getConnectedDevices");
if (profile != BluetoothProfile.GATT && profile != BluetoothProfile.GATT_SERVER) {
throw new IllegalArgumentException("Profile not supported: " + profile);
}
List<BluetoothDevice> connectedDevices = new ArrayList<BluetoothDevice>();
try {
IBluetoothManager managerService = mAdapter.getBluetoothManager();
IBluetoothGatt iGatt = managerService.getBluetoothGatt();
if (iGatt == null) return connectedDevices;
connectedDevices = iGatt.getDevicesMatchingConnectionStates(
new int[] { BluetoothProfile.STATE_CONNECTED });
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
return connectedDevices;
}
可以看到是通过mAdapter获取IBluetoothManager接口,也就是BinderProxy,跟进去BluetoothAdapter:
/*package*/ IBluetoothManager getBluetoothManager() {
return mManagerService;
}
返回mManagerService,该变量是构造BluetoothAdapter时传入的,发现BluetoothAdapter中包含创建BluetoothAdapter的方法getDefaultAdapter,如下:
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
}
return sAdapter;
}
可以看到,也是通过ServiceManager.getService()获取IBinder,并通过adInterface(b)方法转换为BinderProxy。
当然并不是所有的XXManager都需要远端服务,有些XXManager的业务方法是通过ContentProvider来实现的。
由此,我们验证了一点:XXManager中包含的BinderProxy是从ServiceManager.getService()获取的并通过asInterface()得到的。
SystemServer端
下面,我们再来验证注册服务是通过ServiceManager.addService()实现的,从上一篇文章Android SystemServer解析,我们得知,各中XXManagerService都是通过SystemServer.java的静态代码块创建并调用onStart()方法启动,看起来并没有和ServiceManager.addService()发生联系,不急,我们可以看到SystemServer.startOtherService()方法中存在如下代码:
telephonyRegistry = new TelephonyRegistry(context);
ServiceManager.addService("telephony.registry", telephonyRegistry);
vibrator = new VibratorService(context);
ServiceManager.addService("vibrator", vibrator);
可以发现就是通过ServiceManager.addService()向native注册服务
同时,在AMS中也可以发现注册核心Service的代码:
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
说是注册Service,其实就是注册一个IBinder,该IBinder标明了自己的身份,我们可以发现addService()的第二个参数的类均是Binder,如VibratorService:
public class VibratorService extends IVibratorService.Stub
implements InputManager.InputDeviceListener {
....
如TelephonyRegistory:
class TelephonyRegistry extends ITelephonyRegistry.Stub {
private static final String TAG = "TelephonyRegistry";
.....
另外,XXManagerService的父类SystemService中,也提供了向ServiceManager注册的方法:
protected final void publishBinderService(String name, IBinder service,
boolean allowIsolated) {
ServiceManager.addService(name, service, allowIsolated);
}