精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

關于Binder,作為應用開發者你需要知道的全部

移動開發 Android
這篇文章主要從宏觀的層面去理解Binder中的各種概念和基本通信過程,只關注Java層的實現,底層實現不做介紹。對于應用開發者而言,理解Binder的基本設計原理和通信過程已經夠了,想要深入理解Binder需要自行閱讀源碼。

為什么要理解Binder?

一般Android應用開發很少直接用到跨進程信通信(IPC),但如果你想知道:

  • App是如何啟動并初始化的?
  • Activity的啟動過程是怎樣的?
  • 進程間是如何通信的?
  • AIDL的具體原理是什么?
  • 眾多插件化框架的設計原理 等等

就必須對Binder有所了解,無論是四大組件,還是各種系統Service,比如ActivityManagerService、PackageManagerService,它們的實現都依賴Binder的通信機制,可見Binder在Android系統中的重要性,可以說Binder是邁入高級工程師的***步。

[[245146]]

Binder機制很復雜,想要徹底弄懂比較難,除了需要了解操作系統中的各種知識外,還需要看懂Binder驅動層的代碼實現。最近看了很多關于Binder的文章,大部分過于抽象或者過于深入源碼細節,真正淺顯易懂的文章很少。

這篇文章主要從宏觀的層面去理解Binder中的各種概念和基本通信過程,只關注Java層的實現,底層實現不做介紹。對于應用開發者而言,理解Binder的基本設計原理和通信過程已經夠了,想要深入理解Binder需要自行閱讀源碼。

本文主要從三個方面來做分析:

1、為什么是Binder?

  • 傳統Linux IPC機制的缺點
  • Linux的一些基本知識
  • 傳統Linux IPC機制的通信原理

2、Binder的基本原理

  • Binder的底層原理
  • Binder的通信模型
  • Binder的代理機制
  • 對Binder概念的重新理解

3、通過代碼來理解Binder

  • 通過AIDL實例來了解Binder的用法
  • 通過手動編碼實現ActivityManagerService

1、為什么是Binder?

1.1 傳統IPC機制的缺點

大家都知道Android系統是基于Linux內核實現的,Linux已經提供了多種進程間通信機制,比如:管道、消息隊列、共享內存和套接字(Socket)等等,為什么還要再實現一套IPC機制呢?主要是基于兩方面的原因:

1.1.1 性能角度

管道、消息隊列、Socket實現一次進程通信都需要2次內存拷貝,效率太低;共享內存雖然不需要拷貝內存,但管理復雜;Binder只需要一次內存拷貝,從性能角度來看,低于共享內存方式,優于其它方式。

關于Binder,作為應用開發者你需要知道的全部

1.1.2 安全性考慮

傳統的IPC機制沒有安全措施,接收方無法獲得對方可靠的進程ID或用戶ID,完全靠上層的協議來保護,比如Socket通信的IP地址是客戶端填入的,很可能被惡意程序篡改。Android作為面向終端用戶的開源平臺,應用市場中有海量的應用供用戶選擇,因此安全性極為重要。Android系統為每個已安裝的App都分配了用戶ID(UID),UID是鑒別進程身份的重要標識,通過UID可以進行一系列的權限校驗。另一方面 ,傳統IPC的接入點是開放的,任何程序都可以根據協議進行訪問,無法阻止惡意程序的訪問,Android需要一種基于C/S架構的IPC機制,Server端需要能夠對Client的請求進行身份校驗,來保證數據的安全性。

1.2 Linux的一些基本知識

要知道Binder是如何只用一次內存拷貝即實現跨進程通信的,首先需要弄清楚為什么傳統IPC機制為什么需要兩次內存拷貝,這就需要先了解一些操作系統的基礎知識。

1.2.1 進程隔離

先來看一下維基百科對“進程隔離”的定義:

進程隔離是為保護操作系統中進程互不干擾而設計的一組不同硬件和軟件的技術。這個技術是為了避免進程A寫入進程B的情況發生。 進程的隔離實現,使用了虛擬地址空間。進程A的虛擬地址和進程B的虛擬地址不同,這樣就防止進程A將數據信息寫入進程B。

也就是說,進程之間的數據是不共享的,A進程無法直接訪問B進程的數據,以此來保證數據的安全性。在進程隔離的操作系統中,進程之間的交互必須通過IPC機制。

進程隔離的實現使用了虛擬地址空間,什么是虛擬地址空間呢?首先需要了解操作系統中的虛擬內存概念,它是一種提高編程效率和提高物理內存利用效率的一種技術。簡單來說,就是應用程序看到了都一片連續完整的內存地址空間,而實際上這些地壇空間是映射到碎片化的物理內存中的,這個映射的過程對應用程序來說是透明的。這個概念很重要,對于虛擬內存更深入的理解可以參考這篇文章:Linux 虛擬內存和物理內存的理解

1.2.2 進程空間:用戶空間/內核空間

現在的操作系統都采用虛擬內存,對32位的操作系統而言,尋址空間是2的32次方,即4G。操作系統的核心是內核,內核擁有對底層設備的所有訪問權限,因此需要和普通的應用程序獨立開來,用戶進程不能直接訪問內核進程。操作系統從邏輯上把虛擬地址空間劃分為用戶空間(User Space)和內核空間(Kernel Space)。在32位的Linux操作系統中,將高位的1GB字節供內核使用,稱之為內核空間;剩下的3GB字節供用戶進程使用,稱之為用戶空間。

1.2.3 系統調用:用戶態/內核態

