在上一篇文章——藉助 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.javamarkdown
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 類以下:ide
UserManager.java:函數
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:oop
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:post
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,若是你對文章內容有疑問或者有不一樣的意見,歡迎留言,咱們一同探討。