借助 AIDL 理解 Android Binder 機(jī)制——AIDL 的使用和原理分析

在上一篇文章——借助 AIDL 理解 Android Binder 機(jī)制——Binder 來(lái)龍去脈中我們已經(jīng)分析了使用 Binder 機(jī)制的原因以及分析了 Binder 機(jī)制墅冷,本章我們將繼續(xù)從 AIDL 的使用過(guò)程體驗(yàn) Binder 在應(yīng)用層的使用和原理糙麦。

AIDL 使用步驟

1.創(chuàng)建 UserManager.aidl 接口文件茉盏,聲明作為 Server 端的遠(yuǎn)程 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();
}

對(duì)于對(duì)象引用揪荣,還需要引入實(shí)體類(lèi)

User.aidl:

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

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

parcelable User;

跨進(jìn)程傳輸對(duì)象必須實(shí)現(xiàn) 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 類(lèi)如下:

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.創(chuàng)建 Service,實(shí)現(xiàn) UserManager.Stub 類(lèi)并將該實(shí)現(xiàn)類(lèi)的實(shí)例在 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", "進(jìn)程:" + Utils.getProcessName(getApplicationContext())
                    + "懈息,線程:" + Thread.currentThread().getName() + "————" + "Server 執(zhí)行 addUser");
            users.add(user);
        }

        @Override
        public List<User> getUserList() {
            Log.e("gpj", "進(jìn)程:" + Utils.getProcessName(getApplicationContext())
                    + "抵屿,線程:" + Thread.currentThread().getName() + "————" + "Server 執(zhí)行 getUserList");
            return users;
        }
    }

    private UserManagerNative mUserManagerNative = new UserManagerNative();

    @Override
    public IBinder onBind(Intent intent) {
        Log.e("gpj", "進(jìn)程:" + Utils.getProcessName(getApplicationContext())
                + ",線程:" + Thread.currentThread().getName() + "————" + "Server onBind");
        return mUserManagerNative;
    }
}

4.在作為 Client 端的 Activity 中奋构,綁定遠(yuǎn)程 Service 并得到 Server 的代理對(duì)象

5.通過(guò) Server 代理對(duì)象壳影,調(diào)用 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", "進(jìn)程:" + Utils.getProcessName(getApplicationContext())
                    + ",線程:" + Thread.currentThread().getName() + "————" + "Client onServiceConnected");
            mUserManager = UserManagerImpl.asInterface(service);
            try {
                //注冊(cè)遠(yuǎn)程服務(wù)死亡通知
                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;
                //重新綁定服務(wù)
                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 調(diào)用 addUser");
                        mUserManager.addUser(new User(111, "gpj"));
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(MainActivity.this, "先綁定 Service 才能調(diào)用方法", Toast.LENGTH_LONG).show();
                }
                break;
            case R.id.btn_get_size:
                if (null != mUserManager) {
                    try {
                        Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" +"Client 調(diào)用 getUserList");
                        List<User> userList = mUserManager.getUserList();
                        tvResult.setText("getUserList size:" + userList.size());
                        Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" +"調(diào)用結(jié)果:" + userList.size());
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(MainActivity.this, "先綁定 Service 才能調(diào)用方法", 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", "進(jìn)程:" + Utils.getProcessName(getApplicationContext())
                + "弥臼,線程:" + Thread.currentThread().getName() + "————" + "開(kāi)始綁定服務(wù)");
        bindService(intent, mConn, Context.BIND_AUTO_CREATE);
    }
}

AIDL 的實(shí)現(xiàn)過(guò)程