因為用戶空間的權限低于內核空間,不可避免用戶空間需要訪問內核空間的資源,比如讀寫文件和網絡訪問,如何實現呢?唯一的方式就是通過操作系統提供的系統調用接口,通過系統調用接口,用戶程序可以在內核的控制下實現對內核資源的有限訪問,這樣既能滿足應用程序的資源請求,也能保障系統安全和穩定。

當用戶進程執行自己的代碼時,進程當前就處于用戶運行態(用戶態),此時處理器執行用戶代碼,權限較低;當用戶進程通過系統調用執行內核代碼時,進程就暫時進入了內核運行態(內核態),此時處理器權限***,可以執行特權指令。

1.2.4 內核模塊/驅動

前面說了用戶空間可以通過系統調用訪問內核空間,那用戶空間之間(進程間)怎么通信呢?傳統的IPC機制都是通過內核來支持的,Binder也一樣,有一個運行在內核中的Binder驅動程序負責進程之間Binder的通信。

驅動程序一般指的是設備驅動程序(Device Driver),是一種可以使計算機和設備通信的特殊程序。相當于硬件的接口,操作系統只有通過這個接口。

Binder驅動是一種虛擬的字符設備,注冊在/dev/binder中,其定義了一套Binder通信協議,負責建立進程間的Binder通信,提供了數據包在進程之間傳遞的一系列底層支持。應用進程訪問Binder驅動也是通過系統調用實現的。

1.3 傳統IPC機制的通信原理

了解了上面的基礎知識后,我們來看看傳統IPC機制是如何實現,通常是下面兩個步驟(共享內存機制除外):

  1. 發送方進程通過系統調用(copy_from_user)將要發送的數據存拷貝到內核緩存區中。
  2. 接收方開辟一段內存空間,內核通過系統調用(copy_to_user)將內核緩存區中的數據拷貝到接收方的內存緩存區。

關于Binder,作為應用開發者你需要知道的全部

這種傳統IPC機制存在2個問題:

  1. 需要進行2次數據拷貝,第1次是從發送方用戶空間拷貝到內核緩存區,第2次是從內核緩存區拷貝到接收方用戶空間。
  2. 接收方進程不知道事先要分配多大的空間來接收數據,可能存在空間上的浪費。

2、Binder的基本原理

2.1 Binder底層原理

傳統IPC機制需要拷貝2次內存,Binder是如何只用1次內存拷貝就實現進程間通信的呢?前面我們已經了解到,Linux是使用的是虛擬內存尋址方式,用戶空間的虛擬內存地址是映射到物理內存中的,對虛擬內存的讀寫實際上是對物理內存的讀寫,這個過程就是內存映射,這個內存映射過程是通過系統調用mmap()來實現的。

Binder借助了內存映射的方法,在內核空間和接收方用戶空間的數據緩存區之間做了一層內存映射。這樣一來,從發送方用戶空間拷貝到內核空間緩存區的數據,就相當于直接拷貝到了接收方用戶空間的數據緩存區,從而減少了一次數據拷貝。

關于Binder,作為應用開發者你需要知道的全部

2.2 Binder通信模型

Binder是基于C/S架構的,對于通信雙方來說,發起請求的進程屬于Client,接收請求的進程屬于Server,由于存在進程隔離,雙方不能直接通信,Binder是如何實現的呢?

寫給 Android 應用工程師的 Binder 原理剖析中舉的網絡通信例子很貼切,Binder的通信過程與網絡請求類似,網絡通信過程可以簡化為4個角色:Client、Server、DNS服務器和路由器。一次完整的網絡通信大體過程如下:

a、Client輸入Server的域名

b、DNS解析域名

通過域名是無法直接找到相應Server的,必須先通過DNS服務器將Server的域名轉化為具體的IP地址。

c、通過路由器將請求發送至Server

Client通過DNS服務器解析到Server的IP地址后,也還不能直接向Server發起請求,需要經過路由器的層層中轉才還到達Server。

d、Server返回數據

Server接收到請求并處理后,再通過路由器將數據返回給Client。

在Binder機制中,也定義了4個角色:Client、Server、Binder驅動和ServiceManager。

Binder驅動:類似網絡通信中的路由器,負責將Client的請求轉發到具體的Server中執行,并將Server返回的數據傳回給Client。

ServiceManager:類似網絡通信中的DNS服務器,負責將Client請求的Binder描述符轉化為具體的Server地址,以便Binder驅動能夠轉發給具體的Server。Server如需提供Binder服務,需要向ServiceManager注冊。

關于Binder,作為應用開發者你需要知道的全部

具體的通信過程是這樣的:

a、Server向ServiceManager注冊

Server通過Binder驅動向ServiceManager注冊,聲明可以對外提供服務。ServiceManager中會保留一份映射表:名字為zhangsan的Server對應的Binder引用是0x12345。

b、Client向ServiceManager請求Server的Binder引用

Client想要請求Server的數據時,需要先通過Binder驅動向ServiceManager請求Server的Binder引用:我要向名字為zhangsan的Server通信,請告訴我Server的Binder引用。

c、向具體的Server發送請求

Client拿到這個Binder引用后,就可以通過Binder驅動和Server進行通信了。

d、Server返回結果

Server響應請求后,需要再次通過Binder驅動將結果返回給Client。

