我是靠谱客的博主 笨笨水壶,最近开发中收集的这篇文章主要介绍Android进程间通信 深入浅出AIDL(二),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

本篇文章为Android进程间通信 深入浅出AIDL系列的第二篇,建议配合AIDL第一篇食用

3. AIDL原理

3.1 AIDL是怎么工作的?

我们编写了aidl文件之后,啥也没干就自动拥有了跨进程通信的能力.这一切得归功于Android Studio根据aidl文件生成的IPersonManager.java文件(生成的这个文件通过双击Shift输入IPersonManager.java即可找到),它里面已经帮我们封装好了跨进程通信这块的逻辑(最终是通过Binder来完成的),所以这个IPersonManager.java文件最终会打包进apk里面,我们才得以方便地进行跨进程通信.

3.2 详细解读

先来简单看下IPersonManager.java的大致结构,为了更方便阅读,我将IPersonManager.aidl文件中多余的方法全部删除,只剩下List<Person> getPersonList();void addPersonIn(in Person person);:

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.xfhy.allinone.ipc.aidl;

public interface IPersonManager extends android.os.IInterface {
    /**
     * Default implementation for IPersonManager.
     */
    public static class Default implements com.xfhy.allinone.ipc.aidl.IPersonManager {
        @Override
        public java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException {
            return null;
        }

        @Override
        public void addPersonIn(com.xfhy.allinone.ipc.aidl.Person person) throws android.os.RemoteException {
        }

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

    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends android.os.Binder implements com.xfhy.allinone.ipc.aidl.IPersonManager {
        private static final java.lang.String DESCRIPTOR = "com.xfhy.allinone.ipc.aidl.IPersonManager";

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

        /**
         * Cast an IBinder object into an com.xfhy.allinone.ipc.aidl.IPersonManager interface,
         * generating a proxy if needed.
         */
        public static com.xfhy.allinone.ipc.aidl.IPersonManager asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.xfhy.allinone.ipc.aidl.IPersonManager))) {
                return ((com.xfhy.allinone.ipc.aidl.IPersonManager) iin);
            }
            return new com.xfhy.allinone.ipc.aidl.IPersonManager.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 {
            java.lang.String descriptor = DESCRIPTOR;
            switch (code) {
                case INTERFACE_TRANSACTION: {
                    reply.writeString(descriptor);
                    return true;
                }
                case TRANSACTION_getPersonList: {
                    data.enforceInterface(descriptor);
                    java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result = this.getPersonList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
                    return true;
                }
                case TRANSACTION_addPersonIn: {
                    data.enforceInterface(descriptor);
                    com.xfhy.allinone.ipc.aidl.Person _arg0;
                    if ((0 != data.readInt())) {
                        _arg0 = com.xfhy.allinone.ipc.aidl.Person.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    this.addPersonIn(_arg0);
                    reply.writeNoException();
                    return true;
                }
                default: {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }

        private static class Proxy implements com.xfhy.allinone.ipc.aidl.IPersonManager {
            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 java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        return getDefaultImpl().getPersonList();
                    }
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.xfhy.allinone.ipc.aidl.Person.CREATOR);
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }

            @Override
            public void addPersonIn(com.xfhy.allinone.ipc.aidl.Person person) 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 ((person != null)) {
                        _data.writeInt(1);
                        person.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    boolean _status = mRemote.transact(Stub.TRANSACTION_addPersonIn, _data, _reply, 0);
                    if (!_status && getDefaultImpl() != null) {
                        getDefaultImpl().addPersonIn(person);
                        return;
                    }
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            public static com.xfhy.allinone.ipc.aidl.IPersonManager sDefaultImpl;
        }

        static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_addPersonIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

        public static boolean setDefaultImpl(com.xfhy.allinone.ipc.aidl.IPersonManager impl) {
            // Only one user of this interface can use this function
            // at a time. This is a heuristic to detect if two different
            // users in the same process use this function.
            if (Stub.Proxy.sDefaultImpl != null) {
                throw new IllegalStateException("setDefaultImpl() called twice");
            }
            if (impl != null) {
                Stub.Proxy.sDefaultImpl = impl;
                return true;
            }
            return false;
        }

        public static com.xfhy.allinone.ipc.aidl.IPersonManager getDefaultImpl() {
            return Stub.Proxy.sDefaultImpl;
        }
    }

    public java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException;

    public void addPersonIn(com.xfhy.allinone.ipc.aidl.Person person) throws android.os.RemoteException;
}

这块代码看起来很长.咱依次来看,首先IPersonManager是一个接口,然后它继承自IInterface接口.IInterface接口是Binder接口的基类,要通过Binder传输的接口都必须继承自IInterface.它里面的方法就是我们在aidl文件中声明的2个方法.然后用2个整型的id用于标识在transact过程中客户端所请求的是哪个方法.IPersonManager.Stub继承自Binder并实现了IPersonManager接口.当客户端与服务端都位于同一个进程时,方法调用不会走跨进程的transact过程,而当两者位于不同进程时,方法调用需要走transact过程,这个逻辑是由Stub的内部代理Proxy完成的.

Default类就只是IPersonManager的默认实现,可以不用在意.

下面来单独分析一下Stub类

IPersonManager.Stub

public static abstract class Stub extends android.os.Binder implements com.xfhy.allinone.ipc.aidl.IPersonManager {
    private static final java.lang.String DESCRIPTOR = "com.xfhy.allinone.ipc.aidl.IPersonManager";

    /**
     * Construct the stub at attach it to the interface.
     */
    public Stub() {
        this.attachInterface(this, DESCRIPTOR);
    }
    