為了便于理解宴咧,這里用一個(gè) Demo 來(lái)展示 AIDL 的實(shí)現(xiàn)過(guò)程:Activity 作為 Client 與作為 Server 端的遠(yuǎn)程 Service 實(shí)現(xiàn)數(shù)據(jù)交互,在綁定遠(yuǎn)程 Service 之后径缅,點(diǎn)擊 AddUser 后 Service 會(huì)將 Client 端傳進(jìn)來(lái)的 User 對(duì)象加入列表中掺栅,點(diǎn)擊 GetSize 后遠(yuǎn)程 Service 將會(huì)把列表的長(zhǎng)度返回給客戶端。建議在繼續(xù)閱讀之前先查看或者運(yùn)行一下項(xiàng)目源碼

Demo

在項(xiàng)目中創(chuàng)建 UserManager.aidl 文件之后纳猪,系統(tǒng)會(huì)自動(dòng)在 build 目錄生成一個(gè)與 UserManager.java 接口類(lèi)氧卧,它繼承了 IInterface 接口,UserManager 接口只有一個(gè)靜態(tài)抽象類(lèi) Stub氏堤,Stub 繼承自 Binder 并實(shí)現(xiàn)了 UserManager 接口沙绝,Stub 里面也有一個(gè)靜態(tài)內(nèi)部類(lèi) Proxy,Proxy 也繼承了 UserManager(是不是有點(diǎn)亂鼠锈,亂就對(duì)了闪檬,我也很亂)。

如此嵌套是為了避免有多個(gè) .aidl 文件的時(shí)候自動(dòng)生成這些類(lèi)的類(lèi)名不會(huì)重復(fù)购笆,為了提高代碼可讀性粗悯,我們將生成的 UserManager 和 Stub 類(lèi) 拆解并重新命名成了 IUserManager 類(lèi)和 UserManagerImpl 類(lèi)并在關(guān)鍵方法上添加了注釋或者 Log。

AIDL

IUserManager.java:

public interface IUserManager extends android.os.IInterface {
    //唯一性標(biāo)識(shí)
    static final java.lang.String DESCRIPTOR = "com.me.guanpj.binder.IUserManager";

    //方法標(biāo)識(shí)同欠,用十六進(jìn)制表示
    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);
    }

    /**
     * 根據(jù) Binder 本地對(duì)象或者代理對(duì)象返回 IUserManager 接口
     */
    public static IUserManager asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        //查找本地對(duì)象
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof IUserManager))) {
            Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "返回本地對(duì)象");
            return ((IUserManager) iin);
        }
        Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "返回代理對(duì)象");
        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() + "————" + "本地對(duì)象通過(guò) Binder 執(zhí)行 addUser");
                data.enforceInterface(DESCRIPTOR);
                User arg0;
                if ((0 != data.readInt())) {
                    //取出客戶端傳遞過(guò)來(lái)的數(shù)據(jù)
                    arg0 = User.CREATOR.createFromParcel(data);
                } else {
                    arg0 = null;
                }
                //調(diào)用 Binder 本地對(duì)象
                this.addUser(arg0);
                reply.writeNoException();
                return true;
            }
            case TRANSACTION_getUserList: {
                Log.e("gpj", "線程:" + Thread.currentThread().getName() + "————" + "本地對(duì)象通過(guò) Binder 執(zhí)行 getUserList");
                data.enforceInterface(DESCRIPTOR);
                //調(diào)用 Binder 本地對(duì)象
                List<User> result = this.getUserList();
                reply.writeNoException();
                //將結(jié)果返回給客戶端
                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() + "————" + "代理對(duì)象通過(guò) Binder 調(diào)用 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() + "————" + "代理對(duì)象通過(guò) Binder 調(diào)用 getUserList");
                mRemote.transact(UserManagerImpl.TRANSACTION_getUserList, _data, _reply, 0);
                _reply.readException();
                _result = _reply.createTypedArrayList(User.CREATOR);
            } finally {
                _reply.recycle();
                _data.recycle();
            }
            return _result;
        }
    }
}

再進(jìn)行分析之前样傍,先了解幾個(gè)概念:

  1. IInterface : 從注釋中的說(shuō)明看出,聲明(自動(dòng)生成或者手動(dòng)創(chuàng)建)AIDL 性質(zhì)的接口必須繼承這個(gè)接口铺遂,這個(gè)接口只有一個(gè) IBinder asBinder() 方法衫哥,實(shí)現(xiàn)它的類(lèi)代表它能夠進(jìn)程跨進(jìn)程傳輸( Binder 本地對(duì)象)或者持有能夠進(jìn)程跨進(jìn)程傳輸?shù)膶?duì)象的引用(Binder 代理對(duì)象)。
  2. IUserManager : 它同樣是一個(gè)接口襟锐,它繼承了 IInterface 類(lèi)炕檩,并聲明了 Server 承諾給 Client 的能力
  3. IBinder : 它也是一個(gè)接口,實(shí)現(xiàn)這個(gè)接口的對(duì)象就具有了跨進(jìn)程傳輸?shù)哪芰Π聘诳邕M(jìn)程數(shù)據(jù)流經(jīng)驅(qū)動(dòng)的時(shí)候笛质,驅(qū)動(dòng)會(huì)識(shí)別IBinder類(lèi)型的數(shù)據(jù),從而自動(dòng)完成不同進(jìn)程Binder本地對(duì)象以及Binder代理對(duì)象的轉(zhuǎn)換捞蚂。
  4. Binder : 代表 Binder 本地對(duì)象妇押,BinderProxy 類(lèi)是它的內(nèi)部類(lèi),是 Server 端 Binder 對(duì)象的本地代理姓迅,它們都繼承了 IBinder 接口敲霍,因此都能跨進(jìn)程進(jìn)行傳輸,Binder 驅(qū)動(dòng)在跨進(jìn)程傳輸?shù)臅r(shí)候會(huì)將這兩個(gè)對(duì)象自動(dòng)進(jìn)行轉(zhuǎn)換丁存。
  5. UserManagerImpl : 它繼承了 Binder 并實(shí)現(xiàn)了 IInterface 接口肩杈,說(shuō)明它是 Server 端的 Binder 本地對(duì)象,并擁有 Server 承諾給 Client 的能力解寝。

先從 MainActivity 中綁定服務(wù)后的回調(diào)方法著手:

private ServiceConnection mConn = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        mUserManager = UserManagerImpl.asInterface(service);
        try {
            //注冊(cè)遠(yuǎn)程服務(wù)死亡通知
            service.linkToDeath(mDeathRecipient, 0);
        } catch (RemoteException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
        mUserManager = null;
    }
};

onServiceConnected 的參數(shù)中扩然,第一個(gè)是 Service 組件的名字,表示哪個(gè)服務(wù)被啟動(dòng)了聋伦,重點(diǎn)是類(lèi)型為 IBinder 的第二個(gè)參數(shù)夫偶,在 Service.java 中的 onBind 方法中,已經(jīng)把 Server 端的本地對(duì)象 UserManagerNative 實(shí)例返回給 Binder 驅(qū)動(dòng)了:

private UserManagerNative mUserManagerNative = new UserManagerNative();

@Override
public IBinder onBind(Intent intent) {
    return mUserManagerNative;
}

因此觉增,當(dāng)該服務(wù)被綁定的時(shí)候兵拢,Binder 驅(qū)動(dòng)會(huì)為根據(jù)該服務(wù)所在的進(jìn)程決定
是返回本地對(duì)象還是代理對(duì)象給客戶端,當(dāng) Service 與 MainActivity 位于同一個(gè)進(jìn)程當(dāng)中的時(shí)候逾礁,onServiceConnected 返回 Binder 本地對(duì)象——即 UserManagerNative 對(duì)象給客戶端说铃;當(dāng) Service 運(yùn)行在不同進(jìn)程中的時(shí)候,返回的是 BinderProxy 對(duì)象嘹履。

接著腻扇,在將這個(gè) IBinder 對(duì)象傳給 UserManagerImpl 的 asInterface 方法并返回 IUserManager 接口,asInterface 方法實(shí)現(xiàn)如下:

/**
 * 根據(jù) Binder 本地對(duì)象或者代理對(duì)象返回 IUserManager 接口
*/
public static IUserManager asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    //查找本地對(duì)象
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof IUserManager))) {
        return ((IUserManager) iin);
    }
    return new UserManagerImpl.Proxy(obj);
}

首先植捎,會(huì)根據(jù) DESCRIPTOR 調(diào)用 IBinder 對(duì)象的 queryLocalInterface 方法衙解,那么就得看 IBinder 的實(shí)現(xiàn)類(lèi)怎么處理這個(gè)方法了:

在 Binder 類(lèi)中的實(shí)現(xiàn):

public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
    //判斷 mDescriptor 跟參數(shù) DESCRIPTOR 相同,返回 mOwner
    if (mDescriptor != null && mDescriptor.equals(descriptor)) {
        return mOwner;
    }
    return null;
}

那么這個(gè) mOwner 和 mDescriptor 又是什么時(shí)候被賦值的呢焰枢?答案在 Binder 的子類(lèi) UserManagerImpl 的構(gòu)造方法里面蚓峦,:

public UserManagerImpl() {
    //將 UserManagerImpl 和 DESCRIPTOR 注入到父類(lèi)(Binder)
    this.attachInterface(this, DESCRIPTOR);
}

在 Binder$BinderProxy 類(lèi)中的實(shí)現(xiàn):

BinderProxy 并不是 Binder 本地對(duì)象,而是 Binder 的本地代理济锄,因此 queryLocalInterface 返回的是 null:

public IInterface queryLocalInterface(String descriptor) {
    return null;
}

綜上兩點(diǎn)可以看出暑椰,如果 obj.queryLocalInterface(DESCRIPTOR) 方法存在返回值并且是 IUserManager 類(lèi)型的對(duì)象荐绝,那么它就是 Binder 本地對(duì)象一汽,將它直接返回給 Client 調(diào)用;否則,使用 UserManagerImpl$Proxy 類(lèi)將其進(jìn)行包裝后再返回召夹,Proxy 類(lèi)也實(shí)現(xiàn)了 IUserManager 接口岩喷,因此,在 Client 眼中监憎,它也具有 Server 承諾給 Client 的能力纱意,那么,經(jīng)過(guò)包裝后的對(duì)象怎么和 Server 進(jìn)行交互呢鲸阔?

首先偷霉,它會(huì)把 BinderProxy 對(duì)象保存下來(lái):

Proxy(android.os.IBinder remote) {
    mRemote = remote;
}

然后,實(shí)現(xiàn) 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 對(duì)象的值寫(xiě)入 _data
            user.writeToParcel(_data, 0);
        } else {
            _data.writeInt(0);
        }
        //通過(guò) 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);
        //通過(guò) transact 跟 Server 交互
        mRemote.transact(UserManagerImpl.TRANSACTION_getUserList, _data, _reply, 0);
        _reply.readException();
        //獲取 Server 的返回值并進(jìn)程轉(zhuǎn)換
        _result = _reply.createTypedArrayList(User.CREATOR);
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

可以看到褐筛,不管什么方法类少,都是是將服務(wù)端的方法代號(hào)、處理過(guò)的參數(shù)和接收返回值的對(duì)象等通過(guò) mRemote.transact 方法 Server 進(jìn)行交互渔扎,mRemote 是 BinderProxy 類(lèi)型硫狞,在 BinderProxy 類(lèi)中,最終調(diào)用的是 transactNative 方法:

public native boolean transactNative(int code, Parcel data, Parcel reply, int flags) throws RemoteException;

它的最終實(shí)現(xiàn)在 Native 層進(jìn)行赞警,Binder 驅(qū)動(dòng)會(huì)通過(guò) ioctl 系統(tǒng)調(diào)用喚醒 Server 進(jìn)程妓忍,并調(diào)用 Server 本地對(duì)象的 onTransact 函數(shù):

