进程通信之 AIDL 解析(二)

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中自定义的权限
       
       

     if(checkCallingOrSelfPermission("com.kx.studyview.aidl.permission.REMOTE_SERVICE_PERMISSION") == PackageManager.PERMISSION_DENIED) {
             return false;
      }

你可能感兴趣的:(进程通信之 AIDL 解析(二))