AIDL自动生成源码分析以及根据自动生成的源码来自定义类实现IPC

来源:互联网 发布:js 字符串一行打印 编辑:程序博客网 时间:2024/06/07 20:51

前言

今天要写的就是AIDL的具体使用、AIDL自动生成源码分析以及根据自动生成的源码自定义类来实现IPC。这篇博客的着重点就在于源码分析和自定义类,至于使用过程中的细节并没有介绍。开始切入正题!

服务端进程使用

在服务端进程中我们定义AIDL文件,以学生类为例,我们对外接口就是IStudentManager.aidl文件,自定义类AIDL声明文件就是Student.aidl文件,对应我们实体类就是Student,三者代码如下:
Student.java:

package com.lgy.aidl.aidl;import android.os.Parcel;import android.os.Parcelable;public class Student implements Parcelable {    private String mNo;    private String mName;    private String mSex;    private String mTel;    private Student(Parcel in) {        mNo = in.readString();        mName = in.readString();        mSex = in.readString();        mTel = in.readString();    }    public static final Creator<Student> CREATOR = new Creator<Student>() {        @Override        public Student createFromParcel(Parcel in) {            return new Student(in);        }        @Override        public Student[] newArray(int size) {            return new Student[size];        }    };    @Override    public int describeContents() {        return 0;    }    @Override    public void writeToParcel(Parcel parcel, int i) {        parcel.writeString(mNo);        parcel.writeString(mName);        parcel.writeString(mSex);        parcel.writeString(mTel);    }    public String getmNo() {        return mNo;    }    public void setmNo(String mNo) {        this.mNo = mNo;    }    public String getmName() {        return mName;    }    public void setmName(String mName) {        this.mName = mName;    }    public String getmSex() {        return mSex;    }    public void setmSex(String mSex) {        this.mSex = mSex;    }    public String getmTel() {        return mTel;    }    public void setmTel(String mTel) {        this.mTel = mTel;    }}

Student.aidl:

// Student.aidlpackage com.lgy.aidl.aidl;import com.lgy.aidl.aidl.Student;parcelable Student;

IStudentManager.aidl:

// IStudentManager.aidlpackage com.lgy.aidl.aidl;import com.lgy.aidl.aidl.Student;interface IStudentManager {    List<Student>  getAllStudent();    void addStudent(in Student stu);}

此时我们程序的结构图:
这里写图片描述

我们在服务端进程中开启Service,在Service中返回给客户端进程IBinder对象,此时的IBinder对象就是我们刚刚IStudentManager.aidl文件生成源码中静态内部类Stub,客户端拿到服务端IBinder对象,就可以进行进程间的通信了。
Service代码:

package com.lgy.aidl;import android.app.Service;import android.content.Intent;import android.os.IBinder;import android.os.RemoteException;import android.util.Log;import com.lgy.aidl.aidl.IStudentManager;import com.lgy.aidl.aidl.Student;import java.util.ArrayList;import java.util.List;public class MyService extends Service {    private static final String TAG = "MyService";    private ArrayList<Student> mList = new ArrayList<>();    private IStudentManager.Stub mBinder = new IStudentManager.Stub() {        @Override        public List<Student> getAllStudent() throws RemoteException {            Log.i(TAG,"客户端调用getAllStudent方法执行,学生人数" + mList.size());            return mList;        }        @Override        public void addStudent(Student stu) throws RemoteException {            Log.i(TAG,"客户端调用addStudent方法执行之前学生人数" + mList.size());            mList.add(stu);            Log.i(TAG, "客户端调用addStudent方法执行之后学生人数" + mList.size());        }    };    public MyService() {    }    @Override    public void onCreate() {        super.onCreate();        Student stu1 = new Student("1","张三","男","13718447489");        Student stu2 = new Student("2","李四","男","13699485793");        Student stu3 = new Student("3","貂蝉","女","15896345892");        mList.add(stu1);        mList.add(stu2);        mList.add(stu3);        Log.i(TAG,"服务端Service启动!当前总共有" + mList.size() + "名学生");    }    @Override    public IBinder onBind(Intent intent) {        return mBinder;    }}

