前言

使用AIDL接口可以使得我们在调用其他进程的对象的方法,像调用自己进程本地对象的方法一样简单。本文将从AIDL接口文件自动生成的java文件来分析调用过程,虽然分析可能不够底层,但一定能对理解AIDL起到帮助。

代码

AIDL文件如下(IListener的接口文件不重要,这里它是个空接口都可以)

package com.java.prac;
import com.java.prac.IListener;

interface IService {

    void registerListener(in IListener listener);

    void unregisterListener(in IListener listener);

    byte SerTestIn(in byte[] pa);

    byte SerTestOut(out byte[] pa);
    
    byte SerTestInout(inout byte[] pa);
}

对应自动生成的java文件放在后面了。

分析

首先对自动生成的java文件进行分析。不关注其内部类,单看IService接口的声明方法,它已经声明好了aidl文件里的5个方法。需要注意的是IService接口继承了IInterface接口。

IService interface

public interface IService extends android.os.IInterface
{
	//忽略内部类
    public void registerListener(com.java.prac.IListener listener) throws android.os.RemoteException;
    public void unregisterListener(com.java.prac.IListener listener) throws android.os.RemoteException;
    public byte SerTestIn(byte[] pa) throws android.os.RemoteException;
    public byte SerTestOut(byte[] pa) throws android.os.RemoteException;
    public byte SerTestInout(byte[] pa) throws android.os.RemoteException;
}

而IInterface接口的定义如下,IService接口并没有去实现asBinder方法,这说明实现asBinder的任务交给实现IService接口的派生类。这也暗示了asBinder方法在不同的派生类下有着不同的实现。

package android.os;
public interface IInterface
{
	public abstract android.os.IBinder asBinder();
}

其次,IService接口发现有两个内部类,一个是IService$Stub,一个是IService$Stub$Proxy,两个内部类都implement了IService接口。但很明显,一个是用来在service所处的进程中继承并实现AIDL接口的(这个才是真正的方法实现),另一个是用来作为cilent来访问调用远程进程的service的方法的。

IService$Stub内部类

/** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.java.prac.IService
    {
        private static final java.lang.String DESCRIPTOR = "com.java.prac.IService";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.java.prac.IService interface,
         * generating a proxy if needed.
         */
        public static com.java.prac.IService asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.java.prac.IService))) {
                return ((com.java.prac.IService)iin);
            }
            return new com.java.prac.IService.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 TRANSACTION_SerTestIn:
                {
                    data.enforceInterface(descriptor);
                    byte[] _arg0;
                    _arg0 = data.createByteArray();
                    byte _result = this.SerTestIn(_arg0);
                    reply.writeNoException();
                    reply.writeByte(_result);
                    return true;
                }
                //省略
			}
        }
        static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_SerTestIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_SerTestOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
        static final int TRANSACTION_SerTestInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
    }
  • stub类是一个抽象类,需要派生类才能生成对象。
  • 这个类同时继承Binder并实现了IService方法,意味着这个类可以在Binder和IService之间强制转换类型。
  • 从onTransact方法中可以看到,switch case的逻辑里是根据stub定义的常量来进入的,但是却没有找到谁调用了这个方法。
  • switch case的逻辑里,调用方法最终调用的是byte _result = this.SerTestIn(_arg0),这说明IService$Stub是用来在service所处的进程中继承并实现AIDL接口的。因为方法的真正实现在自己的派生类对象里,所以会调用this的方法。
  • asBinder方法里返回this,因为自己的派生类对象将会是真正的service实现,所以就可以理直气壮地返回自己了。
  • asInterface是一个static方法,是一个工具方法。这个方法根据IBinder参数来作判断。当返回return ((com.java.prac.IService)iin)时,说明IBinder参数是stub的派生类对象,Binder里对应的源码如下:
//frameworks/base/core/java/android/os/Binder.java
	//这个函数属于Binder类
    public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
        if (mDescriptor != null && mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }

但mOwner的定义为private IInterface mOwner;,它通过this.attachInterface(this, DESCRIPTOR);来赋值给mOwner。

//frameworks/base/core/java/android/os/Binder.java
	//这个函数属于Binder类
    public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }

这样,一个stub派生类对象几经转手,最后以IService引用而存在着。这样做的好处是只会暴露IService的方法给外部。

而当返回return new com.java.prac.IService.Stub.Proxy(obj);时,说明iin==null了,一般是这种情况。这说明传进来的IBinder参数其对应的类也实现了queryLocalInterface方法,但是却返回的是null。对应的源码如下(所以这种情况下的obj的实际类型为BinderProxy):

//frameworks/base/core/java/android/os/Binder.java
	//这个函数属于BinderProxy类
    public IInterface queryLocalInterface(String descriptor) {
        return null;
    }
  • 总结一下就是,当调用方和service实现方处于同一个进程时,会返回return ((com.java.prac.IService)iin);;当调用方和service实现方处于不同进程时,会返回return new com.java.prac.IService.Stub.Proxy(obj);。当然,这是因为asInterface方法传入参数的实际类型的不同导致的。

IService$Stub$Proxy内部类

