美文网首页
进程通信之 AIDL 解析(二)

进程通信之 AIDL 解析(二)

作者: Android小菜鳥 | 来源:发表于2018-08-12 10:21 被阅读0次

    1.AIDL的简介

    AIDL (Android Interface Definition Language) 是一种接口定义语言,用于生成可以在Android设备上两个进程之间进行进程间通信(Interprocess Communication, IPC)的代码。如果在一个进程中(例如Activity)要调用另一个进程中(例如Service)对象的操作,就可以使用AIDL生成可序列化的参数,来完成进程间通信。

    AIDL能够实现进程间通信,其内部是通过Binder机制来实现的

    AIDL支持的数据类型:

    • Java 编程语言中的所有基本数据类型(如 int、long、char、boolean 等等)
    • String和CharSequence
    • Parcelable:实现了Parcelable接口的对象
    • List:其中的元素需要被AIDL支持,另一端实际接收的具体类始终是
    • ArrayList,但生成的方法使用的是 List 接口
    • Map:其中的元素需要被AIDL支持,包括key和value,另一端实际接收的具体类始终 是 HashMap,但生成的方法使用的是 Map 接口

    其他注意事项:

    • 在AIDL中传递的对象,必须实现Parcelable序列化接口;
    • 在AIDL中传递的对象,需要在类文件相同路径下,创建同名、但是后缀为.aidl的文件,并在文件中使用parcelable关键字声明这个类;
    • 跟普通接口的区别:只能声明方法,不能声明变量;
    • 所有非基础数据类型参数都需要标出数据走向的方向标记。可以是 in、out 或 inout,基础数据类型默认只能是 in,不能是其他方向。

    2.AIDL的使用

    下面是项目的目录结构

    image
    其中在aidl文件下创建相同的包结构,在bean目录下创建和实体类一样的aidl文件,并用 parcelable关键字声明这个类
    package com.kx.studyview.aidl.bean;
    
    parcelable MessageModel ;
    
    MessageReceiver,用于实现服务端传递给客户端消息的监听,类似接口回调的方式。
    package com.kx.studyview.aidl;
    import com.kx.studyview.aidl.bean.MessageModel ;
    interface MessageReceiver {
      void onMessageReceived(in MessageModel receivedMessage);
    }
    
    MessageSender,主要用于实现客户端与服务端的交互
    // MessageSender.aidl
    package com.kx.studyview.aidl;
    import com.kx.studyview.aidl.bean.MessageModel ;
    import com.kx.studyview.aidl.MessageReceiver ;
    interface MessageSender {
      void sendMessage(in MessageModel messageModel);
      void registerReceiveListener(MessageReceiver messageReceiver);
      void unregisterReceiveListener(MessageReceiver messageReceiver);
    }
    
    

    在Build之后,系统会为我们生成MessageSender.java文件

    public interface MessageSender extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.kx.studyview.aidl.MessageSender {
           //  代表当前Binder的唯一标识,一般为完整路径
            private static final java.lang.String DESCRIPTOR = "com.kx.studyview.aidl.MessageSender";
    
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
           将服务端的Binder对象转换为客户端所需要的的AIDL接口类型对象,如果客户端和服务端位于同一进 
           程,则返回服务端的Stub对象本身,当两者处于不同进程时,返回的是系统封装后的Stub.proxy对象
            public static com.kx.studyview.aidl.MessageSender asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.kx.studyview.aidl.MessageSender))) {
                    return ((com.kx.studyview.aidl.MessageSender) iin);
                }
                return new com.kx.studyview.aidl.MessageSender.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_sendMessage: {
                        data.enforceInterface(DESCRIPTOR);
                        com.kx.studyview.aidl.bean.MessageModel _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = com.kx.studyview.aidl.bean.MessageModel.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        this.sendMessage(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_registerReceiveListener: {
                        data.enforceInterface(DESCRIPTOR);
                        com.kx.studyview.aidl.MessageReceiver _arg0;
                        _arg0 = com.kx.studyview.aidl.MessageReceiver.Stub.asInterface(data.readStrongBinder());
                        this.registerReceiveListener(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_unregisterReceiveListener: {
                        data.enforceInterface(DESCRIPTOR);
                        com.kx.studyview.aidl.MessageReceiver _arg0;
                        _arg0 = com.kx.studyview.aidl.MessageReceiver.Stub.asInterface(data.readStrongBinder());
                        this.unregisterReceiveListener(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            不在一个进程时返回的代理
            private static class Proxy implements com.kx.studyview.aidl.MessageSender {
                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 sendMessage(com.kx.studyview.aidl.bean.MessageModel messageModel) 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 ((messageModel != null)) {
                            _data.writeInt(1);
                            messageModel.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public void registerReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) 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.writeStrongBinder((((messageReceiver != null)) ? (messageReceiver.asBinder()) : (null)));
                        mRemote.transact(Stub.TRANSACTION_registerReceiveListener, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public void unregisterReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) 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.writeStrongBinder((((messageReceiver != null)) ? (messageReceiver.asBinder()) : (null)));
                        mRemote.transact(Stub.TRANSACTION_unregisterReceiveListener, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
            用于区分不同方法名的 code
            static final int TRANSACTION_sendMessage = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_registerReceiveListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
            static final int TRANSACTION_unregisterReceiveListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        }
    
        public void sendMessage(com.kx.studyview.aidl.bean.MessageModel messageModel) throws android.os.RemoteException;
    
        public void registerReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) throws android.os.RemoteException;
    
        public void unregisterReceiveListener(com.kx.studyview.aidl.MessageReceiver messageReceiver) throws android.os.RemoteException;
    }
    
    
    其中Stub 的 onTransact() 运行在服务端的Binder线程池中,当客户端发起请求时,服务端根据code可以确定客户端所请求的目标方法时什么。

    Proxy#sendMessage

            @Override
              public void sendMessage(com.kx.studyview.aidl.bean.MessageModel messageModel) 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 ((messageModel != null)) {
                            _data.writeInt(1);
                            messageModel.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
    首先创建此方法的所需的输入型对象_data 和输出型对象_reply,然后将messageModel信息序列化写入_data中(如果messageModel不为空), _data.writeInt(1)和_data.writeInt(0)用于在Stub 的 onTransact()方法中判断是否进行反序列化。接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起。
        mRemote.transact(Stub.TRANSACTION_sendMessage, _data, _reply, 0);
    
    然后服务端的onTransact方法会被调用。根据不同的code区分不同的方法,
                 case TRANSACTION_sendMessage: {
                       data.enforceInterface(DESCRIPTOR);
                       com.kx.studyview.aidl.bean.MessageModel _arg0;
                       if ((0 != data.readInt())) {
                           _arg0 = com.kx.studyview.aidl.bean.MessageModel.CREATOR.createFromParcel(data);
                       } else {
                           _arg0 = null;
                       }
                       this.sendMessage(_arg0);
                       reply.writeNoException();
                       return true;
                   }
    
    当 data.writeInt(1)时,进行反序列化操作,生成与客户端发送消息内容一样的对象(不同的对象,内容一样),data.writeInt(0)时,返回空,代表客户端发送的是null。
     _arg0 = com.kx.studyview.aidl.bean.MessageModel.CREATOR.createFromParcel(data);
    
    反序列化完成后,调用sendMessage方法,这个方法的实现是在服务端
    this.sendMessage(_arg0);
    
    在定义接口方法时,主要的执行过程都是一样的,只不过区别在于定义的方法是否有返回值,是否有参数之分。当有返回值的时候,就会向onTransact参数中的reply对象写入返回值。有参数的时候,就会从data中的取出目标所需的参数。
      void sendMessage(in MessageModel messageModel);
      void registerReceiveListener(MessageReceiver messageReceiver);
      void unregisterReceiveListener(MessageReceiver messageReceiver);
    

    如果onTransact方法返回false,则客户端的请求就会失败,我们可以利用这个特性来做权限验证,因为我们也不希望随便一个进程都能远程调用我们的服务。

    包名验证

                 /**
                 * 包名验证方式
                 */
                String packageName = null;
                String[] packages = getPackageManager().getPackagesForUid(getCallingUid());
                if (packages != null && packages.length > 0) {
                    packageName = packages[0];
                }
                if (packageName == null || !packageName.startsWith("com.kx.studyview.aidl")) {
                    LogUtils.e("MessageService 进程onTransact  "  + "拒绝调用:" + packageName);
                    return false;
                }
    

    权限验证

           //  在AndroidManifest中自定义的权限
           <permission
            android:name="com.kx.studyview.aidl.permission.REMOTE_SERVICE_PERMISSION"
            android:protectionLevel="normal" />
           <uses-permission android:name="com.kx.studyview.aidl.permission.REMOTE_SERVICE_PERMISSION" />
    
         if(checkCallingOrSelfPermission("com.kx.studyview.aidl.permission.REMOTE_SERVICE_PERMISSION") == PackageManager.PERMISSION_DENIED) {
                 return false;
          }
    

    相关文章

      网友评论

          本文标题:进程通信之 AIDL 解析(二)

          本文链接:https://www.haomeiwen.com/subject/dafsbftx.html