在上一篇文章——藉助 AIDL 理解 Android Binder 機制——Binder 前因後果中咱們已經分析了使用 Binder 機制的緣由以及分析了 Binder 機制,本章咱們將繼續從 AIDL 的使用過程體驗 Binder 在應用層的使用和原理。java
UserManager.aidl:android
package com.me.guanpj.binder;
import com.me.guanpj.binder.User;
// Declare any non-default types here with import statements
interface UserManager {
void addUser(in User user);
List<User> getUserList();
}
複製代碼
對於對象引用,還須要引入實體類git
User.aidl:github
// User.aidl
package com.me.guanpj.binder;
// Declare any non-default types here with import statements
parcelable User;
複製代碼
跨進程傳輸對象必須實現 Parcelable 接口bash
User.javaide
public class User implements Parcelable {
public int id;
public String name;
public User() {}
public User(int id, String name) {
this.id = id;
this.name = name;
}
protected User(Parcel in) {
id = in.readInt();
name = in.readString();
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(id);
dest.writeString(name);
}
@Override
public int describeContents() {
return 0;
}
public static final Creator<User> CREATOR = new Creator<User>() {
@Override
public User createFromParcel(Parcel in) {
return new User(in);
}
@Override
public User[] newArray(int size) {
return new User[size];
}
};
}
複製代碼
生成的 UserManager 類以下:函數
UserManager.java:post
package com.me.guanpj.binder;
// Declare any non-default types here with import statements
public interface UserManager extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.me.guanpj.binder.UserManager
{
private static final java.lang.String DESCRIPTOR = "com.me.guanpj.binder.UserManager";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.me.guanpj.binder.UserManager interface,
* generating a proxy if needed.
*/
public static com.me.guanpj.binder.UserManager asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.me.guanpj.binder.UserManager))) {
return ((com.me.guanpj.binder.UserManager)iin);
}
return new com.me.guanpj.binder.UserManager.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
{
java.lang.String descriptor = DESCRIPTOR;
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(descriptor);
return true;
}
case TRANSACTION_addUser:
{
data.enforceInterface(descriptor);
com.me.guanpj.binder.User _arg0;
if ((0!=data.readInt())) {
_arg0 = com.me.guanpj.binder.User.CREATOR.createFromParcel(data);
}
else {
_arg0 = null;
}
this.addUser(_arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getUserList:
{
data.enforceInterface(descriptor);
java.util.List<com.me.guanpj.binder.User> _result = this.getUserList();
reply.writeNoException();
reply.writeTypedList(_result);
return true;
}
default:
{
return super.onTransact(code, data, reply, flags);
}
}
}
private static class Proxy implements com.me.guanpj.binder.UserManager
{
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 addUser(com.me.guanpj.binder.User user) 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 ((user!=null)) {
_data.writeInt(1);
user.writeToParcel(_data, 0);
}
else {
_data.writeInt(0);
}
mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
@Override public java.util.List<com.me.guanpj.binder.User> getUserList() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.util.List<com.me.guanpj.binder.User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(com.me.guanpj.binder.User.CREATOR);
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}
public void addUser(com.me.guanpj.binder.User user) throws android.os.RemoteException;
public java.util.List<com.me.guanpj.binder.User> getUserList() throws android.os.RemoteException;
}
複製代碼
MyService.java:學習
public class MyService extends Service {
class UserManagerNative extends UserManager.Stub {
List<User> users = new ArrayList<>();
@Override
public void addUser(User user) {
Log.e("gpj", "進程:" + Utils.getProcessName(getApplicationContext())
+ ",線程:" + Thread.currentThread().getName() + "————" + "Server 執行 addUser");
users.add(user);
}
@Override
public List<User> getUserList() {
Log.e("gpj", "進程:" + Utils.getProcessName(getApplicationContext())
+ ",線程:" + Thread.currentThread().getName() + "————" + "Server 執行 getUserList");
return users;
}
}
private UserManagerNative mUserManagerNative = new UserManagerNative();
@Override
public IBinder onBind(Intent intent) {
Log.e("gpj", "進程:" + Utils.getProcessName(getApplicationContext())
+ ",線程:" + Thread.currentThread().getName() + "————" + "Server onBind");
return mUserManagerNative;
}
}
複製代碼
MainActivity.java:ui
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
Button btnBind;
Button btnAddUser;
Button btnGetSize;
TextView tvResult;
IUserManager mUserManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnBind = (Button) findViewById(R.id.btn_bind);
btnAddUser = (Button) findViewById(R.id.btn_add_user);
btnGetSize = (Button) findViewById(R.id.btn_get_size);
btnBind.setOnClickListener(this);
btnAddUser.setOnClickListener(this);
btnGetSize.setOnClickListener(this);
tvResult = (TextView) findViewById(R.id.txt_result);
}
@Override
protected void onDestroy() {
unbindService(mConn);
super.onDestroy();
}
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e("gpj", "進程:" + Utils.getProcessName(getApplicationContext())
+ ",線程:" + Thread.currentThread().getName() + "————" + "Client onServiceConnected");
mUserManager = UserManagerImpl.asInterface(service);
try {
//註冊遠程服務死亡通知
service.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mUserManager = null;
}
};
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
@Override
public void binderDied() {
if (mUserManager != null) {
mUserManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
mUserManager = null;
//從新綁定服務
bindService();
}
}
};
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_bind:
bindService();
break;
case R.id.btn_add_user:
if (null != mUserManager) {
try {
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" +"Client 調用 addUser");
mUserManager.addUser(new User(111, "gpj"));
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "先綁定 Service 才能調用方法", Toast.LENGTH_LONG).show();
}
break;
case R.id.btn_get_size:
if (null != mUserManager) {
try {
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" +"Client 調用 getUserList");
List<User> userList = mUserManager.getUserList();
tvResult.setText("getUserList size:" + userList.size());
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" +"調用結果:" + userList.size());
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(MainActivity.this, "先綁定 Service 才能調用方法", Toast.LENGTH_LONG).show();
}
break;
default:
}
}
private void bindService() {
Intent intent = new Intent();
intent.setAction("com.me.guanpj.binder");
intent.setComponent(new ComponentName("com.me.guanpj.binder", "com.me.guanpj.binder.MyService"));
Log.e("gpj", "進程:" + Utils.getProcessName(getApplicationContext())
+ ",線程:" + Thread.currentThread().getName() + "————" + "開始綁定服務");
bindService(intent, mConn, Context.BIND_AUTO_CREATE);
}
}
複製代碼
爲了便於理解,這裏用一個 Demo 來展現 AIDL 的實現過程:Activity 做爲 Client 與做爲 Server 端的遠程 Service 實現數據交互,在綁定遠程 Service 以後,點擊 AddUser 後 Service 會將 Client 端傳進來的 User 對象加入列表中,點擊 GetSize 後遠程 Service 將會把列表的長度返回給客戶端。建議在繼續閱讀以前先查看或者運行一下項目源碼:
在項目中建立 UserManager.aidl 文件以後,系統會自動在 build 目錄生成一個與 UserManager.java 接口類,它繼承了 IInterface 接口,UserManager 接口只有一個靜態抽象類 Stub,Stub 繼承自 Binder 並實現了 UserManager 接口,Stub 裏面也有一個靜態內部類 Proxy,Proxy 也繼承了 UserManager(是否是有點亂,亂就對了,我也很亂)。
如此嵌套是爲了不有多個 .aidl 文件的時候自動生成這些類的類名不會重複,爲了提升代碼可讀性,咱們將生成的 UserManager 和 Stub 類 拆解並從新命名成了 IUserManager 類和 UserManagerImpl 類並在關鍵方法上添加了註釋或者 Log。
IUserManager.java:
public interface IUserManager extends android.os.IInterface {
//惟一性標識
static final java.lang.String DESCRIPTOR = "com.me.guanpj.binder.IUserManager";
//方法標識,用十六進制表示
int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
//Server 具備的能力
void addUser(User user) throws android.os.RemoteException;
List<User> getUserList() throws android.os.RemoteException;
}
複製代碼
UserManagerImpl.java:
public abstract class UserManagerImpl extends Binder implements IUserManager {
/**
* Construct the mLocalStub at attach it to the interface.
*/
public UserManagerImpl() {
this.attachInterface(this, DESCRIPTOR);
}
/**
* 根據 Binder 本地對象或者代理對象返回 IUserManager 接口
*/
public static IUserManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//查找本地對象
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IUserManager))) {
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "返回本地對象");
return ((IUserManager) iin);
}
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "返回代理對象");
return new UserManagerImpl.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_addUser: {
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "本地對象經過 Binder 執行 addUser");
data.enforceInterface(DESCRIPTOR);
User arg0;
if ((0 != data.readInt())) {
//取出客戶端傳遞過來的數據
arg0 = User.CREATOR.createFromParcel(data);
} else {
arg0 = null;
}
//調用 Binder 本地對象
this.addUser(arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getUserList: {
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "本地對象經過 Binder 執行 getUserList");
data.enforceInterface(DESCRIPTOR);
//調用 Binder 本地對象
List<User> result = this.getUserList();
reply.writeNoException();
//將結果返回給客戶端
reply.writeTypedList(result);
return true;
}
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements IUserManager {
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 addUser(User user) 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 (user != null) {
_data.writeInt(1);
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "代理對象經過 Binder 調用 addUser");
mRemote.transact(UserManagerImpl.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public List<User> getUserList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
List<User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "代理對象經過 Binder 調用 getUserList");
mRemote.transact(UserManagerImpl.TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
_result = _reply.createTypedArrayList(User.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
}
複製代碼
再進行分析以前,先了解幾個概念:
先從 MainActivity 中綁定服務後的回調方法着手:
private ServiceConnection mConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mUserManager = UserManagerImpl.asInterface(service);
try {
//註冊遠程服務死亡通知
service.linkToDeath(mDeathRecipient, 0);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
mUserManager = null;
}
};
複製代碼
onServiceConnected 的參數中,第一個是 Service 組件的名字,表示哪一個服務被啓動了,重點是類型爲 IBinder 的第二個參數,在 Service.java 中的 onBind 方法中,已經把 Server 端的本地對象 UserManagerNative 實例返回給 Binder 驅動了:
private UserManagerNative mUserManagerNative = new UserManagerNative();
@Override
public IBinder onBind(Intent intent) {
return mUserManagerNative;
}
複製代碼
所以,當該服務被綁定的時候,Binder 驅動會爲根據該服務所在的進程決定 是返回本地對象仍是代理對象給客戶端,當 Service 與 MainActivity 位於同一個進程當中的時候,onServiceConnected 返回 Binder 本地對象——即 UserManagerNative 對象給客戶端;當 Service 運行在不一樣進程中的時候,返回的是 BinderProxy 對象。
接着,在將這個 IBinder 對象傳給 UserManagerImpl 的 asInterface 方法並返回 IUserManager 接口,asInterface 方法實現以下:
/**
* 根據 Binder 本地對象或者代理對象返回 IUserManager 接口
*/
public static IUserManager asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
//查找本地對象
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof IUserManager))) {
return ((IUserManager) iin);
}
return new UserManagerImpl.Proxy(obj);
}
複製代碼
首先,會根據 DESCRIPTOR 調用 IBinder 對象的 queryLocalInterface 方法,那麼就得看 IBinder 的實現類怎麼處理這個方法了:
在 Binder 類中的實現:
public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
//判斷 mDescriptor 跟參數 DESCRIPTOR 相同,返回 mOwner
if (mDescriptor != null && mDescriptor.equals(descriptor)) {
return mOwner;
}
return null;
}
複製代碼
那麼這個 mOwner 和 mDescriptor 又是何時被賦值的呢?答案在 Binder 的子類 UserManagerImpl 的構造方法裏面,:
public UserManagerImpl() {
//將 UserManagerImpl 和 DESCRIPTOR 注入到父類(Binder)
this.attachInterface(this, DESCRIPTOR);
}
複製代碼
在 Binder$BinderProxy 類中的實現:
BinderProxy 並非 Binder 本地對象,而是 Binder 的本地代理,所以 queryLocalInterface 返回的是 null:
public IInterface queryLocalInterface(String descriptor) {
return null;
}
複製代碼
綜上兩點能夠看出,若是 obj.queryLocalInterface(DESCRIPTOR) 方法存在返回值而且是 IUserManager 類型的對象,那麼它就是 Binder 本地對象,將它直接返回給 Client 調用;不然,使用 UserManagerImpl$Proxy 類將其進行包裝後再返回,Proxy 類也實現了 IUserManager 接口,所以,在 Client 眼中,它也具備 Server 承諾給 Client 的能力,那麼,通過包裝後的對象怎麼和 Server 進行交互呢?
首先,它會把 BinderProxy 對象保存下來:
Proxy(android.os.IBinder remote) {
mRemote = remote;
}
複製代碼
而後,實現 IUserManager 的方法:
@Override
public void addUser(User user) 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 (user != null) {
_data.writeInt(1);
//將 user 對象的值寫入 _data
user.writeToParcel(_data, 0);
} else {
_data.writeInt(0);
}
//經過 transact 跟 Server 交互
mRemote.transact(UserManagerImpl.TRANSACTION_addUser, _data, _reply, 0);
_reply.readException();
} finally {
_reply.recycle();
_data.recycle();
}
}
@Override
public List<User> getUserList() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
List<User> _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
//經過 transact 跟 Server 交互
mRemote.transact(UserManagerImpl.TRANSACTION_getUserList, _data, _reply, 0);
_reply.readException();
//獲取 Server 的返回值並進程轉換
_result = _reply.createTypedArrayList(User.CREATOR);
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
複製代碼
能夠看到,無論什麼方法,都是是將服務端的方法代號、處理過的參數和接收返回值的對象等經過 mRemote.transact 方法 Server 進行交互,mRemote 是 BinderProxy 類型,在 BinderProxy 類中,最終調用的是 transactNative 方法:
public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException;
複製代碼
它的最終實如今 Native 層進行,Binder 驅動會經過 ioctl 系統調用喚醒 Server 進程,並調用 Server 本地對象的 onTransact 函數:
@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_addUser: {
data.enforceInterface(DESCRIPTOR);
User arg0;
if ((0 != data.readInt())) {
//取出客戶端傳遞過來的數據
arg0 = User.CREATOR.createFromParcel(data);
} else {
arg0 = null;
}
//調用 Binder 本地對象
this.addUser(arg0);
reply.writeNoException();
return true;
}
case TRANSACTION_getUserList: {
data.enforceInterface(DESCRIPTOR);
//調用 Binder 本地對象
List<User> result = this.getUserList();
reply.writeNoException();
//將結果返回給客戶端
reply.writeTypedList(result);
return true;
}
default:
break;
}
return super.onTransact(code, data, reply, flags);
}
複製代碼
在 Server 進程中,onTransact 會根據 Client 傳過來的方法代號決定調用哪一個方法,獲得結果後又會經過 Binder 驅動返回給 Client。
回溯到 onServiceConnected 回調方法,待服務鏈接成功後,Client 就須要跟 Server 進行交互了,若是 Server 跟 Client 在同一個進程中,Client 能夠直接調用 Server 的本地對象 ,當它們不在同一個進程中的時候,Binder 驅動會自動將 Server 的本地對象轉換成 BinderProxy 代理對象,通過一層包裝以後,返回一個新的代理對象給 Client。這樣,整個 IPC 的過程就完成了。
參考文章
文章中的代碼已經上傳至個人 Github,若是你對文章內容有疑問或者有不一樣的意見,歡迎留言,咱們一同探討。