到此服务的进程代码编写完毕!

客户端进程使用

我们将服务端进程中所需要的AIDL文件和相关自定义的实体类,原封不动的移动到客户端进程程序中。我们在客户端进程中只需要绑定Service,获取拿到服务端的IBinder对象即可。

package com.lgy.aidl;import android.app.Activity;import android.content.ComponentName;import android.content.Intent;import android.content.ServiceConnection;import android.os.Bundle;import android.os.IBinder;import android.os.RemoteException;import android.support.v7.app.ActionBarActivity;import android.util.Log;import android.view.Menu;import android.view.MenuItem;import com.lgy.aidl.aidl.IStudentManager;import com.lgy.aidl.aidl.Student;import java.util.ArrayList;public class MainActivity extends Activity {    public static final String TAG = "MainActivity";    private IStudentManager mStudentManager;    private ArrayList<Student> mList ;    private ServiceConnection mConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            Log.i(TAG, "客户端进程连接成功");            mStudentManager = IStudentManager.Stub.asInterface(iBinder);            try {                mList = (ArrayList<Student>) mStudentManager.getAllStudent();                Log.i(TAG,"客户端进程连接成功之后,返回的学生人数" + mList.size());            } catch (RemoteException e) {                e.printStackTrace();            }            Student stu4 = new Student("4","Tom","男","15678958962");            Student stu5 = new Student("5","lily","女","18963526354");            try{                mStudentManager.addStudent(stu4);                mStudentManager.addStudent(stu5);            }catch (RemoteException e){                e.printStackTrace();            }            try {                mList = (ArrayList<Student>) mStudentManager.getAllStudent();                Log.i(TAG, "添加了2名学生后,返回的学生人数" + mList.size());            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName componentName) {        }    };    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Intent intent = new Intent(this,MyService.class);        bindService(intent,mConnection,BIND_AUTO_CREATE);    }    @Override    protected void onDestroy() {        unbindService(mConnection);        super.onDestroy();    }}

好了,到此客户端进程程序就写好,我们运行一下程序看看我们打印的log,和我们预想的是否一致。
这里写图片描述
这里写图片描述

AIDL生成代码分析

现在我们分析一下我们写的AIDL文件生成的Java类:

/* * This file is auto-generated.  DO NOT MODIFY. * Original file: E:\\sunshine\\lgy\\aidl\\app\\src\\main\\aidl\\com\\lgy\\aidl\\aidl\\IStudentManager.aidl */package com.lgy.aidl.aidl;public interface IStudentManager extends android.os.IInterface {    /**     * Local-side IPC implementation stub class.     */    public static abstract class Stub extends android.os.Binder implements com.lgy.aidl.aidl.IStudentManager {        private static final java.lang.String DESCRIPTOR = "com.lgy.aidl.aidl.IStudentManager";        /**         * Construct the stub at attach it to the interface.         */        public Stub() {            this.attachInterface(this, DESCRIPTOR);        }        /**         * Cast an IBinder object into an com.lgy.aidl.aidl.IStudentManager interface,         * generating a proxy if needed.         */        public static com.lgy.aidl.aidl.IStudentManager asInterface(android.os.IBinder obj) {            if ((obj == null)) {                return null;            }            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);            if (((iin != null) && (iin instanceof com.lgy.aidl.aidl.IStudentManager))) {                return ((com.lgy.aidl.aidl.IStudentManager) iin);            }            return new com.lgy.aidl.aidl.IStudentManager.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_getAllStudent: {                    data.enforceInterface(DESCRIPTOR);                    java.util.List<com.lgy.aidl.aidl.Student> _result = this.getAllStudent();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addStudent: {                    data.enforceInterface(DESCRIPTOR);                    com.lgy.aidl.aidl.Student _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.lgy.aidl.aidl.Student.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    this.addStudent(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }        private static class Proxy implements com.lgy.aidl.aidl.IStudentManager {            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.lgy.aidl.aidl.Student> getAllStudent() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.List<com.lgy.aidl.aidl.Student> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getAllStudent, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }            @Override            public void addStudent(com.lgy.aidl.aidl.Student stu) 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 ((stu != null)) {                        _data.writeInt(1);                        stu.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }        }        static final int TRANSACTION_getAllStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);        static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);    }    **public java.util.List<com.lgy.aidl.aidl.Student> getAllStudent() throws android.os.RemoteException;    public void addStudent(com.lgy.aidl.aidl.Student stu) throws android.os.RemoteException;**}

从上面自动生成的代码来看,IStudentManager.java类,其实就是一个接口interface、实现了IInterface接口,在里面有2个我们定义的方法getAllStudent和addStudent(代码中粗色部分)。在该接口中有一个静态内部类Stub 继承Binder类、实现了IStudentManager接口。
现在我们从哪里讲呢?我们在客户端进程的编写过程中,在绑定Service的时候,创建连接的时候,我们有这么一句:

mStudentManager = IStudentManager.Stub.asInterface(iBinder);

好了,我们看看这个静态内部类Stub的静态内部方法asInterface是如何实现的?

if ((obj == null)) {    return null;}android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);if (((iin != null) && (iin instanceof com.lgy.aidl.aidl.IStudentManager))) {    return ((com.lgy.aidl.aidl.IStudentManager) iin);}return new com.lgy.aidl.aidl.IStudentManager.Stub.Proxy(obj);

源码中首先判断参数IBinder是否为null, 接着调用Binder对象的queryLocalInterface方法,这个方法又是做什么的呢?
我们继续查看源代码:

/** * Use information supplied to attachInterface() to return the * associated IInterface if it matches the requested * descriptor. */public IInterface queryLocalInterface(String descriptor) {    if (mDescriptor.equals(descriptor)) {        return mOwner;    }    return null;}

从源代码中看很简单,判断descriptor字符串和自己内部的字符串相等还是不相等,返回的是一个mOwner对象,那么这个mOwner对象是IInterface接口,如下:

private int mObject;private IInterface mOwner;private String mDescriptor;

我们就要在去看源码中的构造函数Stub()如下:

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

继续看attachInterface方法如下:

    public void attachInterface(IInterface owner, String descriptor) {        mOwner = owner;        mDescriptor = descriptor;    }

看到这里我想我们应该知道queryLocalInterface的含义了?就是查找当前进程是否和服务端进程在同一个程序进程中,如果在同一个进程的话,那么就直接返回找到自身mOwner IInterface对象 如果不在同一个进程的话,就返回给null。那么最终会返回给我们一个Stub类中的静态代理类Proxy。 也就是说代理类Proxy才是真正的实现IPC的关键!。
好了,我知道了这个代理类Proxy,那么他又是如何实现的呢?
第一:代理类也实现了IStudentManager接口,所以他也会有2个方法去实现。
第二:代理类中的构造和私有函数传递的就是我们IStudentManager.Stub.asInterface(iBinder); IBinder对象。

我们看看两个方法的实现:

@Override            public java.util.List<com.lgy.aidl.aidl.Student> getAllStudent() throws android.os.RemoteException {                android.os.Parcel _data = android.os.Parcel.obtain();                android.os.Parcel _reply = android.os.Parcel.obtain();                java.util.List<com.lgy.aidl.aidl.Student> _result;                try {                    _data.writeInterfaceToken(DESCRIPTOR);                    mRemote.transact(Stub.TRANSACTION_getAllStudent, _data, _reply, 0);                    _reply.readException();                    _result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR);                } finally {                    _reply.recycle();                    _data.recycle();                }                return _result;            }
@Override            public void addStudent(com.lgy.aidl.aidl.Student stu) 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 ((stu != null)) {                        _data.writeInt(1);                        stu.writeToParcel(_data, 0);                    } else {                        _data.writeInt(0);                    }                    mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);                    _reply.readException();                } finally {                    _reply.recycle();                    _data.recycle();                }            }

在方法的源码实现中我们可以发现就是参数 是否回应,结果的返回都是序列化的Parcel。
在这2个方法中:
mRemote.transact(Stub.TRANSACTION_getAllStudent, _data, _reply, 0);
mRemote.transact(Stub.TRANSACTION_addStudent, _data, _reply, 0);
这2句才是真正的在多进程间数据通信。
在transact方法中:

/**     * Default implementation rewinds the parcels and calls onTransact.  On     * the remote side, transact calls into the binder to do the IPC.     */    public final boolean transact(int code, Parcel data, Parcel reply,            int flags) throws RemoteException {        if (false) Log.v("Binder", "Transact: " + code + " to " + this);        if (data != null) {            data.setDataPosition(0);        }        boolean r = onTransact(code, data, reply, flags);        if (reply != null) {            reply.setDataPosition(0);        }        return r;    }

调用onTransact方法此时调用的是服务端的onTransact方法,因Binder对象是服务端的对象:

@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_getAllStudent: {                    data.enforceInterface(DESCRIPTOR);                    java.util.List<com.lgy.aidl.aidl.Student> _result = this.getAllStudent();                    reply.writeNoException();                    reply.writeTypedList(_result);                    return true;                }                case TRANSACTION_addStudent: {                    data.enforceInterface(DESCRIPTOR);                    com.lgy.aidl.aidl.Student _arg0;                    if ((0 != data.readInt())) {                        _arg0 = com.lgy.aidl.aidl.Student.CREATOR.createFromParcel(data);                    } else {                        _arg0 = null;                    }                    this.addStudent(_arg0);                    reply.writeNoException();                    return true;                }            }            return super.onTransact(code, data, reply, flags);        }

从onTransact源码中我们可以看到参数,是否回应,结果都会作为参数传递过来,然后调用相对应的方法,将结果放回对应的参数中去,客户端进程在获取拿到对应的结果返回。

_reply.readException();_result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR);

从而整个过程也就完毕!(注意:客户端进程调用mRemote.transact方法和等待服务端onTransact结果 是同步的,也就是说在服务端进程不能做一些耗时的工作,否则客户端进程就会等待 从而可能会造成ANR现象)。

抛开AIDL,自定义代码实现

通过分析,我想我们应该已经有所认识了,那么我们不依靠AIDL文件生成对应的Java类的话,我们其实一样是可以实现IPC的通信。我做个实现步骤总结:

  1. 定义一个接口类A继承IInterface类,定义我们要实现的方法(按我们的例子就是要写2个方法)。
  2. 定义一个类B继承Binder类,实现刚刚定义的接口类A
  3. 定义我们B类的唯一标识DESCRIPTOR,构造函数实现
  4. 定义我们B类的asInterface静态方法
  5. 定义我们B类的静态内部类Proxy,实现接口类A
  6. 在我们定义B类中实现onTransact方法
    到此就是需要这6部就完成了自定义类似AIDLJava类文件。剩下的就是我们的使用。在使用的过程中和AIDL完全是一样的,只是这个时候需要用到的IStudentManager、Stub内部类,静态内部类Proxy都是我们自己定义的即可。
    看一看我按照以上6部写的类如下:
    IStudentManager:
package com.lgy.aidl;import android.os.IInterface;import android.os.RemoteException;import com.lgy.aidl.aidl.Student;import java.util.List;public interface IStudentManager extends IInterface{    public List<Student> getAllStudent() throws RemoteException;    public void addStudent(Student stu) throws RemoteException;}

IStudentStub:

