Android中的Binder機制一(實名Binder)

前言

Binder機制和Handler機制是Android中的兩大核心機制,是理解Android系統的基礎和關鍵。本文以AMS爲例,簡單分析下實名Binder的工作過程。

一、Binder相關的基礎概念

在Android中的Binder機制中,主要涉及四部分系統組件,分別是ServiceManager、Binder驅動、Client、Server,其中Client、Server、ServiceManager運行在各自的用戶空間中,Binder驅動運行在內核空間中。

  • ServiceManger(SM): 負責註冊管理所有的系統Server,併爲Client提供查詢Server的功能,SM更像是Server和Client中間的一箇中介。而SM、Server、Client這三個組件都是運行在各自獨立的進程中的。所以這三者之間的通信也是進程間的通信,而且也是採用的Binder機制來進行進程間通信的。在這個通信的過程中,ServiceManger除了要管理各種Server,同時自己也充當着Server的角色。
  • Server: Server通過SM的遠程接口,將自己的Binder服務註冊到SM中,然後將服務啓動起來,同時會啓動Binder線程池,等待客戶端請求。
  • Client: Client通過SM的遠程接口,獲取到在SM中相對應的遠程Server代理對象進行通信。
  • Binder驅動: Binder驅動是整個Binder通信機制的核心,進程間的數據交換就是通過它來完成的。如果Client要將數據傳遞給Server,正常情況下,Client把數據從自己的進程空間拷貝到內核空間,然後在從內核空間拷貝到Server的進程空間,這樣Server就拿到了Client傳遞的數據,但是這個過程進行了兩次內存拷貝。而通過Binder驅動,同一個物理頁面,一方面映射到Server進程虛擬地址空間,另一方面又映射到內核虛擬地址空間。這樣,只需要Client把要傳遞的數據拷貝到內核空間中,然後將拷貝到內核空間的數據同時映射到Server進程虛擬地址空間和內核虛擬地址空間,這樣Server和內核就可以共享該數據了,一次內存拷貝就可以了。

這裏需要說明一點,並不是所有的Binder服務都會註冊到SM中的,像AMS、WMS、PMS這些系統的Binder服務是會註冊到SM中並受SM管理的,而像我們開發者平常通過binderService的方式創建的Binder服務是不會註冊到SM中的。這些需要註冊到SM中的Binder服務稱之爲實名Binder,不需要註冊到SM中的Binder服務稱之爲匿名Binder,匿名Binder的傳遞和使用是需要依賴於實名Binder的。本文以AMS爲例,來學習下實名Binder,匿名Binder會在下篇文章中結合通過Aidl和binderService創建的Binder服務來具體分析。
Binder工作原理圖
上圖描述了應用程序客戶端調用AMS進行Binder進程間通信的一個大概流程,要注意一點,AMS和SM的通信也是進程間通信的一個過程,服務的註冊過程是一次IPC調用,這裏圖中就忽略了該過程:

  • 首先一個進程向驅動申請成爲SM,驅動同意之後,該進程就是SM進程,SM會創建一張表來記錄和管理所有向它註冊的Binder服務。
  • AMS通過SM的addService方法註冊到SM中(這也是一個進程間通信的過程,先不考慮),這樣,AMS就添加到SM的服務列表中了。
  • Client需要調用AMS中的方法的時候,會先到SM中查詢AMS,查詢到AMS的信息後,將AMS的代理對象返回給客戶端,然後客戶端就可以通過這個代理對象調用AMS裏面的方法了。
    這裏需要注意,客戶端拿到的AMS對象並不是服務端的AMS對象本身,而是在經過Binder驅動的時候產生了一個跟AMS功能完全一致的代理對象,這個代理對象只是服務端對象的一個影子,它具備服務端本地對象的所有能力,但是它沒有具體的功能實現,它只是包裝了一些參數和返回值相關數據,最終的方法實現還是要轉交給服務端的AMS對象進行處理的。

二、 AMS註冊到SM的過程

Android系統啓動的時候會啓動SyetemServer進程,該進程的程序執行入口是SystemServer類的main方法,源碼如下:

public static void main(String[] args) {
    new SystemServer().run();
}

上述方法中調用了SystemServer的run方法,看下run方法的關鍵代碼:

private void run() {
	..................
		try {
		       traceBeginAndSlog("StartServices");
		       
		       //註釋1 開啓系統服務
		       startBootstrapServices();
		       startCoreServices();
		       startOtherServices();
		       SystemServerInitThreadPool.shutdown();
		     
		   } catch (Throwable ex) {
		       Slog.e("System", "******************************************");
		       Slog.e("System", "************ Failure starting system services", ex);
		       throw ex;
		   } finally {
		       traceEnd();
		   }
	..................
}

在註釋1處會開啓系統服務,跟進去startBootstrapServices()方法:

private void startBootstrapServices() {
 
	   //註釋2 創建ActivityManagerService 
	   mActivityManagerService = mSystemServiceManager.startService(
	              ActivityManagerService.Lifecycle.class).getService();
	
	  
	      traceBeginAndSlog("SetSystemProcess");

		  //註釋3 調用了AMS的setSystemProcess方法
	      mActivityManagerService.setSystemProcess();
	      traceEnd();
}

在註釋2處創建了AMS對象,在註釋3處調用了AMS的setSystemProcess方法,下面跟到AMS裏看下setSystemProcess方法:

public void setSystemProcess() {

	//註釋4 
	ServiceManager.addService(Context.ACTIVITY_SERVICE, this, /* allowIsolated= */ true,
	                 DUMP_FLAG_PRIORITY_CRITICAL | DUMP_FLAG_PRIORITY_NORMAL | DUMP_FLAG_PROTO);
                 
}

在註釋4處,通過ServiceManager.addService方法將AMS註冊到了ServiceManager中,第一個參數是SM註冊表裏對應的字符串key,Context.ACTIVITY_SERVICE的值是"activity",第二個參數this是AMS對象本身,由於AMS向SM的註冊過程也是跨進程的,所以SM的註冊表裏存儲的value是AMS的信息而不是AMS對象本身,這樣當客戶端需要使用AMS的時候,就可以從SM的註冊表裏通過字符串key(“activity”)查詢到相對應的AMS服務信息了,然後在經過Binder驅動爲客戶端創建一個AMS的代理對象返回給客戶端,這樣客戶端就可以通過這個代理對象去調用AMS中的方法了,其他Binder服務的通信過程同理。

三、客戶端是如何使用AMS服務的

在平常開發的應用程序中,有很多地方都會跟AMS打交道,其中四大組件的運行就需要依賴於AMS服務,平時通過ActivityManager調用的方法其內部都是通過調用AMS的服務來具體實現的,由於應用程序和AMS是在兩個不同的進程中,所以應用程序調用AMS服務的過程是跨進程的,這裏以獲取應用程序運行的任務棧爲例,來學習一下應用程序客戶端是如何調用AMS服務的:

ActivityManager activityManager = (android.app.ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);

List<ActivityManager.RunningTaskInfo> listInfos = activityManager.getRunningTasks(20);

上面這段代碼應該很熟悉,通過context的getSystemService方法獲取到ActivityManager對象,然後調用ActivityManager的getRunningTasks方法,ActivityManager就是一個殼,它的存在避免了AMS直接暴露給應用程序,而是通過對外提供的ActivityManager來操作AMS,這樣更安全,下面看下ActivityManager的getRunningTasks方法:

@Deprecated
public List<RunningTaskInfo> getRunningTasks(int maxNum)
       throws SecurityException {
   try {
		//註釋5
       return getService().getTasks(maxNum);
   } catch (RemoteException e) {
       throw e.rethrowFromSystemServer();
   }
}

在註釋5處調用了getService()的getTasks方法,那麼這個getService是什麼呢?跟下這個方法的代碼:

public static IActivityManager getService() {

	//註釋6
    return IActivityManagerSingleton.get();
}

private static final Singleton<IActivityManager> IActivityManagerSingleton =
        new Singleton<IActivityManager>() {
            @Override
            protected IActivityManager create() {
				
				//註釋7
                final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                final IActivityManager am = IActivityManager.Stub.asInterface(b);
                return am;
            }
       };

在註釋6處可以看到,getService方法的返回值就是IActivityManagerSingleton.get()方法的返回值,結合註釋7處可以知道這個返回值就是am對象,在註釋7處通過調用ServiceManager的getService方法查詢出AMS的信息並轉換爲代理對象am。這個am對象是IActivityManager類型的,而IActivityManager是個aidl,根據aidl的規則和原理,可以知道遠程服務的具體實現一定是IActivityManager.Stub的實現類,而AMS實現了IActivityManager.Stub,所以AMS是遠程服務的具體實現。這裏需要說明一點,Binder服務並不是我們Android中四大組件中的Service,而是能被客戶端訪問並具有Binder通信能力的一個功能類(比如AMS/WMS/PMS這些)。下面是AMS的繼承關係源碼:

//AMS繼承並實現了IActivityManager.Stub
public class ActivityManagerService extends IActivityManager.Stub
        implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {

			..................................
}

我們可以類比自己寫的aidl,當我們的應用程序需要向AMS發起通信的時候,會通過IActivityManager的Proxy的transact方法發起binder通信,然後IActivityManager的Stub的onTransact方法會接收到客戶端發送的遠程通信請求,最終會調用到Stub的具體實現類AMS中相對應的方法進行處理,這樣整個進程間通信過程就完成了,具體aidl內部的工作流程在下篇匿名Binder中,結合自己定義的aidl進行學習和梳理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章