可以看到,Client、Server、ServiceManager之間的通信都是通過Binder驅動作為橋梁的,可見Binder驅動的重要性。也許你還有一點疑問,ServiceManager和Binder驅動屬于兩個不同的進程,它們是為Client和Server之間的進程間通信服務的,也就是說Client和Server之間的進程間通信依賴ServiceManager和Binder驅動之間的進程間通信,這就像是:“蛋生雞,雞生蛋,但***個蛋得通過一只雞孵出來”。Binder機制是如何創造***只下蛋的雞呢?

  1. 當Android系統啟動后,會創建一個名稱為servicemanager的進程,這個進程通過一個約定的命令BINDERSETCONTEXT_MGR向Binder驅動注冊,申請成為為ServiceManager,Binder驅動會自動為ServiceManager創建一個Binder實體(***只下蛋的雞);
  2. 并且這個Binder實體的引用在所有的Client中都為0,也就說各個Client通過這個0號引用就可以和ServiceManager進行通信。Server通過0號引用向ServiceManager進行注冊,Client通過0號引用就可以獲取到要通信的Server的Binder引用。

Android Binder設計與實現 - 設計篇中對Client、Server、Binder驅動和ServiceManager有更詳細的介紹。

2.3 Binder的代理機制

通過上面的分析,我們已經知道了Binder的基本通信過程:Client向SerivceManger獲取到Server的Binder引用,Client通過Binder引用向Server發起具體請求。Client通過這個Binder引用具體是如何調用Server方法的呢?

關于Binder,作為應用開發者你需要知道的全部

比如一個Server提供add方法,Client實際請求add的流程是這樣的:Client先通過Binder驅動向ServiceManager獲取Server的Binder引用,這個引用就是一個Java Object,這個Object有一個add方法;Cient拿到這個Object后就可以直接請求add方法了。

實際上Client拿到的Object并不是Server真正的Binder實體,Binder驅動做了一層對象轉換,將這個Object包裝成了一個代理對象ProxyObject,這個ProxyObject和真正的Binder實體有相同的方法簽名,Client通過這個ProxyObject請求add方法時,Binder驅動會自動將請求轉發到具體的Binder實體中執行,這就是Binder的代理機制。由于ProxyObject和真正的Binder實體有相同的方法簽名,其實Client并不需要關心是ProxyObject還是真實的Object。

為了方便描述,下面將Server真正的Binder實體稱為Binder本地對象;將Client中的Binder引用,即ProxyObject,稱之為Binder代理對象。

2.4 對Binder概念的重新理解

經過上面的分析,我們已經大體清楚了Binder機制的基本通信原理,現在回過頭來重新梳理下對Binder機制的認識:

總體來說,Binder是基于C/S結構的一種面向對象的IPC機制。包含:Client、Server、Binder驅動和ServiceManager四大組成部分。各組成部分中的Binder含義都有所有不同:

  • 對于Client

Binder是Server本地對象的一個引用,這個引用實際上是一個代理對象,Client通過這個代理對象來間接訪問Server的本地對象;

  • 對于Server

Binder是提供具體實現的本地對象,需向ServiceManager注冊;

  • 對于Binder驅動

它是連接Client來Server的橋梁,負責將代理對象轉化為本地對象,并將Server的執行結果返回給Client。

  • 對于ServiceManager

它保存了Server Binder字符名稱和Binder引用的映射,Client通過它來找到Server的Binder引用。

Binder驅動中保留了Binder代理對象和Binder本地對象的具體結構,由于我們只關心Binder的基本通信機制,底層實現不做過多介紹,想具體了解的同學可以參考Android Binder設計與實現 - 設計篇。

3、通過代碼來理解Binder

上面的介紹比較抽象,現在我們通過具體實例來理解Binder。

  • 通過AIDL實例來了解Binder的用法
  • 通過手動編碼實現ActivityManagerService

3.1 通過AIDL實例來了解Binder的用法

實現Binder通信的最常用方法就是通過aidl,aidl接口定義了Client和Server進行通信的接口,對aidl不了解的同學請參考官方文檔Android 接口定義語言 (AIDL)。

3.1.1 與Binder相關的幾個類的職責

在具體分析之前,我們需要先了解與Binder相關的幾個類的職責:

  • IBinder

跨進程通信的Base接口,它聲明了跨進程通信需要實現的一系列抽象方法,實現了這個接口就說明可以進行跨進程通信,Client和Server都要實現此接口。

  • IInterface

這也是一個Base接口,用來表示Server提供了哪些能力,是Client和Server通信的協議。

  • Binder

提供Binder服務的本地對象的基類,它實現了IBinder接口,所有本地對象都要繼承這個類。

  • BinderProxy

在Binder.java這個文件中還定義了一個BinderProxy類,這個類表示Binder代理對象它同樣實現了IBinder接口,不過它的很多實現都交由native層處理。Client中拿到的實際上是這個代理對象。

  • Stub

這個類在編譯aidl文件后自動生成,它繼承自Binder,表示它是一個Binder本地對象;它是一個抽象類,實現了IInterface接口,表明它的子類需要實現Server將要提供的具體能力(即aidl文件中聲明的方法)。

  • Proxy

它實現了IInterface接口,說明它是Binder通信過程的一部分;它實現了aidl中聲明的方法,但最終還是交由其中的mRemote成員來處理,說明它是一個代理對象,mRemote成員實際上就是BinderProxy。

3.1.2 AIDL實例

