AIDL简介
AIDL是Android Interface Definition Language的缩写,即Android接口定义语言。它是Android的进程间通信比较常用的一种方式,其原理是通过Binder机制实现进程间通信的
从一个简单的AIDL实例开始分析
由于Binder机制的进程间通信是基于C/S架构的,这里先看下客户端需要创建的文件以及代码---
- 客户端(Client)应用创建:在客户端定义一个Book实体,如果在Binder通信中传递非基本类型,那么除了需要创建一个实现Parcelable接口的实体类外,还需要再建个和实体类命名一样的实体AIDL文件,如下:
// Book.aidl
package com.example.client;
parcelable Book;
在同一个包下定义一个AIDL接口文件,其中有两个方法:
// IBookManager.aidl
package com.example.client;
//注意即使在同一个包下也需要导入
import com.example.client.Book;
interface IBookManager {
//添加书本
void addBook(in Book person);
//返回图书列表
List<Book> getBookList();
}
绑定远程服务端代码(获取远程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;
}
};
-
服务端(Server)应用创建,注意需要把Book实体类和AIDL接口文件完全拷贝过来,包名也需要一致,除此之外,再新建一个服务,其内部创建一个Binder,继承IBookManager.Stub,实现远程方法:
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");
}
}
接下来将两个应用跑起来就可以在Client和Server间进行进程间通信了,在客户端调用以下方法即会调用到服务端的具体实现方法:
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,都实现了IBookManager接口,很显然这是代理模式
- 从客户的绑定服务开始,可以看到在ServiceConnection的onServiceConnected方法中返回了一个IBinder参数service,通过传入方法
IBookManager.Stub.asInterface(service)
中获取一个客户端代理类, - 在Stub的asInterface()中,queryLocalInterface作用是判断是否是在同一个进程中,如果是直接返回当前对象,无需跨进程,如果不是,则将远程返回的BinderProxy(也实现了IBinder)传入Proxy,创建一个本地客户端代理类
- 当调用代理类的
iBookManager.addBook(new Book("历史", 1));
时,将对象序列化入参调用mRemote.transact()
(这个函数三个重要参数:int code、Parcel data、Parcel reply,分别对应了被调函数编号、参数包、响应包),这里就通过Binder驱动,调到了远程服务端的Stub(继承Binder实现IBookManger)的onTransact()方法
,根据入参定位具体方法,进而调用到服务端的Binder中addBook()
方法。getBookList()
方法调用方式一样
整体流程很简单,通过绑定远程服务-->获取远程BinderProxy代理引用-->作为入参创建本地客户端Proxy-->调用本地Proxy方法--->mRemote.transact()-->通过Binder底层驱动处理-->调用到远程Stub的onTransact方法-->最终调用到远程服务的目标实现方法。虽然服务端和客户端有着一模一样的代码,可以看出Stub主要给服务端使用,而Proxy主要是给客户端使用
类关系图如下: AIDL类关系图.pngbindService()如何获取到远程服务Binder引用
进程间通信客户端如何从服务端获取Binder引用是关键,拿到了引用才能调用其远程方法,接下来简单分析下bindService()源码(Android-23)。
@Override
public boolean bindService(Intent service, ServiceConnection conn,
int flags) {
return mBase.bindService(service, conn, flags);
}
-
mBase是上下文context,而调用context的
bindService()
实际上实际上是调用它的实现类ContextImpl的bindService()
方法,所以最终会调用到ContextImpl的bindServiceCommon()
方法: bindServiceCommon.png
1.构建IServiceConnection
后面用于给客户端回传服务端Binder引用。
2.ActivityManagerNative.getDefault()
获取的其实是ActivityManagerService
本地客户端(即当前用户进程)的代理类,调用ActivityManagerService
代理类的bindService()
方法,最终通过Binder驱动会跨进程调用Systemserver进程中ActivityManagerService
的bindService()
方法。
-
看下
ActivityManagerNative.getDefault()
- 由于AMS所在进程是Systemserver进程,因此应用进程调用系统服务
ActivityManagerService
的方法也需要跨进程,那就必须拿到(即Systemserver进程)ActivityManagerService
服务的Binder引用,才能跨进程通信,所以上面代码1处即通过ServiceManager
获取ActivityManagerService
在远程服务端的Binder引用,然后在2处传入本地客户端代理,最终返回客户端代理类ActivityManagerProxy
,当调用代理类的bindService()
时即会跨进程调用服务端ActivityManagerService
方法绑定服务。可以看出这里是一次跨进程调用,应用进程与Systemserver进程的通信,通过系统服务ActivityManagerService
去绑定一个服务 - 而1处是如何拿到AMS远程服务的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;
}
根据系统服务名,先从Cache中查找是否已有,没有的话则通过getIServiceManager().getService(name)
获取,
而getIServiceManager()
中通过BinderInternal.getContextObject()
获取远程服务端ServiceManager
服务的Binder引用,并创建本地代理类,通过代理类的getService()
方法调用远程服务的getService()
方法获取ActivityManagerService
系统服务。
可以看到这里又是一次进程间通信,通过ServiceManager获取系统服务ActivityManagerService
的Binder引用还需要与ServiceManager所在进程跨进程通信,那么与ServiceManager
服务通信的Binder引用又从哪里来呢???
这里简单介绍下ServiceManager
服务,进程间通信的客户端想要获取服务端的 Bind引用都需要通过它来获取,而所有服务端都需要向ServiceManager
注册自己的Binder以供客户端使用,由于其他进程与ServiceManager
服务进程通信也必须获取它的Binder引用,所以ServiceManager
提供的 Binder 比较特殊,它没有名字也不需要注册。当一个进程使用BINDERSETCONTEXT_MGR
命令将自己注册成 ServiceManager
时 Binder 驱动会自动为它创建 Binder 实体,其次这个 Binder 实体的引用在所有 Client 中都固定为 0 而无需通过其它手段获得。也就是说,一个 Server 想要向ServiceManager
注册自己的 Binder 就必须通过这个 0 号引用Binder和 ServiceManager
服务进行通信。
-
回到
ActivityManagerNative.getDefault().bindService()
,经过上面的分析可以知道其实这里调用是用户应用进程的ActivityManagerService
代理类(其实现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);
最终会通过这个方法调用到远程服务ActivityManagerService
的onTransact()
方法,ActivityManagerService
继承自ActivityManagerNative
,并实现了IActivityManager
中相应的方法。
所以先看下ActivityManagerNative
中的transact()
方法中对应的BIND_SERVICE_TRANSACTION
位置:
上述代码1处即调用
ActivityManagerService
的bindService()
方法,至此,从用户进程切换到了AMS所在进程进行绑定服务操作。AMS服务中的相关AIDL类关系: image.png
进入到
ActivityManagerService
中,看下bindService具体实现流程
由于细节太多,这里仅仅列出主线,可自行根据主线方法名跟入源码仔细研究
-
ActivityManagerService#bindService会再调用ActiveServices#bindServiceLocked
,
在ActiveServices#bindServiceLocked中
如果目标进程会去创建目标进程,如果服务未启动,会启动服务 - ActiveServices中启动服务端调用流程:
bindServiceLocked()-->bringUpServiceLocked()-->realStartServiceLocked()-->app.thread.scheduleCreateService()
,在这里app.thread其实又是一个跨进程通信,从AMS进程进入到目标用户进程,其AIDL接口是IApplicationThread
,Stub是ApplicationThreadNative
,Proxy是ApplicationThreadProxy
,远程服务端实现是ActivityThread
内部类ApplicationThread
,它继承自ApplicationThreadNative
(这里用户进程变成了服务端,AMS服务所在进程变成了客户端),所以先看下客户端代理类的ApplicationThreadProxy#scheduleCreateService
方法: image.png
可以看到调用了s.onBind
,就是我们在服务端服务中定义的onBind方法
获取我们的Binder对象,接着又调用ActivityManagerNative.getDefault()
的publishService()
,这里非常眼熟,与前面的bindService就很类似,又是跨进程通信,拿到AMS的客户端代理,执行它的publishService()
,最终又会交给AMS去执行,不再重复看
- 直接到
ActivityManagerService
中找publishService()
方法,发现它又会调用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
中构建的IServiceConnection
,在LoadedApk
中的ServiceDispatcher.InnerConnection
中,其实本质又是一次跨进程通信,感兴趣的可以看下源码)这里就会再调用到我们在客户端绑定服务时传入的ServiceConnection的onServiceConnected方法,最终客户端拿到服务端IBinder的引用!!!
至此,终于结束了,可以发现为了实现自定义的一次跨进程通信,其内部经历了无数次跨进程。。。
网友评论