本文主要介绍如何使用AIDL来实现进程间的通讯过程。
要实现进程间通讯,首先要创建两个进程的环境。通过在AndroidMenifest中配置如下属性即可使组件运行在指定的进程中
android:process=""
例如要使Service运行在名为com.example.yeliang.testapplication:remote的进程中(com.example.yeliang.testapplication 是程序的包名),可以添加如下配置
<service
android:name=".h_aidl.RemoteService"
android:process=":remote"/>
不指定此属性的组件,则默认运行在主进程。
接下来看运行在主进程的Activity和非运行主进程的Service是如何进行通讯的。
用于作为bindService方法的入参。
ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
IBookManager bookManager = BookBinder.asInterface(binder);
try {
List<Book> list = bookManager.getBookList();
Log.i("=ipc=", "onServiceConnected list = " + list);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
Intent intent = new Intent(MainProcessActivity.this, RemoteService.class);
bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);
此时远端进程的Service将会启动。
远端进程的Service创建后,首先在onCreate中创建用于主进程获取数据的Binder对象,然后在onBind()方法中返回此Binder.
public class RemoteService extends Service {
private Binder mBinder;
private CopyOnWriteArrayList<Book> mBookList = new CopyOnWriteArrayList<>();
@Override
public void onCreate() {
super.onCreate();
mBinder = new BookBinder(mBookList);
mBookList.add(new Book("Java",10020));
mBookList.add(new Book("Python",10050));
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Book book = intent.getParcelableExtra("book");
Log.i("=ipc=", "RemoteService onBind 服务端返回的 binder = " + mBinder);
return mBinder;
}
}
onBind方法返回的IBinder对象即为Activity中定义的ServiceConnection对象中的onServiceConnected方法里面的IBinder参数
onServiceConnected(ComponentName name, IBinder binder)
但是这两个IBinder并不是一个对象,本身这两个对象也不在同一个进程中。
实际上Service中onBind()方法返回的IBinder对象是BookBinder对象。
而onServiceConnected()方法中接收到的IBinder是BinderProxy对象。后续会详细介绍。
经过上面的步骤,主进程的Activity和远端进程的Service处于不同的进程。Activity中通过持有的Binder对象来调用获取远端进程的数据,进而实现进程间通讯。
在的onServiceConnected()方法中,首先会通过binder来获取一个IBookManager对象
IBookManager bookManager = BookBinder.asInterface(binder);
public interface IBookManager extends IInterface {
abstract class Stub extends android.os.Binder implements IBookManager {
private static final String DESCRIPTOR = "com.example.yeliang.testapplication.h_aidl.IBookManager";
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}
//如果客户端调用asInterface,则实际传过来的binder对象是 BinderProxy 的实例
//如果服务户端调用asInterface,则实际传过来的binder对象是 IBookManager 的实例
public static IBookManager asInterface(IBinder binder) {
Log.i("=ipc=", "Stub asInterface binder = " + binder);
if (binder == null) {
return null;
}
IInterface iInterface = binder.queryLocalInterface(DESCRIPTOR);
//1 以 (iInterface instanceof IBookManager) 来区分当前是哪个进程
if (iInterface instanceof IBookManager) {
Log.i("=ipc=", "Stub sInterface iInterface instanceof IBookManager");
//2 表示同一进程直接返回 iInterface 对象
return (IBookManager) iInterface;
}
Log.i("=ipc=", "Stub asInterface return new IBookManager.Stub.Proxy(obj)");
//3 如果不是同一个进程 则通过binder来构造Stub.Proxy对象并返回
return new IBookManager.Stub.Proxy(binder);
}
@Override
public IBinder asBinder() {
return this;
}
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
Log.i("=ipc=", "Stub.onTransact code = " + code);
switch (code) {
case INTERFACE_TRANSACTION:
Log.i("=ipc=", "Stub.onTransact case INTERFACE_TRANSACTION");
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_getBookList:
Log.i("=ipc=", "Stub.onTransact case TRANSACTION_getBookList start");
data.enforceInterface(DESCRIPTOR);
List<Book> result = getBookList();
reply.writeNoException();
reply.writeTypedList(result);
Log.i("=ipc=", "Stub.onTransact case TRANSACTION_getBookList end");
return true;
case TRANSACTION_addBook:
data.enforceInterface(DESCRIPTOR);
Book book;
if (0 != data.readInt()) {
book = Book.CREATOR.createFromParcel(data);
} else {
book = null;
}
addBook(book);
reply.writeNoException();
return true;
}
Log.i("=ipc=", "Stub.onTransact execute super");
return super.onTransact(code, data, reply, flags);
}
public static class Proxy implements IBookManager {
private IBinder mRemote;
Proxy(IBinder remote) {
mRemote = remote;
}
public String getInterfaceDescriptor() {
return DESCRIPTOR;
}
@Override
public List<Book> getBookList() throws RemoteException {
Log.i("=ipc=", "Stub.Proxy getBookList" + ", binder = " + mRemote);
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
List<Book> bookList;
try {
data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getBookList, data, reply, 0);
Log.i("=ipc=", "Stub.Proxy transact done");
reply.readException();
bookList = reply.createTypedArrayList(Book.CREATOR);
} finally {
reply.recycle();
data.recycle();
}
return bookList;
}
@Override
public void addBook(Book book) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(DESCRIPTOR);
if (book != null) {
data.writeInt(1);
book.writeToParcel(data, 0);
} else {
data.writeInt(0);
}
try {
mRemote.transact(Stub.TRANSACTION_addBook, data, reply, 0);
reply.readException();
} finally {
reply.recycle();
data.recycle();
}
}
@Override
public IBinder asBinder() {
return mRemote;
}
}
static final int TRANSACTION_getBookList = IBinder.FIRST_CALL_TRANSACTION + 0;
static final int TRANSACTION_addBook = IBinder.FIRST_CALL_TRANSACTION + 1;
}
List<Book> getBookList() throws RemoteException;
void addBook(Book book) throws RemoteException;
}
IBookManager是一个接口类,并且继承自IInterface对象
public interface IBookManager extends IInterface
IInterface是Binder的基础类,使用Binder来作为进程间通讯则必须实现此接口。
List<Book> getBookList() throws RemoteException;
void addBook(Book book) throws RemoteException;
当客户端持有IBookManager对象的实例时,即可通过此接口函数来获取远端进程的数据。
Stub首先继承自Binder,并且实现了IBookManager接口。
abstract class Stub extends android.os.Binder implements IBookManager
再来看Stub中,首先是用来标识Stub的DESCRIPTOR。
private static final String DESCRIPTOR = "com.example.yeliang.testapplication.h_aidl.IBookManager";
此方法会根据binder来创创建并返回一个IBookManager实例。
public static IBookManager asInterface(IBinder binder) {
Log.i("=ipc=", "Stub asInterface binder = " + binder);
if (binder == null) {
return null;
}
IInterface iInterface = binder.queryLocalInterface(DESCRIPTOR);
//1 以 (iInterface instanceof IBookManager) 来区分当前是哪个进程
if (iInterface instanceof IBookManager) {
Log.i("=ipc=", "Stub sInterface iInterface instanceof IBookManager");
//2 表示同一进程直接返回 iInterface 对象
return (IBookManager) iInterface;
}
Log.i("=ipc=", "Stub asInterface return new IBookManager.Stub.Proxy(obj)");
//3 如果不是同一个进程 则通过binder来构造Stub.Proxy对象并返回
return new IBookManager.Stub.Proxy(binder);
}
入参binder:
如果客户端(统一进程)调用asInterface,则实际传过来的binder对象是 BinderProxy 的实例。
如果服务户端调用asInterface,则实际传过来的binder对象是 IBookManager 的实例即BookBinder对象。
返回值IBookManger
如果调用asInterface()方法入参为BinderProxy的实例,即需要跨进程传输数据,则返回IBookManger.Stub.Proxy实例。
如果是同一进程调用asInterface()方法,则返回的是BookBinder实例。
此方法运行在服务端的进程中,用于把服务端的数据写入到Parcel对象中,然后返回给客户端。
@Override
protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
Log.i("=ipc=", "Stub.onTransact code = " + code);
switch (code) {
case INTERFACE_TRANSACTION:
Log.i("=ipc=", "Stub.onTransact case INTERFACE_TRANSACTION");
reply.writeString(DESCRIPTOR);
return true;
case TRANSACTION_getBookList:
Log.i("=ipc=", "Stub.onTransact case TRANSACTION_getBookList start");
data.enforceInterface(DESCRIPTOR);
List<Book> result = getBookList();
reply.writeNoException();
reply.writeTypedList(result);
Log.i("=ipc=", "Stub.onTransact case TRANSACTION_getBookList end");
return true;
}
Log.i("=ipc=", "Stub.onTransact execute super");
return super.onTransact(code, data, reply, flags);
}
当主进程通过IBookManager的实例即IBookManager.Stub.Proxy对象调用getBookList()方法时,Proxy将会通过transact()函数来发起远端进程的转换。
mRemote.transact(Stub.TRANSACTION_getBookList, data, reply, 0);
紧接着将会调用Stub中的onTransact()函数,onTransact()函数将会调用BookBinder获取响应数据,并将此数据写入到Pacel对象中。此时客户端即可获取到服务端的数据。
IBookBinder.Stub.Proxy是客户端的一个代理对象,通过此对象可以获取到服务端即对端进程的数据。Proxy实现了IBookManager的接口,但是这些接口并不真正做远端数据的写入操作,而是起着转发的作用,即将所要获取的数据转发给服务端的Stub#onTransact()方法执行。
2020-07-11 15:20:14.274 15752-15752/? I/=ipc=: RemoteService onBind 服务端返回的 binder = com.example.yeliang.testapplication.h_aidl.BookBinder@c1d8a61
2020-07-11 15:20:14.275 15752-15780/? I/=ipc=: Stub.onTransact code = 1079135572
2020-07-11 15:20:14.275 15752-15780/? I/=ipc=: Stub.onTransact execute super
2020-07-11 15:20:14.275 15267-15267/com.example.yeliang.testapplication I/=ipc=: Activity onServiceConnected 客户端接收到的 binder = android.os.BinderProxy@eb7fe88
2020-07-11 15:20:14.275 15267-15267/com.example.yeliang.testapplication I/=ipc=: Stub asInterface binder = android.os.BinderProxy@eb7fe88
2020-07-11 15:20:14.276 15267-15267/com.example.yeliang.testapplication I/=ipc=: Stub asInterface return new IBookManager.Stub.Proxy(obj)
2020-07-11 15:20:14.276 15267-15267/com.example.yeliang.testapplication I/=ipc=: Stub.Proxy getBookList, binder = android.os.BinderProxy@eb7fe88
2020-07-11 15:20:14.276 15752-15781/? I/=ipc=: Stub.onTransact code = 1
2020-07-11 15:20:14.276 15752-15781/? I/=ipc=: Stub.onTransact case TRANSACTION_getBookList start
2020-07-11 15:20:14.276 15752-15781/? I/=ipc=: BookBinder getBookList, binder = com.example.yeliang.testapplication.h_aidl.BookBinder@c1d8a61
2020-07-11 15:20:14.276 15752-15781/? I/=ipc=: Stub.onTransact case TRANSACTION_getBookList end
2020-07-11 15:20:14.276 15267-15267/com.example.yeliang.testapplication I/=ipc=: Stub.Proxy transact done
2020-07-11 15:20:14.276 15267-15267/com.example.yeliang.testapplication I/=ipc=: onServiceConnected list = [Book{bookId=10020, bookName='Java'}, Book{bookId=10050, bookName='Python'}]
2020-07-11 15:22:37.936 16156-16156/com.example.yeliang.testapplication I/=ipc=: RemoteService onBind 服务端返回的 binder = com.example.yeliang.testapplication.h_aidl.BookBinder@9150021
2020-07-11 15:22:37.937 16156-16156/com.example.yeliang.testapplication I/=ipc=: Activity onServiceConnected 客户端接收到的 binder = com.example.yeliang.testapplication.h_aidl.BookBinder@9150021
2020-07-11 15:22:37.937 16156-16156/com.example.yeliang.testapplication I/=ipc=: Stub asInterface binder = com.example.yeliang.testapplication.h_aidl.BookBinder@9150021
2020-07-11 15:22:37.937 16156-16156/com.example.yeliang.testapplication I/=ipc=: Stub sInterface iInterface instanceof IBookManager
2020-07-11 15:22:37.938 16156-16156/com.example.yeliang.testapplication I/=ipc=: BookBinder getBookList, binder = com.example.yeliang.testapplication.h_aidl.BookBinder@9150021
2020-07-11 15:22:37.938 16156-16156/com.example.yeliang.testapplication I/=ipc=: onServiceConnected list = [Book{bookId=10020, bookName='Java'}, Book{bookId=10050, bookName='Python'}]
1 首先定义IBookManager接口,此接口中定义了需要获取远端数据的方法。并且IBookManager实现了IInterface接口,表明IBookManager支持跨进程传输数据。
2 主进程需要获取远端进程的数据时,首先通过onServiceConnected(ComponentName name, IBinder binder)方法返回的IBinder对象来构建BookManager的实例
IBookManager bookManager = BookBinder.asInterface(binder);
因为IBookManager本身已经定义了远端进程获取数据的接口,而此处又获取到了IBookManger的实例。所以即可通过此实例来获取到远端的数据。
3 当Service和Activity运行在不同的进程时,Activity接收到的是binder为BinderProxy的实例。
当Service和Activity运行在同一的进程时,Activity接收到的binder即为BookBinder的实例。
4 BookBinder继承自BookManager.Stub类,所以BookBinder.asInterface()会调用到IBookManage.Stub的asInterface()方法。在此方法中会根据binder对象的不同返回不同的IBookManager实例。
5 当binder对象为BinderProxy实例时,会根据此binder创建一个BookManger.Stub.Proxy对象。
6 当主进程通过BookManger.Stub.Proxy获取远端方法数据时,首先会调用transact()方法
mRemote.transact(Stub.TRANSACTION_getBookList, data, reply, 0);
7 然后会调用BookManager.Stub类中的onTransat()方法,并将获取到数据写入到reply中
data.enforceInterface(DESCRIPTOR);
List<Book> result = getBookList();
reply.writeNoException();
reply.writeTypedList(result);
8 此时IBookManager.Stub.Proxy中已经能够获取到返回的reply值
bookList = reply.createTypedArrayList(Book.CREATOR);