仿寫系統AIDL框架 學習Binder機制

仿寫系統AIDL框架 學習Binder機制

目的:通過仿寫AIDL加深對Android應用層和Framework層中應用的Binder機制的理解。

AIDL(Android接口定義語言)是一種框架,對Binder的封裝。幫助我們方便的去使用Binder。如果直接用Binder需要寫很多代碼,採用AIDL可能只需要幾行。就能完成跨進程通訊。

代碼地址:https://github.com/itlgc/Android-Binder-Custom

Binder是什麼?

從IPC角度: Binder是Android中的一種跨進程通信方式。

從Android Driver層:Binder還可以理解爲一種虛擬的物理設備,它的設備驅動是/dev/binder。

從Android Native層:Binder是創建Service Manager以及BpBinder/BBinder模型,搭建與binder驅動的橋樑。

從Android Framework層:Binder是各種Manager(ActivityManager、WindowManager等)和相應xxxManagerService的橋樑。

從Android 應用層:Binder是客戶端和服務端進行通信的媒介,當bindService的時候,服務端會返回一個包含了服務端業務調用的 Binder對象,通過這個Binder對象,客戶端就可以獲取服務端提供的服務或者數據,這裏的服務包括普通服務和基於AIDL的服務。

Binder四個重要對象

IBinder
一個接口,代表跨進程通訊的能力,只要實現這個接口就能具備跨進程通訊的能力。
IInterface
代表Service這一方能提供什麼能力,即提供了哪些方法。
Binder
實現了IBinder。
Stub
使用AIDL時候,工具會給我們生成一個靜態內部類Stub,這個類extends Binder 以及 implements IInterface。 這個類也是個抽象類,具體內部實現需要我們自己去實現。

部分代碼實現

仿寫AIDL框架來模擬在Client端添加對象,Server端將對象保存到容器中,同時提供給Client端查詢的方法。

在Client通過連接Server端服務來獲取到代理

/**定義接口服務*/
public interface IPersonManager extends IInterface {
    void addPerson(Person person);
    List<Person> getPersonList();
}
//服務連接
private ServiceConnection connection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        //獲取到Server端提供的功能的代理接口
        iPersonManager = BinderStub.asInterface(service);
    }
    @Override
    public void onServiceDisconnected(ComponentName name) {
    }
};

//Client端觸發功能
 btnBinder.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View v) {
		 //通過AIDL實現調用到Server端方法
     iPersonManager.addPerson(new Person("name" + i, i++));
     //.....省略部分代碼.....
     Log.e("TAG:" + TAG,"客戶端mPersonList.size(): "+iPersonManager.getPersonList().size() + "*");
	 }
});
/**
 * 通過queryLocalInterface方法,查找本地Binder對象
 * 如果返回的就是PersonManger,說明client和server處於同一個進程,直接返回
 * 如果不是,則返回給一個代理對象
 *
 * @param iBinder Binder驅動傳來的IBinder對象
 */
public static IPersonManager asInterface(IBinder iBinder) {
    if (iBinder == null) {
        return null;
    }
    IInterface iInterface = iBinder.queryLocalInterface(DESCRIPTOR);
    if (iInterface instanceof IPersonManager) {
        Log.d("TAG:","asInterface: client和server處於同一個進程,直接返回" );
        return (IPersonManager) iInterface;
    }
    Log.d("TAG:","asInterface: client和server處於不同進程,返回代理對象" );
    return new CustomProxy(iBinder);
}

CustomProxy : 作爲Binder機制的發送端

public class CustomProxy implements IPersonManager {
    private IBinder mIBinder;
    public CustomProxy(IBinder iBinder) {
        this.mIBinder = iBinder;
    }
    /**
     * 1、首先通過Parcel將數據序列化,
     * 2、然後調用 remote.transact()將方法code,和data傳輸過去,
     * 對應的會回調在在Server中的onTransact()中
     * @param person
     */
    @Override
    public void addPerson(Person person) {
        Parcel data = Parcel.obtain();
        Parcel replay = Parcel.obtain();
        try {
            data.writeInterfaceToken(BinderStub.DESCRIPTOR);
            if (person != null) {
                data.writeInt(1);
                person.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            /**
             * 通過transact()方法將上述數據發送到Binder驅動
             * 參數1:目標方法標識符,(Client進程和Server進程自身約定)
             * 參數2:上述的Parcel對象
             * 參數3:結果回覆
             */
            mIBinder.transact(BinderStub.ADD_PERSON, data, replay, 0);
            //在發送數據後,Client進程的該線程會暫時被掛起
            replay.readException();
        }catch (RemoteException e){
            e.printStackTrace();
        }finally {
            data.recycle();
            replay.recycle();
        }
    }

    @Override
    public List<Person> getPersonList() {
      //....省略
    }

    // 3. Binder驅動根據代理對象 找到對應的真身Binder對象所在的Server進程(系統自動執行)
    // 4. Binder驅動把數據發送到Server進程中,並通知Server進程執行解包(系統自動執行)

    @Override
    public IBinder asBinder() {
        return null;
    }
}

BinderStub: 作爲Binder的接收端

public abstract class BinderStub extends Binder implements IPersonManager {

    //Binder唯一標識 自定義
    public static final String DESCRIPTOR = "com.it.binder.IPersonManager";
    // 方法標識
    public static final int GET_PERSON = IBinder.FIRST_CALL_TRANSACTION;
    public static final int ADD_PERSON = IBinder.FIRST_CALL_TRANSACTION + 1;

  	//......省略部分代碼.....

    @Override
    protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply,
                                 int flags) throws RemoteException {
        // 1. 收到Binder驅動通知後,Server 進程通過回調Binder對象onTransact()進行數據解包 & 調用目標方法
        // code即在transact()中約定的目標方法的標識符
        switch (code) {
            case INTERFACE_TRANSACTION:
                return true;

            case GET_PERSON:
                data.enforceInterface(DESCRIPTOR);
                List<Person> personList = this.getPersonList();
                if (reply != null) {
                    reply.writeNoException();
                    reply.writeTypedList(personList);
                }
                return true;

            case ADD_PERSON:
                // 解包Parcel中的數據
                data.enforceInterface(DESCRIPTOR);
                Person person = null;
                // 解析目標方法對象的標識符
                if (data.readInt() != 0) {
                    person = Person.CREATOR.createFromParcel(data);
                }
                this.addPerson(person);
                // 將結果寫入到reply
                if (reply != null)
                    reply.writeNoException();
                return true;
        }

        // 2. 將結算結果返回 到Binder驅動
        return super.onTransact(code, data, reply, flags);
    }
}

mStub對象,也就是Server中的Binder實體對象,在這裏做Server端操作。

public class ServerService extends Service {
    public static final String TAG = ServerService.class.getSimpleName();
    private List<Person> mPersonList = new ArrayList<>();

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

    private IBinder mStub =  new BinderStub() {
        @Override
        public void addPerson(Person person) {
            if (person == null) {
                Log.e("TAG:"+TAG, "null obj");
                person = new Person();
            }
            mPersonList.add(person);
            Log.e("TAG:"+TAG, "服務端mPersonList.size(): "+mPersonList.size());
        }
        @Override
        public List<Person> getPersonList() {
            return mPersonList;
        }
    };
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章