跳至主要內容

Android 中 AIDL 相关知识

JI,XIAOYONG...大约 3 分钟

前言

AIDL是 Android 中用于 IPC 的语言,具体使用可以参见这篇文章open in new window,这篇文章主要想总结一下AIDL具体为我们做了什么工作,主要参考书目《Android 开发艺术探索》。

在 Android 中,除了SocketIntent中使用Bundle、本地文件共享,ContentProvider等等之外,还有一个独有的 IPC 方式即Binder。在日常编程中使用Binder的主要有AIDLMessenger两种方式,而Messenger也是用AIDL来实现的。

准备

  1. 新建一个 AIDL 文件
// IBookManager.aidl
package cf.android666.myapplication;

interface IBookManager {

    void getSth();
}
  1. 用 AndroidStudio 自动生成一个 Binder 类

使用Build->Make Project,会在app/build/generated/aidl_source_output_dir/debug/compileDebugAidl/out目录下生成IBookManager.java

分析

AIDL 从客户端 (Client) 发起请求至服务端 (Server) 相应的工作流程概览,图片来源 (https://blog.csdn.net/qian520ao/article/details/78074983open in new window)

AIDL 从客户端 (Client) 发起请求至服务端 (Server) 的流程
AIDL 从客户端 (Client) 发起请求至服务端 (Server) 的流程

下面我们对IBookManager.java这个文件简单分析一下

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: app/src/main/aidl/cf/android666/myapplication/IBookManager.aidl
 */
package cf.android666.myapplication;

public interface IBookManager extends
  android.os.IInterface//IInterface 接口,所有可以在 Binder 中传输的接口都要继承自该接口
  {
    /**
     * Local-side IPC implementation stub class.
     * 持有 Binder 对象
     * 获取客户端传过来的数据,根据方法 ID 执行相应操作。
     * 将传过来的数据取出来,调用本地写好的对应方法。
     * 将需要回传的数据写入 reply 流,传回客户端。
     */
    public static abstract class Stub extends android.os.Binder implements cf.android666.myapplication.IBookManager {
        private static final java.lang.String DESCRIPTOR = "cf.android666.myapplication.IBookManager";//是 Binder 的唯一标识,一般为当前 Binder 的类目

        /**
         * Construct the stub at attach it to the interface.
         */
        public Stub() {
            this.attachInterface(this, DESCRIPTOR);//将 Binder 和指定的接口绑定,这样当 queryLocalInterface 时会返回与 DESCRIPTOR 一致的 IInterface
        }

        /**
         * Cast an IBinder object into an cf.android666.myapplication.IBookManager interface,
         * generating a proxy if needed.
         * 将服务端的 Binder 转化为客户端需要的 IInterface
         * 如果是相同的进程,则直接返回服务端的 Stub 对象本身(没有跨进程);
         * 如果是不同的进程,则返回的是 Stub.Proxy 代理类对象
         */
        public static cf.android666.myapplication.IBookManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof cf.android666.myapplication.IBookManager))) {
                return ((cf.android666.myapplication.IBookManager) iin);
            }
            return new cf.android666.myapplication.IBookManager.Stub.Proxy(obj);
        }

        @Override
        public android.os.IBinder asBinder() {
            return this;
        }

        /**
        * 客户端远程请求经过系统封装后调用该方法,
        * 生成 _data 和 _reply 数据流,并向 _data 中存入客户端的数据。
        * 通过 transact() 方法将它们传递给服务端,并请求服务端调用指定方法。
        * 接收 _reply 数据流,并从中取出服务端传回来的数据
        */
        @Override
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_getSth: {
                    data.enforceInterface(descriptor);//从 data 中可以读取参数
                    this.getSth();//注意,这里调用的是 IBookManager 的 getSth(),也就是需要我们在使用该 Binder 时实现的方法
                    reply.writeNoException();//可以往 reply 中写入结果
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        /**
        * Proxy 类持有 IBinder 的引用
        *
        */
        private static class Proxy implements cf.android666.myapplication.IBookManager {
            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 getSth() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_getSth, _data, _reply, 0);//这里实际上是调用了远程的 IBinder 的 transact() 方法
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }

        static final int TRANSACTION_getSth = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);//这个是我们在 AIDL 中定义的 getSth() 方法的标志,用于在 onTransact 中区分调用的是哪个方法
    }

    public void getSth() throws android.os.RemoteException;//这个是我们在 AIDL 中定义的方法,需要在服务端实现,并且会在客户端被调用
}

参考资料

Android 深入浅出 AIDL(二)open in new window

Android Binder 之应用层总结与分析open in new window

文章标题:《Android 中 AIDL 相关知识》
本文作者: JI,XIAOYONG
发布时间: 2019/03/20 19:37:40 UTC+8
更新时间: 2023/12/30 16:17:02 UTC+8
written by human, not by AI
本文地址: https://jixiaoyong.github.io/blog/posts/2270057c.html
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 许可协议。转载请注明出处!
你认为这篇文章怎么样?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
评论
  • 按正序
  • 按倒序
  • 按热度
Powered by Waline v2.15.8