private static class Proxy implements com.java.prac.IService
        {
            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 byte SerTestIn(byte[] pa) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeByteArray(pa);
                    mRemote.transact(Stub.TRANSACTION_SerTestIn, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readByte();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
		//省略
        }
  • proxy已经不是抽象类了,可以不需要派生类,就直接生成对象了。
  • 很明显,proxy的构造函数在stub里面的return new com.java.prac.IService.Stub.Proxy(obj);被调用到了。
  • 由于proxy对象是在远程调用方使用的,所以asBinder方法就应该返回这个IBinder类型的mRemote成员(实际类型为BinderProxy)。
  • 从switch case的逻辑看,调用mRemote.transact方法时的第一个参数,刚好可以被stub的switch逻辑用来处理各种case。transact的各个实参刚好和onTransact的形参对应上了。
  • mRemote.transact方法会调用到transactNative(code, data, reply, flags);即用JNI调用c++代码去,之后会通过系统调用进入内核空间(即用户态转到内核态),最后将服务实现方的线程唤醒,并调用相应函数。

系统图

自动生成Java代码框架 自动生成java类_java


从系统图中可以看出Android中设计模式的优良应用,IInterface接口中定义了一个方法asBinder可以返回IBinder类型,而IBinder接口中定义了一个queryLocalInterface方法可以返回IInterface类型。这两个方法刚好相反,使得IBinder类型和IInterface类型可以相互转换。

而为了可以相互转换,它们的派生类:Stub同时继承了IService和Binder;Proxy虽然只继承了IService,但拥有一个BinderProxy的成员。

自动生成的java代码

package com.java.prac;
public interface IService extends android.os.IInterface
{
    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.java.prac.IService
    {
        private static final java.lang.String DESCRIPTOR = "com.java.prac.IService";
        /** Construct the stub at attach it to the interface. */
        public Stub()
        {
            this.attachInterface(this, DESCRIPTOR);
        }
        /**
         * Cast an IBinder object into an com.java.prac.IService interface,
         * generating a proxy if needed.
         */
        public static com.java.prac.IService asInterface(android.os.IBinder obj)
        {
            if ((obj==null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin!=null)&&(iin instanceof com.java.prac.IService))) {
                return ((com.java.prac.IService)iin);
            }
            return new com.java.prac.IService.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_registerListener:
                {
                    data.enforceInterface(descriptor);
                    com.java.prac.IListener _arg0;
                    _arg0 = com.java.prac.IListener.Stub.asInterface(data.readStrongBinder());
                    this.registerListener(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_unregisterListener:
                {
                    data.enforceInterface(descriptor);
                    com.java.prac.IListener _arg0;
                    _arg0 = com.java.prac.IListener.Stub.asInterface(data.readStrongBinder());
                    this.unregisterListener(_arg0);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_SerTestIn:
                {
                    data.enforceInterface(descriptor);
                    byte[] _arg0;
                    _arg0 = data.createByteArray();
                    byte _result = this.SerTestIn(_arg0);
                    reply.writeNoException();
                    reply.writeByte(_result);
                    return true;
                }
                case TRANSACTION_SerTestOut:
                {
                    data.enforceInterface(descriptor);
                    byte[] _arg0;
                    int _arg0_length = data.readInt();
                    if ((_arg0_length<0)) {
                        _arg0 = null;
                    }
                    else {
                        _arg0 = new byte[_arg0_length];
                    }
                    byte _result = this.SerTestOut(_arg0);
                    reply.writeNoException();
                    reply.writeByte(_result);
                    reply.writeByteArray(_arg0);
                    return true;
                }
                case TRANSACTION_SerTestInout:
                {
                    data.enforceInterface(descriptor);
                    byte[] _arg0;
                    _arg0 = data.createByteArray();
                    byte _result = this.SerTestInout(_arg0);
                    reply.writeNoException();
                    reply.writeByte(_result);
                    reply.writeByteArray(_arg0);
                    return true;
                }
                default:
                {
                    return super.onTransact(code, data, reply, flags);
                }
            }
        }
        private static class Proxy implements com.java.prac.IService
        {
            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 registerListener(com.java.prac.IListener listener) 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((((listener!=null))?(listener.asBinder()):(null)));
                    mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
                    _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override public void unregisterListener(com.java.prac.IListener listener) 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((((listener!=null))?(listener.asBinder()):(null)));
                    mRemote.transact(Stub.TRANSACTION_unregisterListener, _data, _reply, 0);
                    _reply.readException();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override public byte SerTestIn(byte[] pa) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeByteArray(pa);
                    mRemote.transact(Stub.TRANSACTION_SerTestIn, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readByte();
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            @Override public byte SerTestOut(byte[] pa) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    if ((pa==null)) {
                        _data.writeInt(-1);
                    }
                    else {
                        _data.writeInt(pa.length);
                    }
                    mRemote.transact(Stub.TRANSACTION_SerTestOut, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readByte();
                    _reply.readByteArray(pa);
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
            @Override public byte SerTestInout(byte[] pa) throws android.os.RemoteException
            {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                byte _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeByteArray(pa);
                    mRemote.transact(Stub.TRANSACTION_SerTestInout, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readByte();
                    _reply.readByteArray(pa);
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
        static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_unregisterListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        static final int TRANSACTION_SerTestIn = (android.os.IBinder.FIRST_CALL_TRANSACTION + 2);
        static final int TRANSACTION_SerTestOut = (android.os.IBinder.FIRST_CALL_TRANSACTION + 3);
        static final int TRANSACTION_SerTestInout = (android.os.IBinder.FIRST_CALL_TRANSACTION + 4);
    }
    public void registerListener(com.java.prac.IListener listener) throws android.os.RemoteException;
    public void unregisterListener(com.java.prac.IListener listener) throws android.os.RemoteException;
    public byte SerTestIn(byte[] pa) throws android.os.RemoteException;
    public byte SerTestOut(byte[] pa) throws android.os.RemoteException;
    public byte SerTestInout(byte[] pa) throws android.os.RemoteException;
}