10.Binder進階:系統服務中的Binder
阿新 • • 發佈:2018-11-15
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訪問遠端服務的模型圖: