Android AIDL 의 인 스 턴 스 와 원 리 를 분석 합 니 다.

19982 단어 AndroidAIDL
개술
쉽게 말 하면 AIDL 은 하나의 인 터 페 이 스 를 정의 하 는 것 입 니 다.클 라 이언 트(호출 단)는 bindService 를 통 해 원 격 서버 와 연결 을 만 들 고 이 연결 을 만 들 때 IBinder 대상 을 되 돌려 줍 니 다.이 대상 은 서버 Binder 의 BinderProxy 입 니 다.연결 을 만 들 때 클 라 이언 트 는 asInterface 함 수 를 통 해 이 BinderProxy 대상 을 원가 의 Proxy 로 포장 하고 Proxy 류 의 mRemote 필드 에 값 을 부여 합 니 다.로 컬 은 mRemote 를 통 해 원 격 방법 을 호출 할 수 있 습 니 다.
2..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);
}
basic Types 방법 은 인터페이스 가 자체 적 으로 가지 고 있 지만,aidl 에 서 는 이러한 기본 적 인 유형의 매개 변수 만 사용 할 수 있 습 니 다:int,long,boolean,float,double,String;
basic Types 방법 외 에 도 우 리 는 자신의 방법 을 추가 할 수 있 습 니 다.따라서 basic Types 방법 을 삭제 하고 자신의 방법 을 추가 할 수 있 습 니 다.
3.자바 파일 생 성
방법 을 추가 한 후.aidl 파일 을 선택 하고 팝 업 메뉴 에서 Synchronize LocalAIDLS...Service.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);            //      ,proxy     ,           ,         
                    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 procject 를 선택 하면 해당 하 는 자바 파일 을 다시 생 성 할 수 있 습 니 다.
생 성 된 이 자바 류 에 대해 서 는 갓 접촉 한 사람들 이 이해 하지 못 하 는 경우 가 많 습 니 다.여기 서 설명 이 필요 합 니 다.
  • IMyAidlInterface:이것 은 우리 가 정의 한 servier 인터페이스 입 니 다.즉,당신 이 원 하 는 기능 을 인터페이스 에 정의 하 는 것 입 니 다.
  • IBinder:원 격 대상 과 의 상호작용 프로 토 콜 을 정의 하고 크로스 프로 세 스 전송 능력 을 대표 하 며 이 인 터 페 이 스 를 실현 하면 이 대상 을 크로스 프로 세 스 로 전달 할 수 있 습 니 다.그러나 사용 하려 면 하위 클래스 Binder 를 계승 하 는 것 을 추천 합 니 다.
  • Binder:IBinder 인 터 페 이 스 를 실 현 했 는데 대표 적 인 것 은 바로 Binder 로 컬 대상 입 니 다.BinderProxy 클래스 는 Binder 클래스 의 내부 클래스 로 원 격 프로 세 스 를 대표 하 는 Binder 대상 의 로 컬 에이전트 입 니 다.이 두 가지 유형 은 모두 IBinder 에서 계승 되 기 때문에 프로 세 스 를 뛰 어 넘 는 전송 능력 을 가진다.실제로 프로 세 스 를 뛰 어 넘 을 때 Binder 드라이브 는 이 두 대상 의 전환 을 자동 으로 완성 합 니 다.
  • Stub:AIDL 일 때 컴 파일 도 구 는 Stub 라 는 정적 내부 추상 류 를 만들어 줍 니 다.이 종 류 는 Binder 를 계승 하여 Binder 로 컬 대상 임 을 설명 합 니 다.IInterface 인 터 페 이 스 를 실현 하여 Server 가 Client 에 약속 하 는 능력 을 가지 고 있 음 을 나타 냅 니 다.Stub 는 추상 적 인 유형 으로 구체 적 인 IInterface 와 관련 된 실현 은 개발 자가 스스로 실현 해 야 한다.
  • IInterface:IInterface 는 서버 프로 세 스 대상 이 어떤 능력 을 가지 고 있 는 지(어떤 방법 을 제공 할 수 있 는 지,사실은 AIDL 파일 에서 정 의 된 인터페이스)
  • 를 대표 합 니 다.
  • proxy:Stub 의 정적 내부 클래스 는 IMyAidlInterface 인 터 페 이 스 를 실현 하기 때문에 그 는 원 격 에이전트 대상 으로 클 라 이언 트 에 게 되 돌아 갈 수 있 습 니 다.client 가 proxy 의 특정한 방법 을 호출 할 때 파 라 메 터 를 proxy 에 전달 합 니 다.원 격 실제 대상 을 통 해 방법 이름과 파라미터 등 을 원 격 실제 대상 에 게 전달 한 다음 에 onTransact 를 되 돌려 주 고 해당 하 는 방법 이 호출 되 어 크로스 프로 세 스 호출 을 실현 합 니 다.
  • 4.복잡 한 데이터 전송
    복잡 한 데 이 터 를 전달 해 야 한다 면 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);
    
        }
    
        /**
         *      Parcel,          
         *
         * @param dest
         */
        public void readFromParcel(Parcel dest) {
            //  ,           writeToParcel()      
            content = dest.readString();
    
        }
    
        //      
        @Override
        public String toString() {
            return "content : " + content;
        }
    }
    이 동시에 info.aidl 파일 을 만들어 데이터 도 전달 할 수 있 음 을 나타 낸다.
    
    package com.viii.aidlclient;
    
    //  :Info.Info.java         
    
    //                   Info     AIDL    
    
    //  parcelable   
    parcelable Info;
    이렇게 하면 info 대상 을 사용 할 수 있 습 니 다.앞의 기본 형식 변수 에 의 해 제어 되 지 않 습 니 다.
    5.서비스 구축
    이 어 새로운 Service 는 메 시 지 를 받 고 AndroidManifest.xml 에 서 비 스 를 등록 합 니 다.
    
    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: ");     //      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);
        }
    
      //           ,    stub,        ,     
        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 {
          //       
            }
        };
    
    }
    이 럴 때 basic Types 방법 으로 구체 적 인 함수 코드 를 추가 하여 원 하 는 기능 을 실현 할 수 있 습 니 다.
    로 컬 에서 프 록 시 를 가 져 온 후에 basic Types 를 호출 하면 서버 호출 이 실 행 됩 니 다.
    6.서비스 획득
    이어서 mainactivity 에서 연결 합 니 다.
    
    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) {       //            ,          service      。
                mService = IMyAidlInterface.Stub.asInterface((IBinder) service);
                mIsBound = true;
                try {
                    //      
                    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: ");
            }
        }
    
        /**
         *   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();
        }
    }
    원 격 서비스의 binder 를 받 은 후에 우 리 는 관련 방법 으로 자신의 기능 을 실현 할 수 있 습 니 다.
    여기까지 AIDL 하나 가 우리 에 게 이 루어 졌 다.
    7.호출 과정 분석
    asInterface 방법 을 보 세 요.저 희 는 bid 하나의 Service 를 받 은 후에 onServiceConnection 의 리 셋 에서 이 방법 을 통 해 원 격 서 비 스 를 받 았 습 니 다.이 방법 은 무엇 을 했 습 니까?
    
    /**
        * 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);
    }
    먼저 함수 의 인자IBinder유형의 obj 를 보십시오.이 대상 은 우리 에 게 구동 되 는 것 입 니 다.Binder 로 컬 대상 이 라면 Binder 유형 입 니 다.Binder 대리 대상 이 라면BinderProxy유형 입 니 다.Binder 로 컬 대상 을 찾 아 보 겠 습 니 다.찾 으 면 Client 와 Server 가 같은 프로 세 스 에 있 음 을 설명 합 니 다.이 매개 변 수 는 로 컬 대상 이 고 형식 변환 을 직접 강제 한 다음 에 돌아 갑 니 다.
    찾 을 수 없다 면 원 격 대상(다른 프로 세 스 에 있 음)임 을 설명 합 니 다.원 격 대상 에 대한 접근 을 위해 서 는 Binder 프 록 시 대상 을 만들어 야 합 니 다.일반적으로 원 격 서비스 대상 과 통신 을 한다 면 여기 서 돌아 오 는 것 은 반드시 Binder 대리 대상 입 니 다.이 IBinder 매개 변 수 는 실제 적 으로 BinderProxy 입 니 다.
    에 이 드 의 basic Types 방법 에 대한 우리 의 실현 을 살 펴 보 자.Stub 류 에서 basic Types 는 추상 적 인 방법 으로 우 리 는 이 유형 을 계승 하여 실현 해 야 한다.클 라 이언 트 와 서버 가 같은 프로 세 스에 있다 면 이 방법 을 직접 호출 하 는 것 입 니 다.그렇다면 원 격 호출 이 라면 그 사이 에 무슨 일이 일 어 났 을 까?Client 는 어떻게 서버 로 호출 합 니까?
    원 격 방법 에 대한 호출 은 Binder 대 리 를 통 해 이 루어 졌 습 니 다.이 예 에서Proxy클래스 입 니 다.Proxybasic Types 방법 에 대한 실현 은 다음 과 같다.
    
    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);
                //      ,           
            mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
            _reply.readException();
        } finally {
            _reply.recycle();
            _data.recycle();
        }
    }
    그것 은 먼저 Parcel 로 데 이 터 를 서열 화한 다음 에 transact 방법 을 호출 했다.이 transact 는 도대체 무엇 을 했 습 니까?이 프 록 시 클래스 는 asInterface 방법 에서 생 성 되 었 습 니 다.앞에서 언급 한 바 와 같이 Binder 에이전트 라면 드라이브 가 되 돌아 오 는 IBinder 가 실제 BinderProxy 라 는 것 을 설명 합 니 다.따라서 우리 프 록 시 클래스 의 mRemote 실제 유형 은 BinderProxy 여야 합 니 다.Binder Proxy 의 transact 방법 을 봅 시다.(Binder.java 의 내부 클래스)
    
    public native boolean transact(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException;
    이것 은 현지 방법 이다.그것 의 실현 은 native 층 에 있 습 니 다.구체 적 으로 프레임 워 크/base/core/jni/androidutil_Binder.cpp 파일 에서 일련의 함수 호출 이 진행 되 었 습 니 다.호출 체인 이 너무 길 어서 여기 서 제시 하지 않 습 니 다.알 아야 할 것 은 토 크 위 드 드라이버 함수 로 최종 호출 되 었 습 니 다.이 함수 의 이름 을 보면 통신 과정 은 구동 에 맡 겨 야 한 다 는 것 을 알 수 있다.이 함 수 는 마지막 으로 ioctl 시스템 을 통 해 호출 되 었 습 니 다.Client 프로 세 스 는 커 널 상태 에 빠 졌 습 니 다.Client 는 basicTypes 방법의 스 레 드 를 걸 어 되 돌아 오 기 를 기다 리 고 있 습 니 다.일련의 작업 이 끝 난 후에 서버 프로 세 스 를 깨 우 고 서버 프로 세 스 로 컬 대상 의 onTransact 함 수 를 호출 했 습 니 다.Binder 로 컬 대상 의 onTransact 방법 을 다시 봅 니 다.
    
    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);
    }
    서버 프로 세 스에 서 onTransact 는 호출 번호(AIDL 함수 마다 하나의 번호 가 있 습 니 다.프로 세 스 를 뛰 어 넘 을 때 함 수 를 전달 하지 않 고 전달 번호 에 따라 어떤 함 수 를 호출 하 는 지 알려 줍 니 다)에 따라 관련 함 수 를 호출 합 니 다.
    이 예 에서 Binder 로 컬 대상 의 basic Types 방법 을 호출 하 였 습 니 다.이 방법 은 결 과 를 드라이버 에 되 돌려 주 고 걸 려 있 는 Client 프로 세 스 의 스 레 드 를 깨 우 고 결 과 를 되 돌려 줍 니 다.그래서 크로스 프로 세 스 호출 이 완료 되 었 습 니 다.
    이로써 AIDL 이라는 통신 방식 의 각 유형 과 각 역할 에 대해 어느 정도 알 게 되 었 을 것 이다.이것 은 항상 고정된 모델 입 니 다.크로스 프로 세 스 전달 이 필요 한 대상 은 반드시 IBinder 에서 계승 합 니 다.만약 에 Binder 로 컬 대상 이 라면 반드시 Binder 를 계승 하여 IInterface 를 실현 합 니 다.만약 에 대리 대상 이 라면 IInterface 를 실현 하고 IBinder 참조 가 있 습 니 다.
    프 록 시 와 스 텁 는 다르다.이들 은 모두 Binder 이자 IInterface 이지 만 스 텁 는 계승(is 관계),프 록 시 는 조합(has 관계)을 사용한다.그들 은 모두 모든 IInterface 함 수 를 실현 했다.
    다른 것 은 Stub 가 정책 모드 를 사용 하여 가상 함수(하위 클래스 구현 대기)를 호출 하고 Proxy 는 조합 모드 를 사용 합 니 다.왜 Stub 는 계승 을 사용 하고 Proxy 는 조합 을 사용 합 니까?사실 Stub 자 체 는 IBinder(Binder)입 니 다.그 자체 가 프로 세 스 경 계 를 넘 어 전송 할 수 있 는 대상 이기 때문에 IBinder 를 계승 하여 transact 라 는 함 수 를 실현 하여 프로 세 스 를 뛰 어 넘 는 능력 을 가 져 야 합 니 다(이 능력 은 구동 에 의 해 부 여 됩 니 다).
    프 록 시 클래스 가 조합 을 사용 하 는 이 유 는 자신 이 무엇 인지 에 관심 이 없고 프로 세 스 전송 을 뛰 어 넘 을 필요 가 없 기 때 문 입 니 다.이 능력 만 가지 면 됩 니 다.이 능력 을 가지 기 위해 서 는 IBinder 에 대한 인용 만 유지 해 야 합 니 다.
    이상 은 안 드 로 이 드 AIDL 의 인 스 턴 스 와 원 리 를 분석 하 는 상세 한 내용 입 니 다.안 드 로 이 드 AIDL 에 관 한 자 료 는 다른 관련 글 을 주목 하 세 요!

    좋은 웹페이지 즐겨찾기