10.Binder进阶:系统服务中的Binder
16lz
2021-01-26
10.1 Binder与SystemService 在我们编写APP程序的时候, 经常会是用getSystemService( String serviceName ) 这个方法,来获取一个系统的服务对象。我们查看源码: frameworks/base/core/java/android/app下ContextImpl.java ,可以看到SystemService可以通过在WallpaperManager中获得到的,而WallpaperManager的initGlobals的构造函数中,则是用ServiceManager.getService( Context.WALLPAPAER_SERVICE) 获取到一个binder的对象。而看其他的源码,比如InputMethodManager他是通过单例模式获取的,如下:
而在InputMethodManager.java的getInstance方法中,我们可以看到如下:
可以看到,获取一个InputMethodManager对象,要先通过ServiceManager获取一个InputMethod Service的Binder对象b,然后在把这个Binder对象作为IInputManager.Stub.asInterface()的参数,返回一个InputMethodManager的统一接口,ServiceManager(android.os包下)的getService代码如下:
所以说,上面所做的就是先看我们需要的SystemService有没有在缓存中,没有的话,就获取到ServiceManager再获取。 其中getIServiceManager的代码如下:
上面的BinderInternal.getContextObject()方法,返回的是ServiceManager的全局服务代理对象,也就是一个BpBinder对象,方法是原生的方法,具体可以查看android_util_binder.cpp文件。服务会在Framework启动的时候,创建并且添加的。这个在这边就先不详细介绍了。
10.2 详述Manager Manager管理的就是服务,并且一个Manager往往管理一个服务,而且Manager更多的时候,调用服务本身的API接口,由于服务都是其他进程,因此,Manager内部使用的是Binder来实现远程调用,Manager隐藏了服务的实现细节,所以客户端并不直接通过调用Binder来访问这些服务,而是调用Manager的方法,所以,我们可以说,Manager将服务的操作、实现细节都封装了起来。这样Manager就相当于客户端通往SystemService的中间件,并使得我们可以灵活、可控地定制API。 比如说AMS,我们一般不希望用户直接访问AMS,而是通过ActivityManager来访问,而ActivityManager内部提供了一些更具有操作性的数据结构,比如RecentTaskInfo数据类封装了最近访问的Task列表,而MemoryInfo数据类封装了和内存相关的信息。 下面是Manager访问远程服务的模型图:
registerService(INPUT_METHOD_SERVICE, new ServiceFetcher() { public Object createService(ContextImpl ctx) { return InputMethodManager.getInstance(ctx); }});
而在InputMethodManager.java的getInstance方法中,我们可以看到如下:
/** * Internally, the input method manager can't be context-dependent, so * we have this here for the places that need it. * @hide */ static public InputMethodManager getInstance(Looper mainLooper) { synchronized (mInstanceSync) { if (mInstance != null) { return mInstance; } IBinder b = ServiceManager.getService(Context.INPUT_METHOD_SERVICE); IInputMethodManager service = IInputMethodManager.Stub.asInterface(b); mInstance = new InputMethodManager(service, mainLooper); } return mInstance; }
可以看到,获取一个InputMethodManager对象,要先通过ServiceManager获取一个InputMethod Service的Binder对象b,然后在把这个Binder对象作为IInputManager.Stub.asInterface()的参数,返回一个InputMethodManager的统一接口,ServiceManager(android.os包下)的getService代码如下:
/** * 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; }
所以说,上面所做的就是先看我们需要的SystemService有没有在缓存中,没有的话,就获取到ServiceManager再获取。 其中getIServiceManager的代码如下:
private static IServiceManager getIServiceManager() { if (sServiceManager != null) { return sServiceManager; } // Find the service manager sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject()); return sServiceManager; }
上面的BinderInternal.getContextObject()方法,返回的是ServiceManager的全局服务代理对象,也就是一个BpBinder对象,方法是原生的方法,具体可以查看android_util_binder.cpp文件。服务会在Framework启动的时候,创建并且添加的。这个在这边就先不详细介绍了。
10.2 详述Manager Manager管理的就是服务,并且一个Manager往往管理一个服务,而且Manager更多的时候,调用服务本身的API接口,由于服务都是其他进程,因此,Manager内部使用的是Binder来实现远程调用,Manager隐藏了服务的实现细节,所以客户端并不直接通过调用Binder来访问这些服务,而是调用Manager的方法,所以,我们可以说,Manager将服务的操作、实现细节都封装了起来。这样Manager就相当于客户端通往SystemService的中间件,并使得我们可以灵活、可控地定制API。 比如说AMS,我们一般不希望用户直接访问AMS,而是通过ActivityManager来访问,而ActivityManager内部提供了一些更具有操作性的数据结构,比如RecentTaskInfo数据类封装了最近访问的Task列表,而MemoryInfo数据类封装了和内存相关的信息。 下面是Manager访问远程服务的模型图:
更多相关文章
- Android(安卓)webview加载本地html实现跨域访问
- 使用application类,实现共享对象实例,实现service与activity交互,ui
- Android(安卓)Toast用法
- Content Provider 用法
- Android(安卓)获取系统或SDCARD剩余空间信息
- API 25 (Android(安卓)7.1.1 API) widget.Toast
- toast的五种效果
- Android(安卓)sdk更新过程中出现问题 (连接不上Google的服务资源
- fragment内嵌fragment之间传值+切换fragment