@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())) {
                //取出客戶端傳遞過(guò)來(lái)的數(shù)據(jù)
                arg0 = User.CREATOR.createFromParcel(data);
            } else {
                arg0 = null;
            }
            //調(diào)用 Binder 本地對(duì)象
            this.addUser(arg0);
            reply.writeNoException();
            return true;
        }
        case TRANSACTION_getUserList: {
            data.enforceInterface(DESCRIPTOR);
            //調(diào)用 Binder 本地對(duì)象
            List<User> result = this.getUserList();
            reply.writeNoException();
            //將結(jié)果返回給客戶端
            reply.writeTypedList(result);
            return true;
        }
        default:
            break;
    }
    return super.onTransact(code, data, reply, flags);
}

在 Server 進(jìn)程中,onTransact 會(huì)根據(jù) Client 傳過(guò)來(lái)的方法代號(hào)決定調(diào)用哪個(gè)方法愧旦,得到結(jié)果后又會(huì)通過(guò) Binder 驅(qū)動(dòng)返回給 Client世剖。

總結(jié)

回溯到 onServiceConnected 回調(diào)方法,待服務(wù)連接成功后笤虫,Client 就需要跟 Server 進(jìn)行交互了旁瘫,如果 Server 跟 Client 在同一個(gè)進(jìn)程中,Client 可以直接調(diào)用 Server 的本地對(duì)象 琼蚯,當(dāng)它們不在同一個(gè)進(jìn)程中的時(shí)候酬凳,Binder 驅(qū)動(dòng)會(huì)自動(dòng)將 Server 的本地對(duì)象轉(zhuǎn)換成 BinderProxy 代理對(duì)象,經(jīng)過(guò)一層包裝之后遭庶,返回一個(gè)新的代理對(duì)象給 Client宁仔。這樣,整個(gè) IPC 的過(guò)程就完成了峦睡。

參考文章

寫(xiě)給 Android 應(yīng)用工程師的 Binder 原理剖析

Binder學(xué)習(xí)指南

文章中的代碼已經(jīng)上傳至我的 Github翎苫,如果你對(duì)文章內(nèi)容有疑問(wèn)或者有不同的意見(jiàn),歡迎留言榨了,我們一同探討煎谍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市龙屉,隨后出現(xiàn)的幾起案子呐粘,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件作岖,死亡現(xiàn)場(chǎng)離奇詭異唆垃,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)鳍咱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)降盹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人谤辜,你說(shuō)我怎么就攤上這事〖叟酰” “怎么了丑念?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)结蟋。 經(jīng)常有香客問(wèn)我脯倚,道長(zhǎng),這世上最難降的妖魔是什么嵌屎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任推正,我火速辦了婚禮,結(jié)果婚禮上宝惰,老公的妹妹穿的比我還像新娘植榕。我一直安慰自己,他們只是感情好尼夺,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布尊残。 她就那樣靜靜地躺著,像睡著了一般淤堵。 火紅的嫁衣襯著肌膚如雪寝衫。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,370評(píng)論 1 302
  • 那天拐邪,我揣著相機(jī)與錄音慰毅,去河邊找鬼。 笑死扎阶,一個(gè)胖子當(dāng)著我的面吹牛汹胃,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播乘陪,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼统台,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了啡邑?” 一聲冷哼從身側(cè)響起贱勃,我...
    開(kāi)封第一講書(shū)人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后贵扰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體仇穗,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年戚绕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纹坐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舞丛,死狀恐怖耘子,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情球切,我是刑警寧澤谷誓,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站吨凑,受9級(jí)特大地震影響捍歪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸵钝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一糙臼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧恩商,春花似錦变逃、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至研叫,卻和暖如春锤窑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嚷炉。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工渊啰, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人申屹。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓绘证,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親哗讥。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嚷那,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容