藉助 AIDL 理解 Android Binder 機制——AIDL 的使用和原理分析

guanpj發表於2019-01-10

在上一篇文章——藉助 AIDL 理解 Android Binder 機制——Binder 來龍去脈中我們已經分析了使用 Binder 機制的原因以及分析了 Binder 機制,本章我們將繼續從 AIDL 的使用過程體驗 Binder 在應用層的使用和原理。

AIDL 使用步驟

1.建立 UserManager.aidl 介面檔案,宣告作為 Server 端的遠端 Service 具有哪些能力

UserManager.aidl:

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();
}
複製程式碼

對於物件引用,還需要引入實體類

User.aidl:

// User.aidl
package com.me.guanpj.binder;

// Declare any non-default types here with import statements

parcelable User;
複製程式碼

跨程式傳輸物件必須實現 Parcelable 介面

User.java

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:

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;
}
複製程式碼

3.建立 Service,實現 UserManager.Stub 類並將該實現類的例項在 onBind 方法返回

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;
    }
}
複製程式碼

4.在作為 Client 端的 Activity 中,繫結遠端 Service 並得到 Server 的代理物件

5.通過 Server 代理物件,呼叫 Server 的具體方法

MainActivity.java:

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);
    }
}
複製程式碼

AIDL 的實現過程

為了便於理解,這裡用一個 Demo 來展示 AIDL 的實現過程:Activity 作為 Client 與作為 Server 端的遠端 Service 實現資料互動,在繫結遠端 Service 之後,點選 AddUser 後 Service 會將 Client 端傳進來的 User 物件加入列表中,點選 GetSize 後遠端 Service 將會把列表的長度返回給客戶端。建議在繼續閱讀之前先檢視或者執行一下專案原始碼

Demo

在專案中建立 UserManager.aidl 檔案之後,系統會自動在 build 目錄生成一個與 UserManager.java 介面類,它繼承了 IInterface 介面,UserManager 介面只有一個靜態抽象類 Stub,Stub 繼承自 Binder 並實現了 UserManager 介面,Stub 裡面也有一個靜態內部類 Proxy,Proxy 也繼承了 UserManager(是不是有點亂,亂就對了,我也很亂)。

如此巢狀是為了避免有多個 .aidl 檔案的時候自動生成這些類的類名不會重複,為了提高程式碼可讀性,我們將生成的 UserManager 和 Stub 類 拆解並重新命名成了 IUserManager 類和 UserManagerImpl 類並在關鍵方法上新增了註釋或者 Log。

AIDL

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;
        }
    }
}
複製程式碼

再進行分析之前,先了解幾個概念:

  1. IInterface : 從註釋中的說明看出,宣告(自動生成或者手動建立)AIDL 性質的介面必須繼承這個介面,這個介面只有一個 IBinder asBinder() 方法,實現它的類代表它能夠程式跨程式傳輸( Binder 本地物件)或者持有能夠程式跨程式傳輸的物件的引用(Binder 代理物件)。
  2. IUserManager : 它同樣是一個介面,它繼承了 IInterface 類,並宣告瞭 Server 承諾給 Client 的能力
  3. IBinder : 它也是一個介面,實現這個介面的物件就具有了跨程式傳輸的能力,在跨程式資料流經驅動的時候,驅動會識別IBinder型別的資料,從而自動完成不同程式Binder本地物件以及Binder代理物件的轉換。
  4. Binder : 代表 Binder 本地物件,BinderProxy 類是它的內部類,是 Server 端 Binder 物件的本地代理,它們都繼承了 IBinder 介面,因此都能跨程式進行傳輸,Binder 驅動在跨程式傳輸的時候會將這兩個物件自動進行轉換。
  5. UserManagerImpl : 它繼承了 Binder 並實現了 IInterface 介面,說明它是 Server 端的 Binder 本地物件,並擁有 Server 承諾給 Client 的能力。

先從 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 的過程就完成了。

參考文章

寫給 Android 應用工程師的 Binder 原理剖析

Binder學習指南

文章中的程式碼已經上傳至我的 Github,如果你對文章內容有疑問或者有不同的意見,歡迎留言,我們一同探討。

相關文章