Binder機制,從Java到C (1. IPC in Application Remote Service)


轉載請標注:張新燕:http://www.cnblogs.com/zhangxinyan

1. Application 中的 service

我們知道Android中Service有三種類型:Local ServiceLocal Bounded ServiceRemote Service

Local Service:基本是提供給自已應用使用,通過startService(intent)來啟動。

Local Bounded Service:也是提供給自己應用使用,通過bindService(intent)啟動,然后在回調中獲得service,這種service一般很少寫,因為既然只提供給自己使用,又何必從回調繞個圈子呢。用第一種service就好了。

RemoteService:可以共享給更多使用者,這里就會涉及到IPC機制。在Android中,IPC機制是通過Binder來實現的。接下來就讓我們開始看看Binder究竟是什么玩意吧~

 

2.Remote Service:

先來看看App層會遇到IPC的地方。
我們在寫App時,當遇到需要在后台默默做點什么事情時,就會采用Service這個組件,當你這個Service要大公無私的向外面提供服務時,我們會采用RemoteService這個玩意。下面我們就看一下怎么樣來寫一個RemoteService:

1.先定義一個aidl文件在這個文件里寫上這個Service可以完成的功能接口

1 package com.example.remoteservice;  
2     interface IRemoteService {  
3         void doSomething ( );
4     }  


2.實現Remote Service寫一個Service組件,在這個組件里,實現Stub(Stub是啥?后面有說)的具體功能,這些功能就對應了上面aidl文件里面定義的一些接口。
接着在回調函數onBind()中把這個實現的Stub對象返回出去。那誰會來調用這個onBind()函數呢?當然是ActivityManagerService啦,有關與ActivityManagerService的詳細內容會新開一篇詳細說明。下面就看代碼吧:

 1 public class RemoteService extends Service {
 2         @Override  
 3         public IBinder onBind(Intent intent) {  
 4            if (IRemoteService.class.getName().equals(intent.getAction())) {
 5                return mRemoteBinder;  //把一個Binder對象返回出去。其實是返回到AMS里面了。AMS:ActivityManagerService。
 6            }  
 7             return null;  
 8         }
 9         private final IRemoteService.Stub mRemoteBinder =new IRemoteService.Stub() {//實現Stub對象要求的方法,即AIDL的實現。
10            public void dosomething() {
11                blablabla;  
12            }  
13         };  
14     }

 

3.訪問Remote Service接着就是在Activity里面啟動和調用Service的功能了,怎么調用呢?看代碼:

 1 public class Helloworld extends Activity  
 2 {  
 3     ...
 4     @Override  
 5     public void onCreate(Bundle savedInstanceState)  
 6     {  
 7        super.onCreate(savedInstanceState);  
 8        setContentView(R.layout.main);  
 9        bindService(new Intent(IRemoteService.class.getName()),mRemoteConnection,  
10                     Context.BIND_AUTO_CREATE);  // 1.觸發Service端回調onBind()。     (1)
11        ...
12        mRemoteService.getPid(); //3. 會通過Binder IPC 將操作請求發送到Service端的Stub實現。    (3)
13        ...
14     }  
15 
16     private ServiceConnection mRemoteConnection = new ServiceConnection() {
17        public void onServiceConnected(ComponentName className, IBinder service) {     (2)
18            Log.i("binder_test","IBinder service : " + service.getClass());//通過Log發現,這個service是BinderProxy object,BinderProxy是什么呢?後面再說。暫時按字面理解為Binder代理對象。
19 
20 
21            mRemoteService = IRemoteService.Stub.asInterface(service); // 2.通過asInterface,把Binder代理對象轉化成接口。
22        }  
23        public void onServiceDisconnected(ComponentName className) {  
24            mRemoteService = null;  
25        }  
26 };     
27 }   

 

說明:
(1)  :在這里調用bindService,最后其實會調用到AMS(ActivityManagerService)中。AMS就會去查找當前系統中有沒有已經啟動過這個Service了,如果沒有啟動這個Service,就把它啟動起來。然后會調用它的onBind()回調,獲得Service的Binder對象。再經過一系列處理后,從調用者 Activity 的 (2)這個地方回調回來,把service傳給它,當然其中對象會有一些變化,我們在回調的這個地方把返回的service打印了出來:


