AIDL簡介
AIDL是Android Interface Definition Language的縮寫少漆,即Android接口定義語言侧馅。它是Android的進程間通信比較常用的一種方式,其原理是通過Binder機制實現(xiàn)進程間通信的
從一個簡單的AIDL實例開始分析
由于Binder機制的進程間通信是基于C/S架構(gòu)的食棕,這里先看下客戶端需要創(chuàng)建的文件以及代碼---
- 客戶端(Client)應(yīng)用創(chuàng)建:在客戶端定義一個Book實體朗和,如果在Binder通信中傳遞非基本類型,那么除了需要創(chuàng)建一個實現(xiàn)Parcelable接口的實體類外簿晓,還需要再建個和實體類命名一樣的實體AIDL文件眶拉,如下:
// Book.aidl
package com.example.client;
parcelable Book;
在同一個包下定義一個AIDL接口文件,其中有兩個方法:
// IBookManager.aidl
package com.example.client;
//注意即使在同一個包下也需要導(dǎo)入
import com.example.client.Book;
interface IBookManager {
//添加書本
void addBook(in Book person);
//返回圖書列表
List<Book> getBookList();
}
綁定遠程服務(wù)端代碼(獲取遠程Binder引用):
private void bindService() {
Intent intent = new Intent();
intent.setComponent(new ComponentName("com.example.client", "com.xx.leo_service.LeoAidlService"));
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iBookManager = IBookManager.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected(ComponentName name) {
iBookManager = null;
}
};
-
服務(wù)端(Server)應(yīng)用創(chuàng)建憔儿,注意需要把Book實體類和AIDL接口文件完全拷貝過來忆植,包名也需要一致,除此之外谒臼,再新建一個服務(wù)朝刊,其內(nèi)部創(chuàng)建一個Binder,繼承IBookManager.Stub蜈缤,實現(xiàn)遠程方法:
void addBook(in Book book);
List<Book> getBookList();
并通過onBind()返回給客戶端
如下:
public class BookManagerService extends Service {
private ArrayList<Book> books;
private String TAG = "BookManagerService";
@Override
public IBinder onBind(Intent intent) {
books = new ArrayList<>();
Log.e(TAG, "success onBind:"+getApplicationInfo().processName);
return iBinder;
}
private IBinder iBinder = new IBookManager.Stub() {
@Override
public void addBook(Book book) throws RemoteException {
Log.e(TAG, "addBook:"+ Thread.currentThread().getName());
books.add(book);
}
@Override
public List<Book> getBookList() throws RemoteException {
Log.e(TAG, "getBookList:"+ Thread.currentThread().getName());
return books;
}
};
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG, "onCreate: success");
}
}
接下來將兩個應(yīng)用跑起來就可以在Client和Server間進行進程間通信了拾氓,在客戶端調(diào)用以下方法即會調(diào)用到服務(wù)端的具體實現(xiàn)方法:
iBookManager.addBook(new Book("歷史", 1));
List<Book> books = iBookManager.getBookList();
簡單分析下AIDL為我們生成的文件
/*
* This file is auto-generated. DO NOT MODIFY.
*/
package com.example.client;
public interface IBookManager extends android.os.IInterface {
public static abstract class Stub extends android.os.Binder implements com.example.client.IBookManager {
private static final java.lang.String DESCRIPTOR = "com.example.client.IBookManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
public static com.example.client.IBookManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.example.client.IBookManager))) {
return ((com.example.client.IBookManager) iin);
}
return new com.example.client.IBookManager.Stub.Proxy(obj);
}
@Override
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_addBook: {
data.enforceInterface(DESCRIPTOR);
com.example.client.Book _arg0;
if ((0 != data.readInt())) {
_arg0 = com.example.client.Book.CREATOR.createFromParcel(data);
} else {
_arg0 = null;
}
this.addBook(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getBookList: {
data.enforceInterface(DESCRIPTOR);
java.util.List<com.example.client.Book> _result = this.getBookList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.client.IBookManager {
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
@Override
public android.os.IBinder asBinder() {
return mRemote;
}
public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public void addBook(com.example.client.Book book) throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
if ((book != null)) {
_data.writeInt(1);
book.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public java.util.List<com.example.client.Book> getBookList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.example.client.Book> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.example.client.Book.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void addBook(com.example.client.Book book) throws android.os.RemoteException;
public java.util.List<com.example.client.Book> getBookList() throws android.os.RemoteException;
}
這里主要生成了兩個類,一個Stub和一個Proxy底哥,都實現(xiàn)了IBookManager接口咙鞍,很顯然這是代理模式
- 從客戶的綁定服務(wù)開始,可以看到在ServiceConnection的onServiceConnected方法中返回了一個IBinder參數(shù)service趾徽,通過傳入方法
IBookManager.Stub.asInterface(service)
中獲取一個客戶端代理類续滋, - 在Stub的asInterface()中,queryLocalInterface作用是判斷是否是在同一個進程中孵奶,如果是直接返回當(dāng)前對象疲酌,無需跨進程,如果不是拒课,則將遠程返回的BinderProxy(也實現(xiàn)了IBinder)傳入Proxy徐勃,創(chuàng)建一個本地客戶端代理類
- 當(dāng)調(diào)用代理類的
iBookManager.addBook(new Book("歷史", 1));
時事示,將對象序列化入?yún)⒄{(diào)用mRemote.transact()
(這個函數(shù)三個重要參數(shù):int code、Parcel data僻肖、Parcel reply肖爵,分別對應(yīng)了被調(diào)函數(shù)編號、參數(shù)包臀脏、響應(yīng)包)劝堪,這里就通過Binder驅(qū)動,調(diào)到了遠程服務(wù)端的Stub(繼承Binder實現(xiàn)IBookManger)的onTransact()方法
揉稚,根據(jù)入?yún)⒍ㄎ痪唧w方法秒啦,進而調(diào)用到服務(wù)端的Binder中addBook()
方法。getBookList()
方法調(diào)用方式一樣
整體流程很簡單搀玖,通過綁定遠程服務(wù)-->獲取遠程BinderProxy代理引用-->作為入?yún)?chuàng)建本地客戶端Proxy-->調(diào)用本地Proxy方法--->mRemote.transact()-->通過Binder底層驅(qū)動處理-->調(diào)用到遠程Stub的onTransact方法-->最終調(diào)用到遠程服務(wù)的目標實現(xiàn)方法余境。雖然服務(wù)端和客戶端有著一模一樣的代碼,可以看出Stub主要給服務(wù)端使用灌诅,而Proxy主要是給客戶端使用
類關(guān)系圖如下:bindService()如何獲取到遠程服務(wù)Binder引用
進程間通信客戶端如何從服務(wù)端獲取Binder引用是關(guān)鍵芳来,拿到了引用才能調(diào)用其遠程方法,接下來簡單分析下bindService()源碼(Android-23)猜拾。
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
-
mBase是上下文context即舌,而調(diào)用context的
bindService()
實際上實際上是調(diào)用它的實現(xiàn)類ContextImpl的bindService()
方法,所以最終會調(diào)用到ContextImpl的bindServiceCommon()
方法:bindServiceCommon.png
1.構(gòu)建IServiceConnection
后面用于給客戶端回傳服務(wù)端Binder引用挎袜。
2.ActivityManagerNative.getDefault()
獲取的其實是ActivityManagerService
本地客戶端(即當(dāng)前用戶進程)的代理類顽聂,調(diào)用ActivityManagerService
代理類的bindService()
方法,最終通過Binder驅(qū)動會跨進程調(diào)用Systemserver進程中ActivityManagerService
的bindService()
方法盯仪。
-
看下
ActivityManagerNative.getDefault()
- 由于AMS所在進程是Systemserver進程紊搪,因此應(yīng)用進程調(diào)用系統(tǒng)服務(wù)
ActivityManagerService
的方法也需要跨進程,那就必須拿到(即Systemserver進程)ActivityManagerService
服務(wù)的Binder引用全景,才能跨進程通信嗦明,所以上面代碼1處即通過ServiceManager
獲取ActivityManagerService
在遠程服務(wù)端的Binder引用,然后在2處傳入本地客戶端代理蚪燕,最終返回客戶端代理類ActivityManagerProxy
娶牌,當(dāng)調(diào)用代理類的bindService()
時即會跨進程調(diào)用服務(wù)端ActivityManagerService
方法綁定服務(wù)。可以看出這里是一次跨進程調(diào)用馆纳,應(yīng)用進程與Systemserver進程的通信诗良,通過系統(tǒng)服務(wù)ActivityManagerService
去綁定一個服務(wù) - 而1處是如何拿到AMS遠程服務(wù)的Binder引用的呢?
-
接著看下
ServiceManager.getService("activity")
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;
}
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
return sServiceManager;
}
根據(jù)系統(tǒng)服務(wù)名鲁驶,先從Cache中查找是否已有鉴裹,沒有的話則通過getIServiceManager().getService(name)
獲取,
而getIServiceManager()
中通過BinderInternal.getContextObject()
獲取遠程服務(wù)端ServiceManager
服務(wù)的Binder引用,并創(chuàng)建本地代理類径荔,通過代理類的getService()
方法調(diào)用遠程服務(wù)的getService()
方法獲取ActivityManagerService
系統(tǒng)服務(wù)督禽。
可以看到這里又是一次進程間通信,通過ServiceManager獲取系統(tǒng)服務(wù)ActivityManagerService
的Binder引用還需要與ServiceManager所在進程跨進程通信总处,那么與ServiceManager
服務(wù)通信的Binder引用又從哪里來呢狈惫??鹦马?
這里簡單介紹下ServiceManager
服務(wù)胧谈,進程間通信的客戶端想要獲取服務(wù)端的 Bind引用都需要通過它來獲取,而所有服務(wù)端都需要向ServiceManager
注冊自己的Binder以供客戶端使用荸频,由于其他進程與ServiceManager
服務(wù)進程通信也必須獲取它的Binder引用菱肖,所以ServiceManager
提供的 Binder 比較特殊,它沒有名字也不需要注冊旭从。當(dāng)一個進程使用BINDERSETCONTEXT_MGR
命令將自己注冊成 ServiceManager
時 Binder 驅(qū)動會自動為它創(chuàng)建 Binder 實體稳强,其次這個 Binder 實體的引用在所有 Client 中都固定為 0 而無需通過其它手段獲得。也就是說和悦,一個 Server 想要向ServiceManager
注冊自己的 Binder 就必須通過這個 0 號引用Binder和 ServiceManager
服務(wù)進行通信键袱。
-
回到
ActivityManagerNative.getDefault().bindService()
,經(jīng)過上面的分析可以知道其實這里調(diào)用是用戶應(yīng)用進程的ActivityManagerService
代理類(其實現(xiàn)IActivityManager接口)的bindService()摹闽,即是:ActivityManagerProxy.bindService()
public int bindService(IApplicationThread caller, IBinder token,
Intent service, String resolvedType, IServiceConnection connection,
int flags, String callingPackage, int userId) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeStrongBinder(token);
service.writeToParcel(data, 0);
data.writeString(resolvedType);
data.writeStrongBinder(connection.asBinder());
data.writeInt(flags);
data.writeString(callingPackage);
data.writeInt(userId);
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
data.recycle();
reply.recycle();
return res;
}
其實就是AIDL中代理類的方法,mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
最終會通過這個方法調(diào)用到遠程服務(wù)ActivityManagerService
的onTransact()
方法褐健,ActivityManagerService
繼承自ActivityManagerNative
付鹿,并實現(xiàn)了IActivityManager
中相應(yīng)的方法。
所以先看下ActivityManagerNative
中的transact()
方法中對應(yīng)的BIND_SERVICE_TRANSACTION
位置:
上述代碼1處即調(diào)用
ActivityManagerService
的bindService()
方法蚜迅,至此舵匾,從用戶進程切換到了AMS所在進程進行綁定服務(wù)操作。AMS服務(wù)中的相關(guān)AIDL類關(guān)系:
進入到
ActivityManagerService
中谁不,看下bindService具體實現(xiàn)流程
由于細節(jié)太多坐梯,這里僅僅列出主線,可自行根據(jù)主線方法名跟入源碼仔細研究
-
ActivityManagerService#bindService會再調(diào)用ActiveServices#bindServiceLocked
,
在ActiveServices#bindServiceLocked中
如果目標進程會去創(chuàng)建目標進程刹帕,如果服務(wù)未啟動吵血,會啟動服務(wù) - ActiveServices中啟動服務(wù)端調(diào)用流程:
bindServiceLocked()-->bringUpServiceLocked()-->realStartServiceLocked()-->app.thread.scheduleCreateService()
,在這里app.thread其實又是一個跨進程通信偷溺,從AMS進程進入到目標用戶進程蹋辅,其AIDL接口是IApplicationThread
,Stub是ApplicationThreadNative
挫掏,Proxy是ApplicationThreadProxy
侦另,遠程服務(wù)端實現(xiàn)是ActivityThread
內(nèi)部類ApplicationThread
,它繼承自ApplicationThreadNative
(這里用戶進程變成了服務(wù)端,AMS服務(wù)所在進程變成了客戶端),所以先看下客戶端代理類的ApplicationThreadProxy#scheduleCreateService
方法:image.png
可以看到調(diào)用了s.onBind
褒傅,就是我們在服務(wù)端服務(wù)中定義的onBind方法
獲取我們的Binder對象弃锐,接著又調(diào)用ActivityManagerNative.getDefault()
的publishService()
,這里非常眼熟殿托,與前面的bindService就很類似霹菊,又是跨進程通信,拿到AMS的客戶端代理碌尔,執(zhí)行它的publishService()
浇辜,最終又會交給AMS去執(zhí)行,不再重復(fù)看
- 直接到
ActivityManagerService
中找publishService()
方法唾戚,發(fā)現(xiàn)它又會調(diào)用ActiveServices#publishServiceLocked()
:
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true;
b.received = true;
for (int conni=r.connections.size()-1; conni>=0; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG_SERVICE, "Published intent: " + intent);
continue;
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")", e);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false);
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
可以看到核心部分c.conn.connected(r.name, service)
柳洋,(其實這里涉及到一開始bindServiceCommon
中構(gòu)建的IServiceConnection
,在LoadedApk
中的ServiceDispatcher.InnerConnection
中叹坦,其實本質(zhì)又是一次跨進程通信熊镣,感興趣的可以看下源碼)這里就會再調(diào)用到我們在客戶端綁定服務(wù)時傳入的ServiceConnection的onServiceConnected方法,最終客戶端拿到服務(wù)端IBinder的引用D际椤P鞔选!
至此莹捡,終于結(jié)束了鬼吵,可以發(fā)現(xiàn)為了實現(xiàn)自定義的一次跨進程通信,其內(nèi)部經(jīng)歷了無數(shù)次跨進程篮赢。齿椅。。