AIDL生成文件的解析

AIDL生成Java文件的解析

上一篇说了kotlin如何使用AIDL进行跨进程通信,这篇文章是对上一篇文章的补充和深入,主要研究依赖AIDL生成的Java文件写了什么。

先附上之前的实体类文件

Person

package com.example.com.testapplication.bean.kotlin

import android.annotation.SuppressLint
import android.os.Parcelable
import kotlinx.android.parcel.Parcelize

@Parcelize
@SuppressLint("ParcelCreator")
class Person(var name: String) : Parcelable {

    override fun toString(): String {
        return " [Person name = " + name + " ]"
    }
}

整理之后的Java生成文件

package com.example.com.testapplication.aidl;

import android.os.Binder;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.example.com.testapplication.bean.kotlin.Person;

import java.util.List;

public interface IMyAidl extends IInterface {

    void addPerson(com.example.com.testapplication.bean.kotlin.Person person) throws android.os.RemoteException;

	java.util.List<com.example.com.testapplication.bean.kotlin.Person> getPersonList() throws android.os.RemoteException;

    /**
     * Local-side IPC implementation stub class.
     */
    public static abstract class Stub extends Binder implements IMyAidl {
        private static final String DESCRIPTOR = "com.example.com.testapplication.IMyAidl";
        static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

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

        /**
         * Cast an IBinder object into an com.example.com.testapplication.IMyAidl interface,
       	 * generating a proxy if needed.
         */
        public static com.example.com.testapplication.aidl.IMyAidl asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.example.com.testapplication.aidl.IMyAidl))) {
                return ((com.example.com.testapplication.aidl.IMyAidl) iin);
            }
            return new com.example.com.testapplication.aidl.IMyAidl.Stub.Proxy(obj);
        }

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

        /**
         * 返回true则代表访问成功,返回失败则代表访问失败
         *
         * @param code
         * @param data
         * @param reply
         * @param flags
         * @return
         * @throws RemoteException
         */
        @Override
        protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
            switch (code) {
                case INTERFACE_TRANSACTION:
                    reply.writeString(DESCRIPTOR);
                    return true;
                case TRANSACTION_addPerson:
                    data.enforceInterface(DESCRIPTOR);
                    Person arg0;
                    if (0 != data.readInt()) {
                        arg0 = (Person) Person.CREATOR.createFromParcel(data);
                    } else {
                        arg0 = null;
                    }
                    this.addPerson(arg0);
                    reply.writeNoException();
                    return true;
                case TRANSACTION_getPersonList:
                    data.enforceInterface(DESCRIPTOR);
                    List<Person> result = getPersonList();
                    reply.writeNoException();
                    reply.writeTypedList(result);
                    return true;
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements IMyAidl {
            private IBinder mRemote;

            public Proxy(IBinder mRemote) {
                this.mRemote = mRemote;
            }

            @Override
            public IBinder asBinder() {
                return mRemote;
            }

            public String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            @Override
            public void addPerson(Person person) throws RemoteException {
                Parcel data = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                try {
                    data.writeInterfaceToken(DESCRIPTOR);
                    if (null != person) {
                        data.writeInt(1);
                        person.writeToParcel(data, 0);
                    } else {
                        data.writeInt(0);
                    }
                    mRemote.transact(TRANSACTION_addPerson, data, reply, 0);
                    reply.readException();
                } finally {
                    data.recycle();
                    reply.recycle();
                }
            }

            @Override
            public List<Person> getPersonList() throws RemoteException {
                Parcel data = Parcel.obtain();
                Parcel reply = Parcel.obtain();
                List<Person> result;
                try {
                    data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(TRANSACTION_getPersonList, data, reply, 0);
                    reply.readException();
                    result = reply.createTypedArrayList(Person.CREATOR);
                } finally {
                    data.recycle();
                    reply.recycle();
                }
                return result;
            }
        }

    }
}

上面是经过整理的生成的Java文件,看上面的代码其实还不够简洁,咱们来拆分一下,上面的文件中有三个类,IMyAidl、Stub、Proxy,我们将这三个类分别写入一个单独的文件。

IMyAidl

package com.example.com.testapplication.aidl;

import android.os.IInterface;

public interface IMyAidl extends IInterface {

    void addPerson(com.example.com.testapplication.bean.kotlin.Person person) throws android.os.RemoteException;

	java.util.List<com.example.com.testapplication.bean.kotlin.Person> getPersonList() throws android.os.RemoteException;

}

Stub

package com.example.com.testapplication.aidl;

import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.example.com.testapplication.bean.kotlin.Person;

import java.util.List;

/**
 * Local-side IPC implementation stub class.
 */
public abstract class Stub extends Binder implements IMyAidl {
    static final String DESCRIPTOR = "com.example.com.testapplication.IMyAidl";
    static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);

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

    /**
     * Cast an IBinder object into an com.example.com.testapplication.IMyAidl interface,
     * generating a proxy if needed.
     */
    public static com.example.com.testapplication.aidl.IMyAidl asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof com.example.com.testapplication.aidl.IMyAidl))) {
            return ((com.example.com.testapplication.aidl.IMyAidl) iin);
        }
        return new Proxy(obj);
    }

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

    /**
     * 返回true则代表访问成功,返回失败则代表访问失败
     *
     * @param code
     * @param data
     * @param reply
     * @param flags
     * @return
     * @throws RemoteException
     */
    @Override
    protected boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {
        switch (code) {
            case INTERFACE_TRANSACTION:
                reply.writeString(DESCRIPTOR);
                return true;
            case TRANSACTION_addPerson:
                data.enforceInterface(DESCRIPTOR);
                Person arg0;
                if (0 != data.readInt()) {
                    arg0 = (Person) Person.CREATOR.createFromParcel(data);
                } else {
                    arg0 = null;
                }
                this.addPerson(arg0);
                reply.writeNoException();
                return true;
            case TRANSACTION_getPersonList:
                data.enforceInterface(DESCRIPTOR);
                List<Person> result = getPersonList();
                reply.writeNoException();
                reply.writeTypedList(result);
                return true;
        }
        return super.onTransact(code, data, reply, flags);
    }

}

