欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

解析Android AIDL的實例與原理

 更新時間:2021年06月30日 09:25:16   作者:huansky  
為使應(yīng)用程序之間能夠彼此通信,Android提供了IPC(Inter Process Communication,進(jìn)程間通信)的一種獨(dú)特實現(xiàn):AIDL(Android Interface Definition Language,Android接口定義語言)

一、概述

簡單來說,AIDL 就是定義一個接口,客戶端(調(diào)用端)通過 bindService 來與遠(yuǎn)程服務(wù)端建立一個連接,在該連接建立時會將返回一個 IBinder 對象,該對象是服務(wù)端 Binder 的 BinderProxy。在建立連接時,客戶端通過 asInterface 函數(shù)將該 BinderProxy 對象包裝成本地的 Proxy,并賦值給Proxy類的 mRemote 字段,本地通過 mRemote 即可調(diào)用遠(yuǎn)程方法。

二、創(chuàng)建 .aidl 文件

首先打開 Android Studio,new 一個 AIDL file。具體代碼如下 :

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);
}

basicTypes 方法事接口自帶的,不過可以知道,在 aidl 中只能使用這些基本類型參數(shù):int, long, boolean, float,double, String ;

除了basicTypes 方法之外,我們也可以添加自己的方法。因此,可以刪除basicTypes 方法,添加自己的方法。

三、生成 .java 文件

添加完方法之后,選中 .aidl 文件,在彈出的菜單中選擇 Synchronize LocalAIDLS... Service.java,就會會自動幫你生成對應(yīng)的 java 代碼。

格式化代碼之后,如下所示:

package com.example.databasetest;

public interface IMyAidlInterface extends android.os.IInterface {
    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.example.databasetest.IMyAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.example.databasetest.IMyAidlInterface";

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }

        /**
         * Cast an IBinder object into an com.example.databasetest.IMyAidlInterface interface,
         * generating a proxy if needed.
         */
        public static com.example.databasetest.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.databasetest.IMyAidlInterface))) {
                return ((com.example.databasetest.IMyAidlInterface) iin);
            }
            return new com.example.databasetest.IMyAidlInterface.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 {
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(DESCRIPTOR);
                    return true;
                }
                case TRANSACTION_basicTypes: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.example.databasetest.IMyAidlInterface {
            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;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);            // 這里是重點(diǎn),proxy 持有引用,這樣就可以進(jìn)行數(shù)據(jù)交換,也不會暴露這個對象
                    mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}

如果,你需要修改 .aidl 文件,那么修改之后,選擇 build -> make project 即可,會重新生成對應(yīng)的java文件。

對于生成的這個java 類,很多剛接觸的人會不理解,這里需要解釋下:

  • IMyAidlInterface :這個是我們自己定義的一個 servier 接口,也就是將你想要有的功能定義在接口中;
  • IBinder:定義了與遠(yuǎn)程對象的交互協(xié)議,代表一種跨進(jìn)程傳輸?shù)哪芰?,實現(xiàn)這個接口,就能將這個對象進(jìn)行跨進(jìn)程傳遞,但是如果要使用的話,推薦繼承其子類 Binder;
  • Binder:實現(xiàn)了 IBinder 接口,代表的其實就是Binder 本地對象。BinderProxy 類是 Binder 類的一個內(nèi)部類,它代表遠(yuǎn)程進(jìn)程的 Binder 對象的本地代理;這兩個類都繼承自IBinder, 因而都具有跨進(jìn)程傳輸?shù)哪芰?;實際上,在跨越進(jìn)程的時候,Binder 驅(qū)動會自動完成這兩個對象的轉(zhuǎn)換。
  • Stub: AIDL 的時候,編譯工具會給我們生成一個名為 Stub 的靜態(tài)內(nèi)部抽象類;這個類繼承了 Binder, 說明它是一個 Binder 本地對象,它實現(xiàn)了 IInterface 接口,表明它具有 Server 承諾給 Client 的能力;Stub 是一個抽象類,具體的 IInterface 的相關(guān)實現(xiàn)需要開發(fā)者自己實現(xiàn)。
  • IInterface:IInterface 代表的就是 Server 進(jìn)程對象具備什么樣的能力(能提供哪些方法,其實對應(yīng)的就是 AIDL 文件中定義的接口)
  • proxy:Stub 的靜態(tài)內(nèi)部類,是一個實現(xiàn)了IMyAidlInterface接口,所以他是一個遠(yuǎn)程代理對象,可以用于返回給客戶端用。當(dāng) client 調(diào)用 proxy的某個方法的時候,會將參數(shù)傳到 proxy 中,在通過其持有的遠(yuǎn)程實際對象,將方法名和參數(shù)等都傳給遠(yuǎn)程實際對象,然后就會回調(diào)onTransact,對應(yīng)的方法就會被調(diào)用,以此來實現(xiàn)跨進(jìn)程調(diào)用。

四、傳輸復(fù)雜數(shù)據(jù)

如果,需要傳遞復(fù)雜數(shù)據(jù),那么就需要實現(xiàn)Parcelable 接口,可序列化:

public class Info implements Parcelable {


    private String content;

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Info() {
    }

    public Info(Parcel in) {
        content = in.readString();

    }

    public static final Creator<Info> CREATOR = new Creator<Info>() {
        @Override
        public Info createFromParcel(Parcel in) {
            return new Info(in);
        }

        @Override
        public Info[] newArray(int size) {
            return new Info[size];
        }
    };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(content);

    }

    /**
     * 參數(shù)是一個Parcel,用它來存儲與傳輸數(shù)據(jù)
     *
     * @param dest
     */
    public void readFromParcel(Parcel dest) {
        //注意,此處的讀值順序應(yīng)當(dāng)是和writeToParcel()方法中一致的
        content = dest.readString();

    }

    //方便打印數(shù)據(jù)
    @Override
    public String toString() {
        return "content : " + content;
    }
}

與此同時,也要建一個 info.aidl 文件,表明數(shù)據(jù)也是可以傳遞的。

package com.viii.aidlclient;

//注意:Info.Info.java的包名應(yīng)當(dāng)是一樣的

//這個文件的作用是引入了一個序列化對象 Info 供其他的AIDL文件使用

//注意parcelable是小寫
parcelable Info;

這樣就可以使用 info 對象了。 不用在受前面的基本類型變量所控制。

五、建立 service

接下去,新建一個Service負(fù)責(zé)接收消息,并在AndroidManifest.xml里面注冊 Service:

public class MyService extends Service {

    private static final String TAG = "MyService";

   // private MyBinder mMyBinder = new MyBinder();

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        Log.d(TAG, "onBind: ");     // 應(yīng)該返回 mBinder
        return null;
    }

    @Override
    public void onCreate() {
        Log.d(TAG, "onCreate: ");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand: ");
        return super.onStartCommand(intent, flags, startId);
    }

  // 這里就是服務(wù)端的實現(xiàn),繼承了 stub,想要怎么樣的能力,自己去實現(xiàn)
    private final IMyAidlInterface.Stub mBinder = new IMyAidlInterface.Stub() {

        @Override
        public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {
      // 具體實現(xiàn)過程
        }
    };

}

這時候,可以basicTypes 方法添加具體函數(shù)代碼,實現(xiàn)你想要的功能。

當(dāng)我們在本地獲取到代理后之后,調(diào)用basicTypes 就會觸發(fā)服務(wù)端的調(diào)用。

六、獲取服務(wù)

接下去在 mainactivity 中進(jìn)行綁定。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private IMyAidlInterface mService;
    private boolean mIsBound;
    private AdditionServiceConnection mServiceConnection;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        doBindService() ;
    }/**
     * bind service
     */
    private void doBindService() {
        mServiceConnection = new AdditionServiceConnection();
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, mServiceConnection, BIND_AUTO_CREATE);

    }

    /**
     * unbind service
     */
    private void doUnbindService() {
        if (mIsBound) {
            unbindService(mServiceConnection);
            mServiceConnection = null;
            mIsBound = false;
        }
    }

    /**
     * ServiceConection
     */

    class AdditionServiceConnection implements ServiceConnection {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {       // 連接的時候獲取本地代理,這樣我們就可以調(diào)用 service 中的方法了。
            mService = IMyAidlInterface.Stub.asInterface((IBinder) service);
            mIsBound = true;
            try {
                //設(shè)置死亡代理
                service.linkToDeath(mDeathRecipient, 0);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            Log.d(TAG, "onServiceConnected: ");
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
            mIsBound = false;
            Log.d(TAG, "onServiceDisconnected: ");
        }
    }

    /**
     * 監(jiān)聽Binder是否死亡
     */
    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        @Override
        public void binderDied() {
            if (mService == null) {
                return;
            }
            mService.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mService = null;
            //重新綁定
            doBindService();
        }
    };

    @Override
    protected void onStop() {
        super.onStop();
        doUnbindService();
    }
}

將遠(yuǎn)程服務(wù)的 binder 拿到之后,我們就可以調(diào)用相關(guān)方法實現(xiàn)自己的功能呢。

到這里,一個 AIDL 就被我們實現(xiàn)了。

七、分析調(diào)用過程

看看 asInterface 方法,我們在 bind 一個 Service 之后,在 onServiceConnecttion 的回調(diào)里面,就是通過這個方法拿到一個遠(yuǎn)程的 service 的,這個方法做了什么呢?

/**
    * Cast an IBinder object into an com.example.databasetest.IMyAidlInterface interface,
    * generating a proxy if needed.
    */
public static com.example.databasetest.IMyAidlInterface asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.example.databasetest.IMyAidlInterface))) {
        return ((com.example.databasetest.IMyAidlInterface) iin);
    }        // 實際上,代理對象持有真實對象,同時代理對象會對數(shù)據(jù)進(jìn)行處理后,再調(diào)用實體對象的方法
    return new com.example.databasetest.IMyAidlInterface.Stub.Proxy(obj);
}

首先看函數(shù)的參數(shù)IBinder類型的 obj,這個對象是驅(qū)動給我們的,如果是 Binder 本地對象,那么它就是 Binder 類型,如果是 Binder 代理對象,那就是BinderProxy類型;它會試著查找 Binder 本地對象,如果找到,說明 Client 和 Server 都在同一個進(jìn)程,這個參數(shù)直接就是本地對象,直接強(qiáng)制類型轉(zhuǎn)換然后返回。

如果找不到,說明是遠(yuǎn)程對象(處于另外一個進(jìn)程)那么就需要創(chuàng)建一個 Binder 代理對象,讓這個 Binder 代理實現(xiàn)對于遠(yuǎn)程對象的訪問。一般來說,如果是與一個遠(yuǎn)程 Service 對象進(jìn)行通信,那么這里返回的一定是一個 Binder 代理對象,這個 IBinder 參數(shù)的實際上是 BinderProxy;

再看看我們對于 aidl 的basicTypes方法的實現(xiàn);在 Stub 類里面,basicTypes是一個抽象方法,我們需要繼承這個類并實現(xiàn)它;如果 Client 和 Server 在同一個進(jìn)程,那么直接就是調(diào)用這個方法;那么,如果是遠(yuǎn)程調(diào)用,這中間發(fā)生了什么呢?Client 是如何調(diào)用到 Server 的方法的?

對于遠(yuǎn)程方法的調(diào)用,是通過 Binder 代理完成的,在這個例子里面就是Proxy類;Proxy對于basicTypes方法的實現(xiàn)如下:

public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        _data.writeInt(anInt);
        _data.writeLong(aLong);
        _data.writeInt(((aBoolean) ? (1) : (0)));
        _data.writeFloat(aFloat);
        _data.writeDouble(aDouble);
        _data.writeString(aString);
            // 這里是重點(diǎn),調(diào)用的是實體對象的方法
        mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}

它首先用 Parcel 把數(shù)據(jù)序列化了,然后調(diào)用了 transact 方法;這個 transact 到底做了什么呢?這個 Proxy 類在 asInterface 方法里面被創(chuàng)建,前面提到過,如果是 Binder 代理那么說明驅(qū)動返回的 IBinder 實際是 BinderProxy,因此我們的 Proxy 類里面的 mRemote 實際類型應(yīng)該是BinderProxy;我們看看 BinderProxy 的 transact 方法:( Binder.java 的內(nèi)部類)

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

這是一個本地方法;它的實現(xiàn)在 native 層,具體來說在 frameworks/base/core/jni/android_util_Binder.cpp 文件,里面進(jìn)行了一系列的函數(shù)調(diào)用,調(diào)用鏈實在太長這里就不給出了;要知道的是它最終調(diào)用到了talkWithDriver函數(shù);看這個函數(shù)的名字就知道,通信過程要交給驅(qū)動完成了;這個函數(shù)最后通過 ioctl 系統(tǒng)調(diào)用,Client 進(jìn)程陷入內(nèi)核態(tài),Client 調(diào)用 basicTypes 方法的線程掛起等待返回;驅(qū)動完成一系列的操作之后喚醒 Server 進(jìn)程,調(diào)用了Server進(jìn)程本地對象的 onTransact 函數(shù)(實際上由 Server 端線程池完成)。我們再看 Binder 本地對象的 onTransact 方法(這里就是 Stub 類里面的此方法):

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_basicTypes: {
            data.enforceInterface(DESCRIPTOR);
            int _arg0;
            _arg0 = data.readInt();
            long _arg1;
            _arg1 = data.readLong();
            boolean _arg2;
            _arg2 = (0 != data.readInt());
            float _arg3;
            _arg3 = data.readFloat();
            double _arg4;
            _arg4 = data.readDouble();
            java.lang.String _arg5;
            _arg5 = data.readString();
            this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
            reply.writeNoException();
            return true;
        }
    }
    return super.onTransact(code, data, reply, flags);
}

在 Server 進(jìn)程里面,onTransact 根據(jù)調(diào)用號(每個 AIDL 函數(shù)都有一個編號,在跨進(jìn)程的時候,不會傳遞函數(shù),而是傳遞編號指明調(diào)用哪個函數(shù))調(diào)用相關(guān)函數(shù)。

在這個例子里面,調(diào)用了 Binder 本地對象的 basicTypes 方法;這個方法將結(jié)果返回給驅(qū)動,驅(qū)動喚醒掛起的 Client 進(jìn)程里面的線程并將結(jié)果返回。于是一次跨進(jìn)程調(diào)用就完成了。

至此,你應(yīng)該對 AIDL 這種通信方式里面的各個類以及各個角色有了一定的了解;它總是那么一種固定的模式:一個需要跨進(jìn)程傳遞的對象一定繼承自 IBinder,如果是 Binder 本地對象,那么一定繼承 Binder 實現(xiàn) IInterface,如果是代理對象,那么就實現(xiàn)了 IInterface 并持有了 IBinder 引用;

Proxy 與 Stub 不一樣,雖然他們都既是 Binder 又是 IInterface,不同的是 Stub 采用的是繼承(is 關(guān)系),Proxy采用的是組合(has 關(guān)系)。他們均實現(xiàn)了所有的 IInterface 函數(shù)。

不同的是,Stub又使用策略模式調(diào)用的是虛函數(shù)(待子類實現(xiàn)),而 Proxy 則使用組合模式。為什么Stub采用繼承而 Proxy 采用組合?事實上,Stub 本身 is 一個 IBinder(Binder),它本身就是一個能跨越進(jìn)程邊界傳輸?shù)膶ο?,所以它得繼承 IBinder 實現(xiàn) transact 這個函數(shù)從而得到跨越進(jìn)程的能力(這個能力由驅(qū)動賦予)。

Proxy 類使用組合,是因為他不關(guān)心自己是什么,它也不需要跨越進(jìn)程傳輸,它只需要擁有這個能力即可,要擁有這個能力,只需要保留一個對 IBinder 的引用。

以上就是解析Android AIDL的實例與原理的詳細(xì)內(nèi)容,更多關(guān)于Android AIDL的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論