首先定義一個aidl文件,這個接口中聲明了一個getPid方法:

  1. // IRemoteService.aidl 
  2. package com.rush.demo.aidltest; 
  3.  
  4. interface IRemoteService { 
  5.     int getPid(); 

下面是編譯IRemoteService.aild后生成的java類:

  1. // IRemoteService.java 
  2. package com.rush.demo.aidltest; 
  3.  
  4. public interface IRemoteService extends android.os.IInterface { 
  5.     public static abstract class Stub extends android.os.Binder implements com.rush.demo.aidltest.IRemoteService { 
  6.         //Binder描述符 
  7.         private static final java.lang.String DESCRIPTOR = "com.rush.demo.aidltest.IRemoteService"
  8.  
  9.         public Stub() { 
  10.             this.attachInterface(this, DESCRIPTOR); 
  11.         } 
  12.  
  13.         public static com.rush.demo.aidltest.IRemoteService asInterface(android.os.IBinder obj) { 
  14.             if ((obj == null)) { 
  15.                 return null
  16.             } 
  17.             android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 
  18.             if (((iin != null) && (iin instanceof com.rush.demo.aidltest.IRemoteService))) { 
  19.                 return ((com.rush.demo.aidltest.IRemoteService) iin); 
  20.             } 
  21.             return new com.rush.demo.aidltest.IRemoteService.Stub.Proxy(obj); 
  22.         } 
  23.  
  24.         @Override 
  25.         public android.os.IBinder asBinder() { 
  26.             return this; 
  27.         } 
  28.  
  29.         @Override 
  30.         public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { 
  31.             switch (code) { 
  32.                 case INTERFACE_TRANSACTION: { 
  33.                     reply.writeString(DESCRIPTOR); 
  34.                     return true
  35.                 } 
  36.                 case TRANSACTION_getPid: { 
  37.                     data.enforceInterface(DESCRIPTOR); 
  38.                     java.lang.String _arg0; 
  39.                     _arg0 = data.readString(); 
  40.                     int _result = this.getPid(_arg0); 
  41.                     reply.writeNoException(); 
  42.                     reply.writeInt(_result); 
  43.                     return true
  44.                 } 
  45.             } 
  46.             return super.onTransact(code, data, reply, flags); 
  47.         } 
  48.  
  49.         private static class Proxy implements com.rush.demo.aidltest.IRemoteService { 
  50.             private android.os.IBinder mRemote; 
  51.  
  52.             Proxy(android.os.IBinder remote) { 
  53.                 mRemote = remote; 
  54.             } 
  55.  
  56.             @Override 
  57.             public android.os.IBinder asBinder() { 
  58.                 return mRemote; 
  59.             } 
  60.  
  61.             public java.lang.String getInterfaceDescriptor() { 
  62.                 return DESCRIPTOR; 
  63.             } 
  64.  
  65.             @Override 
  66.             public int getPid(java.lang.String name) throws android.os.RemoteException { 
  67.                 android.os.Parcel _data = android.os.Parcel.obtain(); 
  68.                 android.os.Parcel _reply = android.os.Parcel.obtain(); 
  69.                 int _result; 
  70.                 try { 
  71.                     _data.writeInterfaceToken(DESCRIPTOR); 
  72.                     _data.writeString(name); 
  73.                     mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0); 
  74.                     _reply.readException(); 
  75.                     _result = _reply.readInt(); 
  76.                 } finally { 
  77.                     _reply.recycle(); 
  78.                     _data.recycle(); 
  79.                 } 
  80.                 return _result; 
  81.             } 
  82.  
  83.         static final int TRANSACTION_getPid = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0); 
  84.     } 
  85.  
  86.     public int getPid(java.lang.String name) throws android.os.RemoteException; 

這個文件中有3個類:

a、IRemoteService

繼承至IInterface接口,聲明了IRemoteService.aidl中聲明的getPid方法,它是Client和Service通信的接口。

b、IRemoteService.Stub

IRemoteService的靜態抽象內部類,繼承自Binder,其子類需要實現IRemoteService接口,表明它是Server的Binder本地對象,需要實現getPid接口。

c、IRemoteService.Stub.Proxy

IRemoteService.Stub的靜態內部類,它并沒有繼承自Binder,而是包含了一個IBinder對象,這個對象其實是BinderProxy,說明它是Server在Client中的本地代理對象。Proxy實現了getPid接口,將參數序列化后交由mRemote(BinderProxy)處理,實際上就是交給Binder驅動來完成與遠程Stub的通信。

先來看Stub中的asInterface方法,這個方法通常是Client在bindService成功后,由Client來調用的,作用是將綁定成功后返回的IBinder對象轉換為具體的IInterface接口,Client拿到這個IInterface接口后就可以和自由的調用Server提供的方法了。

  1. public static com.rush.demo.aidltest.IRemoteService asInterface(android.os.IBinder obj) { 
  2.     if ((obj == null)) { 
  3.         return null
  4.     } 
  5.     android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR); 
  6.     if (((iin != null) && (iin instanceof com.rush.demo.aidltest.IRemoteService))) { 
  7.         return ((com.rush.demo.aidltest.IRemoteService) iin); 
  8.     } 
  9.     return new com.rush.demo.aidltest.IRemoteService.Stub.Proxy(obj); 

asInterface方法中既可能返回Stub本身的IRemoteService對象,也可能創建一個Proxy對象,這是為什么呢?因為Binder雖然是跨進程通信機制,但也可以為本進程服務,也就是說Client和Server可能在同一個進程,在同一個進程就沒必要通過Binder驅動來中轉了,直接訪問就可以了;如果Client和Server在不同的進程,就需要通過Binder代理對象來中轉。也就是說:

  1. Client和Server在同一個進程,obj是Binder本地對象(Stub的子類),asInterface方法返回的就是Binder本地對象;
  2. Client和Server在不同的進程,obj實際上是Binder代理對象,asInterface返回一個Proxy對象。
  1. //Binder.java 
  2. /** 
  3.  * obj.queryLocalInterface是怎樣去查找是否有本地的IInterface呢,從Binder的代碼中可以看到,只是簡單的比較Binder的描述符和要查找的描述符是否匹配,匹配的話直接返回mOwner,這個mOwner就是Stub構造方法中調用attachInterface方法傳入的this參數。 
  4.  */ 
  5. public IInterface queryLocalInterface(String descriptor) { 
  6.     if (mDescriptor.equals(descriptor)) { 
  7.         return mOwner; 
  8.     } 
  9.     return null
  10.  
  11. final class BinderProxy implements IBinder { 
  12.     public IInterface queryLocalInterface(String descriptor) { 
  13.         return null
  14.     } 
  15.  
  16. public static abstract class Stub extends android.os.Binder implements com.rush.demo.aidltest.IRemoteService { 
  17.     // Binder描述符,值為接口類名全稱 
  18.     private static final java.lang.String DESCRIPTOR = "com.rush.demo.aidltest.IRemoteService"
  19.  
  20.     public Stub() { 
  21.         //向Binder中綁定owner和descriptor 
  22.         this.attachInterface(this, DESCRIPTOR); 
  23.     } 

obj.queryLocalInterface是怎樣去查找是否有本地的IInterface呢,從Binder的代碼中可以看到,只是簡單的比較Binder的描述符和要查找的描述符是否匹配,匹配的話直接返回mOwner,這個mOwner就是Stub構造方法中調用attachInterface方法傳入的this參數。而BinderProxy的queryLocalInterface方法直接返回null。

Client中通過Binder調用Server方法有兩種場景:

1、Client和Server在同一個進程

Stub.asInterface方法返回的是Stub對象,即Binder本地對象。也就是說和Binder跨進程通信無關,直接調用即可,此時Client調用方和Server響應方在同一個線程中。

2、Client和Server在不同的進程

Stub.asInterface方法返回的是Binder代理對象,需要通過Binder驅動完成跨進程通信。這種場景下,Client調用方線程會被掛起(Binder也提供了異步的方式,這里不討論),等待Server響應后返回數據。這里要注意的是,Server的響應是在Server進程的Binder線程池中處理的,并不是主線程。

接下來分析跨進程場景下,Client調用getPid方法的具體流程:

1、Client調用Binder代理對象,Client線程掛起

Client中拿到的IRemoteService引用實際上是Proxy,調用getPid方法實際上是調用Proxy的getPid方法,這個方法只是將參數序列化后,調用了mRemote成員的transact方法。Stub類中為IRemoteService中的每個方法定義了方法編號,transact方法中傳入getPid方法的編號。此時Client調用方線程掛起,等待Server響應數據。

  1. // Stub.Proxy 
  2. public int getPid(java.lang.String name) throws android.os.RemoteException { 
  3.     ... 
  4.     _data.writeInterfaceToken(DESCRIPTOR); 
  5.     _data.writeString(name); 
  6.     mRemote.transact(Stub.TRANSACTION_getPid, _data, _reply, 0); 
  7.     _reply.readException(); 
  8.     _result = _reply.readInt(); 
  9.     ... 
  10.     return _result; 

2、Binder代理對象將請求派發給Binder驅動

Proxy中的mRemote成員實際上是BinderProxy,而BinderProxy中的transact方法最終調用于transactNative方法,也就是說Client的請求派發給了Binder驅動來處理。

3、Binder驅動將請求派發給Server

Binder驅動經過一系列的處理后,將請求派發給了Server,即調用Server本地Binder對象(Stub)的onTransact方法最終在此方法中完成getPid方法的具體調用。在onTransact方法中,根據Proxy中調用transact時傳入的方法編號來區別具體要處理的方法。

  1. // Stub 
  2. public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { 
  3.     switch (code) { 
  4.         ... 
  5.         case TRANSACTION_getPid: { 
  6.             data.enforceInterface(DESCRIPTOR); 
  7.             //獲取方法參數 
  8.             java.lang.String _arg0 = data.readString(); 
  9.             //調用getPid方法,這個方法在Stub的子類,即Server中實現 
  10.             int _result = this.getPid(_arg0); 
  11.             reply.writeNoException(); 
  12.             reply.writeInt(_result); 
  13.             return true
  14.         } 
  15.     } 
  16.     return super.onTransact(code, data, reply, flags); 

4、喚醒Client線程,返回結果

onTransact處理結束后,將結果寫入reply并返回至Binder驅動,驅動喚醒掛起的Client線程,并將結果返回。至此,一次跨進程通信完成。

3.2 手動編碼來實現ActivityManagerService

通過前面的示例我們已經知道,aidl文件只是用來定義C/S交互的接口,Android在編譯時會自動生成相應的Java類,生成的類中包含了Stub和Proxy靜態內部類,用來封裝數據轉換的過程,實際使用時只關心具體的Java接口類即可。為什么Stub和Proxy是靜態內部類呢?這其實只是為了將三個類放在一個文件中,提高代碼的聚合性。通過上面的分析,我們其實完全可以不通過aidl,手動編碼來實現Binder的通信,下面我們通過編碼來實現ActivityManagerService。

首先定義IActivityManager接口:

  1. public interface IActivityManager extends IInterface { 
  2.     //binder描述符 
  3.     String DESCRIPTOR = "android.app.IActivityManager"
  4.     //方法編號 
  5.     int TRANSACTION_startActivity = IBinder.FIRST_CALL_TRANSACTION + 0; 
  6.     //聲明一個啟動activity的方法,為了簡化,這里只傳入intent參數 
  7.     int startActivity(Intent intent) throws RemoteException; 

其次,實現ActivityManagerService側的本地Binder對象基類:

  1. // 名稱隨意,不一致叫Stub 
  2. public abstract class ActivityManagerNative extends Binder implements IActivityManager { 
  3.  
  4.     public static IActivityManager asInterface(IBinder obj) { 
  5.         if (obj == null) { 
  6.             return null
  7.         } 
  8.         IActivityManager in = (IActivityManager) obj.queryLocalInterface(IActivityManager.DESCRIPTOR); 
  9.         if (in != null) { 
  10.             return in
  11.         } 
  12.         //代理對象,見下面的代碼 
  13.         return new ActivityManagerProxy(obj); 
  14.     } 
  15.  
  16.     @Override 
  17.     public IBinder asBinder() { 
  18.         return this; 
  19.     } 
  20.  
  21.     @Override 
  22.     protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { 
  23.         switch (code) { 
  24.             // 獲取binder描述符 
  25.             case INTERFACE_TRANSACTION: 
  26.                 reply.writeString(IActivityManager.DESCRIPTOR); 
  27.                 return true
  28.             // 啟動activity,從data中反序列化出intent參數后,直接調用子類startActivity方法啟動activity。 
  29.             case IActivityManager.TRANSACTION_startActivity: 
  30.                 data.enforceInterface(IActivityManager.DESCRIPTOR); 
  31.                 Intent intent = Intent.CREATOR.createFromParcel(data); 
  32.                 int result = this.startActivity(intent); 
  33.                 reply.writeNoException(); 
  34.                 reply.writeInt(result); 
  35.                 return true
  36.         } 
  37.         return super.onTransact(code, data, reply, flags); 
  38.     } 

再次,實現Client側的代理對象:

  1. public class ActivityManagerProxy implements IActivityManager { 
  2.     private IBinder mRemote; 
  3.  
  4.     public ActivityManagerProxy(IBinder remote) { 
  5.         mRemote = remote; 
  6.     } 
  7.  
  8.     @Override 
  9.     public IBinder asBinder() { 
  10.         return mRemote; 
  11.     } 
  12.  
  13.     @Override 
  14.     public int startActivity(Intent intent) throws RemoteException { 
  15.         Parcel data = Parcel.obtain(); 
  16.         Parcel reply = Parcel.obtain(); 
  17.         int result; 
  18.         try { 
  19.             // 將intent參數序列化,寫入data中 
  20.             intent.writeToParcel(data, 0); 
  21.             // 調用BinderProxy對象的transact方法,交由Binder驅動處理。 
  22.             mRemote.transact(IActivityManager.TRANSACTION_startActivity, data, reply, 0); 
  23.             reply.readException(); 
  24.             // 等待server執行結束后,讀取執行結果 
  25.             result = reply.readInt(); 
  26.         } finally { 
  27.             data.recycle(); 
  28.             reply.recycle(); 
  29.         } 
  30.         return result; 
  31.     } 

***,實現Binder本地對象(IActivityManager接口):

  1. public class ActivityManagerService extends ActivityManagerNative { 
  2.     @Override 
  3.     public int startActivity(Intent intent) throws RemoteException { 
  4.         // 啟動activity 
  5.         return 0; 
  6.     } 

簡化版的ActivityManagerService到這里就已經實現了,剩下就是Client需要獲取到AMS的代理對象IActivityManager就可以通信了。實際開發過程中通過aidl文件能夠自動編譯出中間代碼,并不需要我們手動去實現,不過手動編碼能夠加深對Binder機制的理解。在開發過程中我們也并不會直接使用到AMS,但了解AMS實現原理對熟悉Framework來說必不可少,關于AMS具體實現原理,我會在后續的文章中分析。

至此,Binder機制的基本通信過程就介紹完了,由于Binder機制太過復雜,本人水平有限,文中難免出現錯誤或不足之處,歡迎大家指正。

責任編輯:未麗燕 來源: 簡書
相關推薦

2021-12-24 11:24:59

React HackReact JavaScript

2013-06-28 14:19:20

2010-07-30 16:27:06

Flex開發

2014-07-17 09:31:50

iOS8SDK

2010-03-01 10:20:27

Flex

2011-05-26 11:13:36

Flex

2023-01-30 11:43:04

開源代碼

2014-07-31 17:13:50

編碼程序員

2016-02-22 15:09:19

Android項目管理技巧

2023-06-05 16:50:06

開發TypeScriptJavaScript

2017-06-09 13:33:57

2025-02-25 08:30:00

前端開發VSCode

2015-08-21 09:47:02

ios9sdk新特性

2015-06-30 10:59:22

MobileWeb適配

2023-02-10 08:44:05

KafkaLinkedIn模式

2015-11-09 10:50:42

2017-03-28 15:47:17

數據治理數據庫

2018-05-16 09:41:13

神經網絡NN函數

2013-04-26 09:38:13

go

2024-04-26 13:36:01

點贊
收藏

51CTO技術棧公眾號

成人av网站在线| 成人在线视频免费观看| 亚洲一区二区三区视频在线播放| 超碰97国产在线| 伦av综合一区| 国产精品久久占久久| 日韩午夜av电影| 亚洲欧洲日产国码无码久久99| 成黄免费在线| 成人一区二区三区视频| 国产91精品高潮白浆喷水| 九一在线免费观看| 91久久精品无嫩草影院| 色av成人天堂桃色av| 日本精品免费视频| 久草视频在线看| 丁香啪啪综合成人亚洲小说| 国产成人精品最新| 久久久精品视频免费| 欧美日一区二区| 精品国产一区二区三区四区四 | 亚洲一区二区三区在线播放| 欧美一区二区福利| 亚洲精品喷潮一区二区三区| 麻豆免费看一区二区三区| 久久久免费精品| 久久人妻无码aⅴ毛片a片app| 婷婷亚洲精品| 亚洲第一页自拍| 欧美日韩久久婷婷| 素人啪啪色综合| 五月天一区二区| 青青草综合视频| 久久精品视频免费看| 日本一区二区免费在线| 免费在线成人av| 色网站免费观看| 国产一区在线看| 国产三级精品在线| 色婷婷一区二区| 国产精品一二三在线观看| 成人影院免费观看| 久久久国产一区二区三区四区小说 | 国产午夜精品一区二区三区欧美 | 欧美一区三区二区| 亚洲欧美国产中文| 国产精品无码久久久久| 日本韩国欧美三级| avav在线看| 亚洲日本天堂| 日韩欧美在线看| 黄色免费观看视频网站| 男人av在线播放| 欧美日韩激情小视频| 欧美激情 国产精品| av成人 com a| 午夜影院久久久| 精品久久一二三| 麻豆理论在线观看| 欧美日韩激情视频| 国产精品69页| 成人精品国产亚洲| 欧美精品免费视频| 97超碰免费在线观看| 精品视频在线观看免费观看| 7777精品伊人久久久大香线蕉| 99国产精品久久久久久| 成人av在线播放| 欧美岛国在线观看| 日本69式三人交| 免费成人av| 丝袜美腿精品国产二区| 中文国语毛片高清视频| 欧美jjzz| 性亚洲最疯狂xxxx高清| 中文在线第一页| 久久电影网站中文字幕| 91视频在线免费观看| 人妻无码一区二区三区久久99| 99精品国产视频| 日韩欧美在线一区二区| 国产在线1区| 亚洲国产综合人成综合网站| 国产91对白刺激露脸在线观看| 欧美黄色网页| 91精品国产综合久久小美女| 一本色道久久hezyo无码| 天堂网av成人| 日韩视频亚洲视频| 国产 欧美 日韩 在线| 秋霞午夜av一区二区三区| 亚洲一区美女视频在线观看免费| 日本黄色大片视频| 欧美国产欧美亚州国产日韩mv天天看完整 | 国产美女撒尿一区二区| 亚洲视频综合网| 国产成人av免费在线观看| 亚洲精品系列| 成人福利网站在线观看| 婷婷五月综合久久中文字幕| 国产精品久久网站| 欧美二区在线视频| 亚洲日日夜夜| 亚洲男子天堂网| 成年人午夜剧场| 久久国产直播| 国产精品9999久久久久仙踪林| 国产精品秘入口| 亚洲福利视频三区| 在线观看av免费观看| 亚洲性视频大全| 欧美高清videos高潮hd| 中文字幕无线码一区| 91在线你懂得| 国产a级黄色大片| 成人四虎影院| 亚洲精品一区中文字幕乱码| 精品国产百合女同互慰| 在线观看一区二区三区视频| 欧美综合在线视频观看| 性视频1819p久久| 国产免费av观看| 国产色产综合色产在线视频| 九一国产精品视频| 久久免费福利| 久久精品国产清自在天天线| 精品一区二区无码| 91热门视频在线观看| 欧美激情亚洲天堂| 婷婷精品久久久久久久久久不卡| 亚洲欧美日韩高清| 亚洲高清毛片一区二区| www.av亚洲| 日本人体一区二区| 日本精品视频| 久久九九全国免费精品观看| 中文字幕 日韩有码| 久久久久高清精品| 国产无套内射久久久国产| 牛牛影视久久网| 久久久久久久一| 成人av手机在线| 亚洲免费在线播放| 在线观看免费看片| 欧美高清不卡| 丁香婷婷久久久综合精品国产| а√中文在线8| 欧美一级午夜免费电影| 国产成人自拍网站| 国产一区二区三区在线观看免费视频| 亚洲乱码一区二区三区三上悠亚| 日韩一区二区三区在线免费观看| 亚洲欧美激情一区| 夜夜躁日日躁狠狠久久av| 国产午夜一区二区三区| 亚洲一二三区av| 精品99久久| 国产精品极品尤物在线观看| 成人在线观看免费| 欧美女孩性生活视频| 神马久久精品综合| 国产精品18久久久久久vr| 日本福利视频在线观看| 911精品国产| 2019中文字幕在线| www.国产精品.com| 欧美一区二区三区免费观看视频| 久久久美女视频| 99re8在线精品视频免费播放| av片中文字幕| 欧美1级片网站| 97超碰最新| av在线私库| 在线看日韩av| 99热在线只有精品| 欧美日韩国产精品一区二区三区四区 | 黄在线观看免费网站ktv| 欧美大片免费久久精品三p| 日韩久久久久久久久| 欧美激情综合五月色丁香| 91日韩精品视频| 亚洲激情综合| 亚洲黄色成人久久久| 亚洲精品一二三**| 全亚洲最色的网站在线观看| 在线视频91p| 亚洲第一精品电影| 中文字幕av无码一区二区三区| 亚洲六月丁香色婷婷综合久久| 日本少妇毛茸茸| 美女mm1313爽爽久久久蜜臀| 久久精品无码中文字幕| 国内黄色精品| 亚洲自拍偷拍第一页| 中文在线8资源库| 久久精品中文字幕电影| 三级无遮挡在线观看| 欧美一区二区视频观看视频| av资源免费观看| 亚洲精品视频在线观看网站| 亚洲一区二区观看| 国产精品亚洲一区二区三区在线| 国产亚洲精品网站| 亚洲一区二区三区无吗| 欧美中日韩免费视频| 6080成人| 成人亚洲综合色就1024| 97超碰在线资源| 交100部在线观看| 中文字幕亚洲欧美| 午夜福利理论片在线观看| 欧美精品 国产精品| 青青青国产在线| 亚洲精品国产精华液| 69视频在线观看免费| 91亚洲精品一区二区乱码| 国产探花在线观看视频| 日韩电影一二三区| 久无码久无码av无码| 中文字幕一区二区三区乱码图片 | 国产精品手机在线播放| 国产精品二区在线| 国产激情一区| 国产精品网址在线| 欧美1级2级| 91av成人在线| 678在线观看视频| 久久99精品国产99久久6尤物| av资源在线观看免费高清| 国产视频在线观看一区二区| 四虎免费在线观看| 亚洲成av人片在线观看香蕉| 国产女人高潮的av毛片| 欧美美女一区二区| 91在线公开视频| 欧美日韩视频在线观看一区二区三区 | 中文字幕一区久久| 久久爱另类一区二区小说| 动漫av免费观看| 日本亚洲一区二区| 国产精品动漫网站| 性色一区二区| 91黄色小网站| 日韩精品每日更新| 亚洲性生活网站| 天堂在线亚洲视频| 老头吃奶性行交视频| 日韩国产精品大片| 我要看一级黄色大片| 免费亚洲电影在线| 91女神在线观看| 久久国产精品72免费观看| 五月婷婷之婷婷| 国产一区二区三区精品视频| 欧美一级特黄aaa| 国产成人aaa| 中文字幕精品久久久| 99久久er热在这里只有精品66| 朝桐光av一区二区三区| 久久久久国产一区二区三区四区| 东方伊人免费在线观看| 国产精品国产三级国产有无不卡| www深夜成人a√在线| 一区二区三区日韩欧美| 国产一级淫片免费| 精品久久久久久中文字幕一区奶水 | 成人精品中文字幕| 中文字幕乱码一区二区三区| 欧美一区激情| xxxx18hd亚洲hd捆绑| 美女网站久久| 在线看免费毛片| 成人黄色一级视频| 成人黄色免费网址| 最新不卡av在线| 国产一级理论片| 欧美午夜美女看片| 伊人亚洲综合网| 日韩三区在线观看| 日产精品久久久久久久性色| 一区二区三区四区视频| 中文字幕在线观看网站| 欧美一级免费视频| 999精品视频在线观看| 国产精品国产精品国产专区不卡| 国产欧美日韩| 日韩视频 中文字幕| 亚洲综合欧美| 欧美黄色成人网| 中文字幕一区二区三区四区欧美| 欧美日韩一区高清| 黄色av小说在线观看| 一区二区在线免费视频| 高清电影在线观看免费| 国产精品高潮在线| 一区二区日韩| 亚洲午夜精品久久久久久浪潮| 欧美日韩少妇| 性生活免费在线观看| 99视频精品在线| 午夜国产福利一区二区| 色综合中文综合网| www国产在线| 中文字幕日韩精品有码视频| 91在线三级| 91久久精品美女高潮| 国产成人高清| 蜜臀av无码一区二区三区| 久久97超碰国产精品超碰| 中文字幕xxx| 亚洲成人精品在线观看| 国产又黄又猛又爽| 国产亚洲精品日韩| 黄色在线免费观看网站| 99九九电视剧免费观看| 日韩在线中文| 亚洲色图38p| 久久一二三国产| 日韩福利片在线观看| 制服.丝袜.亚洲.另类.中文| 国产日本在线视频| 欧美亚洲视频一区二区| 哺乳一区二区三区中文视频| 熟妇熟女乱妇乱女网站| 久久精品国产久精国产爱| 男人舔女人下部高潮全视频| 无码av免费一区二区三区试看| 99视频国产精品免费观看a| 最近免费中文字幕视频2019| 日韩成人亚洲| 免费久久一级欧美特大黄| 亚洲美女色禁图| 东京热av一区| 亚洲一区二区三区视频在线播放| 国产av精国产传媒| 久久久国产视频91| 亚洲精品自拍| 一区二区三区四区五区精品 | 天天色综合社区| 国产日韩精品一区二区浪潮av | 日本美女在线中文版| 国产精品国产三级国产专播精品人| 午夜欧洲一区| 精品国产免费av| 久久综合九色综合欧美就去吻| 一级片中文字幕| 亚洲日本中文字幕| 国产一区二区主播在线| 日韩精品一区二区三区丰满| 日产国产欧美视频一区精品| 在线观看国产精品一区| 欧美影视一区二区三区| 亚洲欧美视频一区二区| 成人免费网视频| 中文字幕免费一区二区三区| 亚洲色图欧美自拍| 亚洲午夜久久久久久久久电影院| www.成人在线观看| 午夜精品www| 国产欧美亚洲精品a| 日本在线观看免费视频| 亚洲视频中文字幕| 亚洲精华国产精华精华液网站| 久久久亚洲精品视频| 小说区图片区色综合区| 欧美性猛交久久久乱大交小说| 国产精品伦理一区二区| 精品人妻久久久久一区二区三区| 欧美激情亚洲一区| 中文字幕精品影院| 第四色婷婷基地| 艳妇臀荡乳欲伦亚洲一区| 神马亚洲视频| 国产精品视频1区| 欧美一区网站| 国产精品久久久免费观看| 欧美亚洲动漫制服丝袜| 99福利在线| 久久久久免费网| 久久激情五月激情| 一级aaa毛片| 尤物九九久久国产精品的特点 | 欧美色精品在线视频| av片在线观看免费| 精品国产乱码久久久久软件| 免费精品视频最新在线| 免费又黄又爽又色的视频| 亚洲人成网站999久久久综合| 一级欧美视频| 大陆极品少妇内射aaaaa| 国产精品成人免费精品自在线观看| 精品人妻一区二区三区四区不卡 | 在线观看欧美| 国产九九九九九| ...xxx性欧美| 水中色av综合| 91视频婷婷| 蜜桃视频一区二区三区| 日韩精品一区三区| xxx一区二区|