所以那個回調 onServiceConnected傳進來的 IBinder service,它其實是一個BinderProxy!按照字面意思,我們稱它為 Binder代理對象,先不管這個IBinder是來的,也不管BinderProxy到底是什么,先往下看,看下去你就會慢慢知道了。
這個對象返回到Activity中之后,通過asInterface進行一個轉化,轉化成了接口,其實是轉化成了Proxy對象啦,Proxy對象實現了接口。
那這個轉化得來的mRemoteService,我們以后就稱之為 Service代理對象
(3) :這樣,獲得了Service的代理對象之后,就可以通過Service代理對象調用Service的功能啦。雖然Service具體的執行是在另外一個進程,但是你是感覺不到的。

 

3. AIDL 工具

上面說的內容似乎有點亂,那我們整理下上面的訪問過程,可以看一下下面的圖:

這里面的Stub對象Stub.Proxy對象,這些對象我們上面都沒有創建吧?這些類其實都是由aidl工具自動生成的。

 Client中Activity,通過bindService,觸發Service回調onBind()方法,把一個Binder代理對象返回給Client。

Client通過轉化,轉化成一個Service代理對象,Client通過這個Service代理對象,在通過底層的Binder驅動,就可以調用進Service進程。在Service進程收到請求后,會根據里面的一個參數值,找到對應的函數,執行具體的操作。

 

 

下面這個類就是用了aidl工具后,IRemoteService.aidl自動生成的對應的類:IRemoteService.java

 1 package com.example.remoteservice;  
 2 
 3     public interface IRemoteService extends android.os.IInterface { 1  
 4         public static abstract class Stub extends android.os.Binder implements  
 5                com.example.remoteservice.IRemoteService {//繼承Binder,並且實現了IRemoteService接口
 6              ...
 7            public static com.example.remoteservice.IRemoteService asInterface(android.os.IBinder obj) {//根據傳進來的IBinder對象創建一個Service 代理對象給客戶端。
 8                ...
 9                android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);  
10                if (((iin != null) && (iin instanceof com.example.remoteservice.IRemoteService))) {  
11                     return((com.example.remoteservice.IRemoteService) iin);  
12                }  
13                return new com.example.remoteservice.IRemoteService.Stub.Proxy(obj);  //看,返回的是Proxy這個對象。就是Service代理對象。
14            }  
15 
16            public android.os.IBinder asBinder() {  
17                return this;  
18            }  
19 
20            @Override  
21            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply,  
22                     int flags)throwsandroid.os.RemoteException { //把IPC消息取出來解析,找到具體執行方法。
23                switch (code) {  //根據code值,找到方法。
24                     case INTERFACE_TRANSACTION: {  
25                     }  
26                     case TRANSACTION_doSomething: { 
27                     }  
28                }  
29                return super.onTransact(code, data, reply, flags);    
30            }  
31 
32            private static class Proxy implements com.example.remoteservice.IRemoteService {//實現了IRemoteService接口
33                private android.os.IBinder mRemote; //實際上是BinderProxy對象
34               ...
35                public int doSomething() throws android.os.RemoteException {
36                      ...
37                         mRemote.transact(Stub.TRANSACTION_doSomething,_data, _reply, 0);//通過BinderProxy將命令發送出去。 
38                     ….
39            }  
40             static final int TRANSACTION_doSomething = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);   //這玩意就是用來區別方法的code。
41         }  
42 
43         public void doSomething() throwsandroid.os.RemoteException;   
44     }  

 

這里面呢,會涉及到幾個類,Proxy啦,Binder啦等等,他們的關系圖可以在下圖中看出:

 

那Stub和Proxy都實現了了IRemoteService。但是呢Proxy只是把參數包裝一下,通過mRemote發送出去。

Stub就是真正實現的地方了,不過這邊實現的代碼其實是寫在Service里的,就是那個mRemoteBinder。

Proxy類是Stub的一個子類。Proxy里面的mRemote就是BinderProxy,通過它就可以把請求發送出去,然后再通過底層Binder的一些操作,最后走到Service進程里去執行一些操作。

 

那來總結一下吧,上面這個過程可以概括的說是:

1.Activity通過AMS的bindService(String name),讓AMS做一些查找操作,然后AMS把一個service的Binder代理對象返回給Activity。
2.Activity通過一個轉換,創建一個service代理對象Proxy,其是在Proxy里面,還是利用Binder代理對象向service發送命令。

 

下一篇會將一下AMS里面的IPC機制:

Binder機制,從Java到C (2. IPC in System Service :AMS)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM