Android下AIDL機制詳解
AIDL全名Android Interface Definition Language,是一種介面定義語言,也是Android系統的一種跨程式通訊機制。從AIDL的名字就可以看出來,AIDL做的就是在服務提供程式和服務使用程式之間的協商好的介面,雙方通過該介面進行通訊。本文將以一個例子來講述AIDL的使用方式和流程,在下一篇文章中我將從程式碼層面對AIDL進行分析。
AIDL例項
文章中所涉及的例子來源於android開發之AIDL用法_程式間通訊原理詳解 一文。首先我們建立一個AIDL檔案,並建立了一個介面方法:
interface forService {
void registerTestCall(forActivity cb);
void invokCallBack();
}
這裡多說一句,在AIDL檔案中並不是所有的資料都可以使用,能夠使用的資料型別包括如下幾種:
* 基本資料型別(int, long, char, boolean, double等)
* String和CharSequence
* List:只支援ArrayList,並且裡面的元素都能被AIDL支援
* Map:只支援HashMap,裡面的每個元素能被AIDL支援
* Parcelable:所有實現Parcelable介面的物件
* AIDL: 所有AIDL介面本身也能在AIDL檔案中使用
另外AIDL中除了基本資料型別意外,其他資料型別必須標上方向:in、out或者inout。其實AIDL檔案和interface很像,其作用本質也是定義了一個介面,就像雙方制定的一個協議一樣,在通訊時必須遵守該協定才能正常通訊。
遠端服務端Service實現
package com.styleflying.AIDL;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Log;
public class mAIDLService extends Service {
....
@Override
public void onCreate() {
Log("service create");
}
@Override
public IBinder onBind(Intent t) {
Log("service on bind");
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
Log("service on unbind");
return super.onUnbind(intent);
}
public void onRebind(Intent intent) {
Log("service on rebind");
super.onRebind(intent);
}
private final forService.Stub mBinder = new forService.Stub() {
@Override
public void invokCallBack() throws RemoteException
{
callback.performAction();
}
@Override
public void registerTestCall(forActivity cb) throws RemoteException
{
callback = cb;
}
};
}
這裡注意一下onBind()
函式,該函式返回了一個IBinder
型別,IBinder
說明AIDL底層是基於Android Binder機制實現的,Binder機制的具體實現細節放到下一篇部落格再做詳細介紹。onBind
函式實際返回的是mBinder
型別,而該型別實際是宣告瞭一個forService.stub
型別,並在宣告中對AIDL檔案定義的介面方法做了具體的實現。所以這裡的mBinder
可以理解為一個包含了AIDL所定義介面具體實現的類,而這個類最終將傳遞給客戶端,供其呼叫。
客戶端程式碼
package com.styleflying.AIDL;
....
public class mAIDLActivity extends Activity {
private static final String TAG = "AIDLActivity";
forService mService;
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mService = forService.Stub.asInterface(service);
try {
mService.registerTestCall(mCallback);}
catch (RemoteException e) {
}
}
public void onServiceDisconnected(ComponentName className) {
Log("disconnect service");
mService = null;
}
};
}
ServiceConnection
是客戶端發起的一個指向服務端的連線,而在連線成功時(onServiceConnected
被呼叫時),通過mService =forService.Stub.asInterface(service)
獲取到了服務端傳遞過來的包含有AIDL規定介面具體實現的AIDL物件(即service端onBind
返回的物件,該物件原本是一個forService.stub
物件通過呼叫asInterface
介面獲取到了對應的AIDL物件),接下來就可以利用mService
呼叫對應的方法了。然後在連線斷開時再釋放即可。
AIDL原始碼解析
上文即是一個AIDL的使用例項,利用AIDL可以輕鬆的實現在Android端的跨應用通訊。但知其然還要知其所以然,這樣簡單的使用顯然無法透徹的瞭解AIDL通訊的原理。上文我們已經提到了AIDL實際底層利用的是Android Binder機制進行通訊,在本文中我們將從程式碼層面繼續剖析AIDL機制,而在下一篇部落格中講解Binder機制的原理。雖然我們定義的AIDL檔案只有寥寥數行,但是真正的執行起來的AIDL程式碼卻遠遠不止這點,實際上大部分的工作IDE都幫我們完成了,以上文中的forService
為例,在我們編寫完AIDL檔案後,IDE會生成其對應的java檔案forService.java
:
package ...;
import java.lang.String;
import android.os.RemoteException;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Binder;
import android.os.Parcel;
public interface forService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.styleflying.AIDL.forService
{
private static final java.lang.String DESCRIPTOR = "com.styleflying.AIDL.forService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an forService interface,
* generating a proxy if needed.
*/
public static com.styleflying.AIDL.forService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = (android.os.IInterface)obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.styleflying.AIDL.forService))) {
return ((com.styleflying.AIDL.forService)iin);
}
return new com.styleflying.AIDL.forService.Stub.Proxy(obj);
}
public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_registerTestCall:
{
data.enforceInterface(DESCRIPTOR);
com.styleflying.AIDL.forActivity _arg0;
_arg0 = com.styleflying.AIDL.forActivity.Stub.asInterface(data.readStrongBinder());
this.registerTestCall(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_invokCallBack:
{
data.enforceInterface(DESCRIPTOR);
this.invokCallBack();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.styleflying.AIDL.forService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeStrongBinder((((cb!=null))?(cb.asBinder()):(null)));
mRemote.transact(Stub.TRANSACTION_registerTestCall, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
public void invokCallBack() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_invokCallBack, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_registerTestCall = (IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_invokCallBack = (IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void registerTestCall(com.styleflying.AIDL.forActivity cb) throws android.os.RemoteException;
public void invokCallBack() throws android.os.RemoteException;
}
程式碼比較複雜,而且一看就是系統自動生成的,看起來很不規範。不用著急,我們一點一點來啃。首先這個類在內部實現了一個抽象類Stub,這個詞看起來是不是很熟悉,對了,它就是在Service端出現的那個stub。stub直譯過來是存根,也就是Service保留在本地的一個憑證。forService
類中所有的邏輯都在stub中實現。而在stub中又有一個子類稱為proxy(代理),這個類名更好理解,他是service的代理,需要用到代理的地方只有遠端的呼叫者,即客戶端。所以proxy就是從服務端傳遞到客戶端的物件,客戶端正是通過這個代理來執行AIDL中的介面方法的。
Stub
接下來我們深入兩個類來看其程式碼,首先stub通過android.os.IInterface
的attachInterface
方法來完成自我構造。接下來是asInterface
方法,客戶端正是利用這個方法來獲取到遠端服務物件的。在該方法中,首先是在本地查詢是否有DESCRIPTOR
所描述的類,如果存在直接返回;如果不存在就返回proxy。這說明當客戶端在呼叫該方法獲取遠端服務時,實際上服務端首先是會檢查服務端是否和客戶端在同一個程式中,如果在則直接返回自身,如果不是則返回proxy代理。onTransact
是指令的執行的函式,也即執行AIDL介面定義的函式實際上最終都會執行到這裡。data是傳入資料,reply是返回資料,兩個資料都是Parcel類說明在AIDL的通訊過程中資料必須經過序列化操作。不同的指令執行不同的switch分支:1)讀取資料;2)執行指令;3)返回資料。
Proxy
讀懂了Stub的原始碼,Proxy的原始碼就更加簡單了,Proxy類中有一個mRemote屬性,該屬性就是遠端的服務端stub。當客戶端利用proxy代理執行對應的方法時,proxy的執行邏輯都是:1)宣告傳入資料和返回結果兩個序列化物件;2)寫入傳入資料;3)執行方法,執行的邏輯就是呼叫mRemote的onTransact方法在遠端執行方法;4)執行完成後讀取返回結果
以上就是從程式碼層面來解析AIDL機制的實現原理,其實如果讀懂了程式碼,AIDL的實現原理也不難,stub-proxy模式也是一個常用的設計模式。但是資料和指令究竟是怎麼在兩個程式之間進行傳遞的,原始碼中卻沒有體現,這就需要了解AIDL的底層實現機制Binder了。
相關文章
- Android AIDL使用詳解AndroidAI
- Android 程式通訊機制之 AIDLAndroidAI
- Android Handler機制詳解Android
- Android Studio Service AIDL 詳解AndroidAI
- Android的IPC機制(一)——AIDL的使用AndroidAI
- 【Android原始碼】Binder機制和AIDL分析Android原始碼AI
- 藉助 AIDL 理解 Android Binder 機制——AIDL 的使用和原理分析AIAndroid
- Android 訊息機制詳解Android
- Android 程式間通訊 AIDL詳解AndroidAI
- Binder機制之AIDLAI
- Android 訊息機制詳解(Android P)Android
- android事件分發機制詳解Android事件
- Android事件機制詳細解讀Android事件
- Android AIDL SERVICE 雙向通訊 詳解AndroidAI
- Android的IPC機制(二)——AIDL實現原理簡析AndroidAI
- Android進階;Handler訊息機制詳解Android
- Android--Handler機制及原始碼詳解Android原始碼
- Android Handler訊息傳遞機制詳解Android
- Android ViewGroup 事件分發機制詳解AndroidView事件
- 藉助 AIDL 理解 Android Binder 機制——Binder 來龍去脈AIAndroid
- 從AIDL開始談Android程式間Binder通訊機制AIAndroid
- Session機制詳解Session
- AsyncTask機制詳解
- Android之Handler訊息傳遞機制詳解Android
- 詳解 Android 中的 IPC 機制:基礎篇Android
- Android頁面跳轉與返回機制詳解Android
- Redis 事件機制詳解Redis事件
- Java SPI機制詳解Java
- Java 反射機制詳解Java反射
- 回撥機制詳解
- android下的callback機制Android
- Android 事件分發機制原始碼詳解-最新 APIAndroid事件原始碼API
- 詳解 php 反射機制原理PHP反射
- JavaScript非同步機制詳解JavaScript非同步
- Java-SPI機制詳解Java
- Spring事件機制詳解Spring事件
- js執行機制詳解JS
- PHP 垃圾回收機制詳解PHP