    /**
     * Cast an IBinder object into an com.xfhy.allinone.ipc.aidl.IPersonManager interface,
     * generating a proxy if needed.
     */
    public static com.xfhy.allinone.ipc.aidl.IPersonManager asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.xfhy.allinone.ipc.aidl.IPersonManager))) {
            return ((com.xfhy.allinone.ipc.aidl.IPersonManager) iin);
        }
        return new com.xfhy.allinone.ipc.aidl.IPersonManager.Stub.Proxy(obj);
    }
}
  • DESCRIPTOR是Binder的唯一标识,一般用当前Binder的类名表示.
  • attachInterface()是将Binder对象转成客户端需要的AIDL接口类型对象.如果需要跨进程,则还需要封装一个Stub.Proxy对象再返回;如果不需要跨进程,那么直接将Service端的Stub直接返回就行.

接着看Stub剩余的方法:

@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 {
    java.lang.String descriptor = DESCRIPTOR;
    switch (code) {
        case INTERFACE_TRANSACTION: {
            reply.writeString(descriptor);
            return true;
        }
        case TRANSACTION_getPersonList: {
            data.enforceInterface(descriptor);
            java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result = this.getPersonList();
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
        case TRANSACTION_addPersonIn: {
            data.enforceInterface(descriptor);
            //从data中序列化一个Person出来,然后调用addPersonIn()去添加这个Person
            com.xfhy.allinone.ipc.aidl.Person _arg0;
            if ((0 != data.readInt())) {
                _arg0 = com.xfhy.allinone.ipc.aidl.Person.CREATOR.createFromParcel(data);
            } else {
                _arg0 = null;
            }
            this.addPersonIn(_arg0);
            reply.writeNoException();
            return true;
        }
        default: {
            return super.onTransact(code, data, reply, flags);
        }
    }
}
  • asBinder()就是将当前的Binder对象返回
  • onTransact()方法是运行在服务端的线程池中的.这里看起来就像是同一个进程里面的调用一样,但其实已经涉及到跨进程通信了.当客户端跨进程请求服务端时,远程请求会通过系统底层封装后交由此方法来处理.服务端通过code来确定客户端请求的目标方法是什么,然后从data中取出目标方法所需的参数,然后执行目标方法.当目标方法执行完毕之后,向reply中写入返回值.

IPersonManager.Stub.Proxy

 private static class Proxy implements com.xfhy.allinone.ipc.aidl.IPersonManager {
    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;
    }
}

这里的mRemote是用于远程请求的Binder.如果需要跨进程,那么客户端就是通过这个Proxy代理来进行远程调用的.来看看调用方法具体是怎么实现的

static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_addPersonIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

@Override
public java.util.List<com.xfhy.allinone.ipc.aidl.Person> getPersonList() throws android.os.RemoteException {
    android.os.Parcel _data = android.os.Parcel.obtain();
    android.os.Parcel _reply = android.os.Parcel.obtain();
    java.util.List<com.xfhy.allinone.ipc.aidl.Person> _result;
    try {
        _data.writeInterfaceToken(DESCRIPTOR);
        boolean _status = mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
        if (!_status && getDefaultImpl() != null) {
            return getDefaultImpl().getPersonList();
        }
        _reply.readException();
        _result = _reply.createTypedArrayList(com.xfhy.allinone.ipc.aidl.Person.CREATOR);
    } finally {
        _reply.recycle();
        _data.recycle();
    }
    return _result;
}

@Override
public void addPersonIn(com.xfhy.allinone.ipc.aidl.Person person) 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 ((person != null)) {
            _data.writeInt(1);
            person.writeToParcel(_data, 0);
        } else {
            _data.writeInt(0);
        }
        boolean _status = mRemote.transact(Stub.TRANSACTION_addPersonIn, _data, _reply, 0);
        if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().addPersonIn(person);
            return;
        }
        _reply.readException();
    } finally {
        _reply.recycle();
        _data.recycle();
    }
}
  • 这2个方法都是运行在客户端的,当客户端调用此方法时: 首先创建该方法所需要的输入型Parcel对象_data,输出型Parcel对象_reply和返回值(如果有).然后将客户端方法的入参写入_data里面,通过序列化的方式.接着调用transact方法发起RPC远程调用,当前线程会被挂起,然后服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程才能继续执行.然后将方法的返回值写入到_reply中,也是通过序列化的方式,最后返回_reply中的数据.
  • Parcel对象是用来进行客户端与服务端进行数据传输的,只能传输可序列化的数据

应用层面的原理基本就这些了,如果再往里层探究的话,就会涉及到Binder机制里面比较底层的东西了.这里暂时不做分析.

下面这张图刚好总结上面的流程(来自Android开发艺术探索):

在这里插入图片描述

因为上面的IPersonManager.java文件是自动生成的,所以是很有规律的.即使我们不用AIDL也完全可以自定义Binder,从而实现跨进程通信.

资料

  • 文中代码仓库
  • Android 接口定义语言 (AIDL)
  • Android中AIDL的工作原理
  • 你真的理解AIDL中的in,out,inout么?
  • Android 深入浅出AIDL(一)
  • RemoteCallbackList
  • Android:学习AIDL,这一篇文章就够了(下)
  • Android开发艺术探索

最后

以上就是笨笨水壶为你收集整理的Android进程间通信 深入浅出AIDL(二)的全部内容,希望文章能够帮你解决Android进程间通信 深入浅出AIDL(二)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(40)

评论列表共有 0 条评论

立即
投稿
返回
顶部