AIDL源码分析

前言

本文是本人研究AIDL时候的笔记,包含很多UML图和截图,内容仓促且不包含驱动层分析,如下文有错漏还请指出(容我精通Linux和C++后杀入,很可惜现在太菜)

服务端

  • 首先写一个AIDL文件 如下:
// IMyAidlInterface.aidl
package com.fmy.changevoice.aidl_resource;



interface IMyAidlInterface {

    void test1(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

                String hello( String aString);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 在编译后生成一个java文件(as位于build/generated/source/aidl/debug),文件内容如下:

package com.fmy.changevoice.aidl_resource;

public interface IMyAidlInterface extends android.os.IInterface {

    public static abstract class Stub extends android.os.Binder implements com.fmy.changevoice.aidl_resource.IMyAidlInterface {
        private static final java.lang.String DESCRIPTOR = "com.fmy.changevoice.aidl_resource.IMyAidlInterface";


        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }


        public static com.fmy.changevoice.aidl_resource.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.fmy.changevoice.aidl_resource.IMyAidlInterface))) {
                return ((com.fmy.changevoice.aidl_resource.IMyAidlInterface) iin);
            }
            return new com.fmy.changevoice.aidl_resource.IMyAidlInterface.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_test1: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.test1(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_hello: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = this.hello(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }

        private static class Proxy implements com.fmy.changevoice.aidl_resource.IMyAidlInterface {
            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;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public void test1(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) 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.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_test1, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public java.lang.String hello(java.lang.String aString) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.lang.String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }

        static final int TRANSACTION_test1 = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    }

    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    public void test1(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;

    public java.lang.String hello(java.lang.String aString) throws android.os.RemoteException;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 先看一下类图结构示例图:

这里写图片描述

  • 首先分析IMyAidlInterface这个类(内部类先不分析):
public interface IMyAidlInterface extends android.os.IInterface {
//内部类先不做分析
 public static abstract class Stub extends android.os.Binder implements com.fmy.changevoice.aidl_resource.IMyAidlInterface{...}
//声明接口方法
public void test1(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
//声明接口方法
    public java.lang.String hello(java.lang.String aString) throws android.os.RemoteException;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 我们看到IMyAidlInterface 还继承类一个接口IInterface ,我们再看看这个接口:
package android.os;

public interface IInterface
{


//检索与此接口相关联的Binder对象。您必须使用此代替普通转换,以便代理对象可以返回正确的结果。
    public IBinder asBinder();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 从描述可得治会在代理对象用使用使用此方法。然而IMyAidlInterface 没有实现此方法。我们继续看内部类Stub。
    这里写图片描述

  • 分析1:Stub是一个抽象类。继承Binder和实现IMyAidlInterface接口。
    但是从类图可以看到并没有实现我们IMyAidlInterface的方法(test1和hello方法)。

综上分析,我们服务实现接口的时候我们会继承IMyAidlInterface.Stub类。而不是直接IMyAidlInterface因为此接口还继承了IInterface接口 还必须实现其IBinder asBinder();方法。但是这个方法怎么实现返回我们却不知道。好在Stub实现除了我们自己定义接口方法之外IMyAidlInterface类的所有继承方法。

也就是说IMyAidlInterface我们定义了两个方法test1()和hello()没有被Stub实现,但是IMyAidlInterface其继承IInterface方法我们实现了。

所以我们写一个服务如下:

////MyService.java
package com.fmy.changevoice.aidl_resource;

public class MyService extends Service {



    @Override
    public IBinder onBind(Intent intent) {

        return new MyAidlInterface();
    }

    @Override
    public void onRebind(Intent intent) {
        super.onRebind(intent);
    }

    class MyAidlInterface extends IMyAidlInterface.Stub {



        @Override
        public void test1(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) throws RemoteException {

        }

        @Override
        public String hello(String aString) throws RemoteException {
            return null;
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 分析2: 我们再看一下我们Stub类实例化的过程.在上面的Myservice中我们在实例化内部类MyAidlInterface 的时候会调用父类无参构造方法。所以我们从Stub的构造方法开始看。
 private static final String DESCRIPTOR = "com.fmy.changevoice.aidl_resource.IMyAidlInterface";

        public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
  • 1
  • 2
  • 3
  • 4
  • 5

构造方法调用attachInterface传入this和一个描述。而attachInterface属于Binder方法
继续跟进

 //将特定接口与Binder关联的便捷方法。
 //调用后,将为您实现queryLocalInterface()
 //返回给定的所有者IInterface时相应的
 //描述符被请求。
    public void attachInterface(IInterface owner, String descriptor) {
        mOwner = owner;
        mDescriptor = descriptor;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

DESCRIPTOR 字符串就是一个id一样 用于确定一个接口对应的Binder对象。而Binder对象是IBinder子类用于内存共享实现进程通信.当我们使用IInterface接口的asBinder()方法时候会根据descriptor返回对应IBinder对象

既然上文提到了queryLocalInterface ()那么我们顺便看看这个方法。
这个方法在Binder实现继承自IBinder

//使用提供给attachInterface()的信息来返回
关联的IInterface。
 public IInterface queryLocalInterface(String descriptor) {
        if (mDescriptor.equals(descriptor)) {
            return mOwner;
        }
        return null;
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

mOwner对象是Binder属性对象,就是我们attachInterface()传入的。回过头来再看看我们怎么调用attachInterface()的传入实参

 public Stub() {
            this.attachInterface(this, DESCRIPTOR);
        }
  • 1
  • 2
  • 3

可见调用queryLocalInterface()方法后直接返回如果字符串匹配那么直接返回Stub对象

Stub父类的构造方法Binder如下

public Binder() {
        init();

        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Binder> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }
    }
  private native final void init();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

和可惜主要的init()方法是native方法,所以暂时到这


客户端

我们连接Myservice这个服务类代码如下

//MainActivity.java
package com.fmy.changevoice.aidl_resource;


public class MainActivity extends AppCompatActivity {

    private static final String TAG = "FMY";

    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "onStart: ");
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //连接核心代码
        Intent intent = new Intent(this, MyService.class);
        bindService(intent, new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.e(TAG, "onServiceConnected: ");
               //32行 
                IMyAidlInterface.Stub.asInterface(service);

               try {
                    //调用接口中的一个方法. //36行
                    String test = iMyAidlInterface.hello("test");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        }, BIND_AUTO_CREATE);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

我们来先分析一下32行代码:
我们看看调用Stub的方法asInterface

     /**
        将IBinder对象转换为com .fmy. changevoice.aidl_resource.IMyAidlInterface接口,在需要时生成代理。
         */
        public static com.fmy.changevoice.aidl_resource.IMyAidlInterface asInterface(android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }
            //30行
            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            if (((iin != null) && (iin instanceof com.fmy.changevoice.aidl_resource.IMyAidlInterface))) {
                return ((com.fmy.changevoice.aidl_resource.IMyAidlInterface) iin);
            }
            //34行
            return new com.fmy.changevoice.aidl_resource.IMyAidlInterface.Stub.Proxy(obj);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我们先分析30行

//30行
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
  • 1
  • 2

queryLocalInterface方法在前面我们大致介绍了下,用你传入的DESCRIPTOR检索接口和binder相关的接口实现。如果你的ServiceClient在一个同一个进程那么直接返回本地对象,不需要进程间通信。否则返回空

如果返回本地对象那么后面也没有什么介绍了,我们假设这里ServiceClient不在同一进程。

34行

  return new com.fmy.changevoice.aidl_resource.IMyAidlInterface.Stub.Proxy(obj);
  • 1

可以看到假设不在同进程的时候用Proxy类创建返回IMyAidlInterface接口的实现

我们来大致看看Proxy类

这里写图片描述

ProxyStub静态私有内部类代码如下

   private static class Proxy implements com.fmy.changevoice.aidl_resource.IMyAidlInterface {
            private android.os.IBinder mRemote;

            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }

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

            public String getInterfaceDescriptor() {
                return DESCRIPTOR;
            }

            /**
             * Demonstrates some basic types that you can use as parameters
             * and return values in AIDL.
             */
            @Override
            public void test1(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, String aString) 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.writeInt(anInt);
                    _data.writeLong(aLong);
                    _data.writeInt(((aBoolean) ? (1) : (0)));
                    _data.writeFloat(aFloat);
                    _data.writeDouble(aDouble);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_test1, _data, _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public String hello(String aString) throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                String _result;
                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    _data.writeString(aString);
                    mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
                    _reply.readException();
                    _result = _reply.readString();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
                return _result;
            }
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

我们先把精力放在Proxy构造方法上

  private static class Proxy implements com.fmy.changevoice.aidl_resource.IMyAidlInterface {
            private android.os.IBinder mRemote;
            //当Client和Service不在同进程的时候 传入Stub
            Proxy(android.os.IBinder remote) {
                mRemote = remote;
            }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

可见当ClientSerivice不在同进程的时候 ,Stub把自身传给Proxy构造对象 然后返回接口实例。
Stub因为继承自Binder可以把一些数据写入到共享内存中,所以保存此对象的一个引用。而proxy是我们接口的实现。

自此我们分析完成了
IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);这句代码

接下来我们看下用返回实例对象调用接口方法:

  Log.e(TAG, "onServiceConnected: ");
                //32
                IMyAidlInterface iMyAidlInterface = IMyAidlInterface.Stub.asInterface(service);

                try {
                    //调用接口中的一个方法. //36行
                    String test = iMyAidlInterface.hello("test");
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 36行分析开始:
  String test = iMyAidlInterface.hello("test");
  • 1

我们知道aidl连接对象当客户端服务端不在同一进程的时候 ,在客户端返回的接口实例是Stub内部类Proxy的实例。

所以上面的调用 hell(“test”);的源码我们直接从Proxyhell()开始看

hell() 是我们最开始定义的两个方法的其中一个,另外一个是test1()

Proxy hell方法

这里写图片描述

上图已给出行号

先解释一个类android.os.Parcel 这个类运行在内存中传递序列化后的数据。Parcelable这类相比大家都用过。Parcelable内部就是封装了Parcel 对象而已。

Serializable是java提供的序列化,Parcel是google提供。更轻量并且在内存传输胜过Serializable

122-123获取parcel池获取对象实例,

   android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
  • 1
  • 2

_data 用于写入数据,reply用于接受数据。

124行接收结果。因为我们hello()返回值是String所以他自然也是String。

写入token。DESCRIPTOR就是我们前面说过确定Binder和哪个接口关联的一个ID。这里很明显。你要告诉我你要写个哪个Binder我才能确定 传个哪个接口。

 _data.writeInterfaceToken(DESCRIPTOR);
  • 1

127行

//写入参数
 _data.writeString(aString);
  • 1
  • 2

128行 放入Stub对象transact方法中 然后写入共享内存

mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
  • 1

其中第一个参数 final的int值。是用于确定你调用哪个接口方法。每个定义接口方法都有一个对应的final值。其声明在Stub类中
本案例中
这里写图片描述

继续分析。。。。。。。
mRemote.transact()客户端的实现类是final class BinderProxy implements IBinder {。。。}
BinderProxyBinder 两个都是IBinder的实现类

public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
        Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
        if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
        return transactNative(code, data, reply, flags);
    }
  • 1
  • 2
  • 3
  • 4
  • 5

后面是JNI代码有兴趣的同学可以继续往下学习。
在这之后我们会回调到服务端的StubonTransact()方法

@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_test1: {
                    data.enforceInterface(DESCRIPTOR);
                    int _arg0;
                    _arg0 = data.readInt();
                    long _arg1;
                    _arg1 = data.readLong();
                    boolean _arg2;
                    _arg2 = (0 != data.readInt());
                    float _arg3;
                    _arg3 = data.readFloat();
                    double _arg4;
                    _arg4 = data.readDouble();
                    java.lang.String _arg5;
                    _arg5 = data.readString();
                    this.test1(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
                    reply.writeNoException();
                    return true;
                }
                case TRANSACTION_hello: {
                    data.enforceInterface(DESCRIPTOR);
                    java.lang.String _arg0;
                    _arg0 = data.readString();
                    java.lang.String _result = this.hello(_arg0);
                    reply.writeNoException();
                    reply.writeString(_result);
                    return true;
                }
            }
            return super.onTransact(code, data, reply, flags);
        }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37

上面的代码不需要介绍太多了相信代价都看得懂。

这里写图片描述
看完这些我们再来看看bindService的执行过程。这里我直接贴出时序图给大家看,不做过多介绍这里写图片描述

Activity的实现类为ContextImpl。你也许在继承类图看不到这个类的,但是你可以看到Activity的父类ContextWrapper的构造方法传入的一个对象实例是什么。
这里写图片描述

加入讨论

电子邮件地址不会被公开。 必填项已用*标注