Proxy

package com.example.com.testapplication.aidl;

import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;

import com.example.com.testapplication.bean.kotlin.Person;

import java.util.List;

import static com.example.com.testapplication.aidl.Stub.DESCRIPTOR;
import static com.example.com.testapplication.aidl.Stub.TRANSACTION_addPerson;
import static com.example.com.testapplication.aidl.Stub.TRANSACTION_getPersonList;

public class Proxy implements IMyAidl {
    private IBinder mRemote;

    public Proxy(IBinder mRemote) {
        this.mRemote = mRemote;
    }

    @Override
    public IBinder asBinder() {
        return mRemote;
    }

    public String getInterfaceDescriptor() {
        return DESCRIPTOR;
    }

    @Override
    public void addPerson(Person person) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            if (null != person) {
                data.writeInt(1);
                person.writeToParcel(data, 0);
            } else {
                data.writeInt(0);
            }
            mRemote.transact(TRANSACTION_addPerson, data, reply, 0);
            reply.readException();
        } finally {
            data.recycle();
            reply.recycle();
        }
    }

    @Override
    public List<Person> getPersonList() throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        List<Person> result;
        try {
            data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(TRANSACTION_getPersonList, data, reply, 0);
            reply.readException();
            result = reply.createTypedArrayList(Person.CREATOR);
        } finally {
            data.recycle();
            reply.recycle();
        }
        return result;
    }
}

通过上面拆分出来的三个类我们能看明白,定义了一个拥有Person类中方法名一样的接口类IMyAidl,一个继承Binder实现了IMyAidl接口的抽象类Stub,一个实现了IMyAidl接口的具体实现类Proxy。

IMyAidl继承IInterface接口,规范接口方法。

Stub这个类是重点,我们看到它继承Binder类就知道使用的是Binder机制。其中有下面几个方法

Stub()

构造方法,内部调用Binder的attachInterface(IInterface owner, String descriptor)方法将Stub当前类和描述写入Binder父类

asInterface(android.os.IBinder obj)

我们先来看一下这个方法的注释

/**
 * Cast an IBinder object into an com.example.com.testapplication.IMyAidl interface,
 * generating a proxy if needed.
 */

可以看到这个方法是将参数传进来的IBinder转成我们定义的接口类,如果需要的话创建代理类。那么什么是需要的时候通常来说非本应用访问就属于需要的时候。

这个类主要也是实现了注释所说的功能,第一步为空判断,判断传进来的参数是否为空不为空的话继续否则退出,第二步查询接口,通过构造方法中attachInterface传入的说明使用Binder的queryLocalInterface方法查询接口,第三步接口转换,查询接口不为空并且是定义的IMyAidl接口类的话就将查询到的接口强转成IMyAidl接口并返回,第四步启动代理,如果第三步判断没有通过则创建Proxy类启动代理模式。

其实呢,这个方法是AIDL为我们生成的,如果我们有其他操作,改变这个方法甚至不要这个方法也是没有问题的,具体的就看你的需求了。

asBinder()

这个方法是属于IInterface接口类的,IInterface接口类是使用Binder时必须要继承的类

我们同样先看一下注释

 /**
 * Retrieve the Binder object associated with this interface.
 * You must use this instead of a plain cast, so that proxy objects
 * can return the correct result.
 */

检索与此接口关联的绑定器对象。必须实现这个对象而不能强制转换,否则代理对象会出现返回对象不正确的情况。

注释写的云里雾里的,并没有说这个方法怎么用,只是说了必须用它。那么我们看一下这个方法的返回值,IBinder,对照上面的asInterface方法,我们可以知道asBinder方法是将实现了IInterface接口的类转成IBinder接口。

onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException

同样我们来看下注释

 /**
 * Default implementation is a stub that returns false.  You will want
 * to override this to do the appropriate unmarshalling of transactions.
 *
 * <p>If you want to call this, call transact().
 */

此方法默认返回false,如果你想实现自定义的逻辑需要重写这个方法进行事务处理,这个方法的触发需要调用transact()方法。也就是说这个方法是用来处理我们自定义的事务的,我们自定义的事务是什么,在此篇文章中就是IMyAidl接口的方法。

这个方法在同一进程内通信时不会执行,只有当不同进程间通信时才会执行。

Proxy

跟Stub实现的功能差不多,但是它是功能代理类,内部持有一个IBinder代理对象,asBinder方法返回的是持有的代理对象。

它拥有方法

Proxy(IBinder mRemote)

构造方法,参数为传入的IBinder对象。

asBinder()

返回持有的IBinder对象

getInterfaceDescriptor()

返回接口的说明

addPerson(Person person)

IMyAidl接口需要实现的方法,具体逻辑看编写,编写方法将在下篇文章进行讲解

getPersonList()

IMyAidl接口需要实现的方法,具体逻辑看编写,编写方法将在下篇文章进行讲解

至此,AIDL自动生成的Java文件中的三个类就已经分析完了,之后的文章将讲解Binder机制和Parcel

致敬源码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值