package com.lgy.aidl;import android.os.Binder;import android.os.IBinder;import android.os.IInterface;import android.os.Parcel;import android.os.RemoteException;import com.lgy.aidl.aidl.*;import java.util.List;public class IStudentStub extends Binder implements IStudentManager{    public static final String DESCRIPTOR = "com.lgy.aidl.IStudentStub";    public static final int TRANSACTION_getAllStudent = FIRST_CALL_TRANSACTION + 0;    public static final int TRANSACTION_addStudent = FIRST_CALL_TRANSACTION + 1;    IStudentStub(){        this.attachInterface(this,DESCRIPTOR);    }    public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {        switch (code) {            case INTERFACE_TRANSACTION: {                reply.writeString(DESCRIPTOR);                return true;            }            case TRANSACTION_getAllStudent: {                data.enforceInterface(DESCRIPTOR);                List<Student> _result = this.getAllStudent();                reply.writeNoException();                reply.writeTypedList(_result);                return true;            }            case TRANSACTION_addStudent: {                data.enforceInterface(DESCRIPTOR);                Student _arg0;                if ((0 != data.readInt())) {                    _arg0 = Student.CREATOR.createFromParcel(data);                } else {                    _arg0 = null;                }                this.addStudent(_arg0);                reply.writeNoException();                return true;            }        }        return super.onTransact(code, data, reply, flags);    }    public static IStudentManager asInterface(IBinder binder){        if (null == binder){            return null;        }        IInterface iin = binder.queryLocalInterface(DESCRIPTOR);        if (iin != null && iin instanceof IStudentStub){            return (IStudentManager) iin;        }        return new Proxy(binder);    }    @Override    public List<Student> getAllStudent() throws RemoteException {        return null;    }    @Override    public void addStudent(Student stu) throws RemoteException {    }    @Override    public IBinder asBinder() {        return this;    }    static class Proxy implements IStudentManager{        private IBinder mRemote;        Proxy(IBinder binder){            mRemote = binder;        }        @Override        public List<Student> getAllStudent() throws RemoteException {            Parcel _data = Parcel.obtain();            Parcel _reply = Parcel.obtain();            List<Student> _result;            try {                _data.writeInterfaceToken(DESCRIPTOR);                mRemote.transact(TRANSACTION_getAllStudent, _data, _reply, 0);                _reply.readException();                _result = _reply.createTypedArrayList(com.lgy.aidl.aidl.Student.CREATOR);            } finally {                _reply.recycle();                _data.recycle();            }            return _result;        }        @Override        public void addStudent(Student stu) throws RemoteException {            Parcel _data = Parcel.obtain();            Parcel _reply = Parcel.obtain();            try {                _data.writeInterfaceToken(DESCRIPTOR);                if ((stu != null)) {                    _data.writeInt(1);                    stu.writeToParcel(_data, 0);                } else {                    _data.writeInt(0);                }                mRemote.transact(TRANSACTION_addStudent, _data, _reply, 0);                _reply.readException();            } finally {                _reply.recycle();                _data.recycle();            }        }        @Override        public IBinder asBinder() {            return mRemote;        }    }}

我们的使用在客户端和服务器端:

 private ServiceConnection mConnection = new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {            Log.i(TAG, "客户端进程连接成功");            mStudentManager = IStudentStub.asInterface(iBinder);            try {                mList = (ArrayList<Student>) mStudentManager.getAllStudent();                Log.i(TAG,"客户端进程连接成功之后,返回的学生人数" + mList.size());            } catch (RemoteException e) {                e.printStackTrace();            }            Student stu4 = new Student("4","Tom","男","15678958962");            Student stu5 = new Student("5","lily","女","18963526354");            try{                mStudentManager.addStudent(stu4);                mStudentManager.addStudent(stu5);            }catch (RemoteException e){                e.printStackTrace();            }            try {                mList = (ArrayList<Student>) mStudentManager.getAllStudent();                Log.i(TAG, "添加了2名学生后,返回的学生人数" + mList.size());            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName componentName) {        }    };
    private IStudentStub mBinder = new IStudentStub(){        @Override        public List<Student> getAllStudent() throws RemoteException {            Log.i(TAG,"客户端调用getAllStudent方法执行,学生人数" + mList.size());            return mList;        }        @Override        public void addStudent(Student stu) throws RemoteException {            Log.i(TAG,"客户端调用addStudent方法执行之前学生人数" + mList.size());            mList.add(stu);            Log.i(TAG, "客户端调用addStudent方法执行之后学生人数" + mList.size());        }    };

我们在看一看运行的log日志是否和我们预期的一致呢?!
服务器端
这里写图片描述
再看一下我编写后的程序结构如下:
这里写图片描述
不知道写到这里大家是否能够理解,有问题大家一起探讨吧!

0 0
原创粉丝点击