AIDL中的in,out,inout原理篇

AIDL中的in,out,inout用法篇主要对跨进程传输对象三种定向tag方式的用法进行了讲解,验证了以下结论:
in:由cilent端流向server端,server端可以收到此对象的所有数据,收到之后会重新创建一个新的对象将数据填充进去,因为cilent端和server端是两个不同的对象,所以server端对数据的修改不会影响到client端的对象。
out:由server端流向client端,client端将对象传递给server端后,server端相当于收到的是一个空对象,没有client端此对象的任何数据,但是server端对此空对象的操作会影响到cilent端。
inout:对象可以双向流动,即server端能收到cilent发过来的对象的数据,server端对此对象的操作也能影响到cilent端

看此篇文章是根据上一篇的代码进行分析的
主要看一下系统给我们生成的IAIDLControl.java文件

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.tct.aidlapplication;

public interface IAIDLControl extends android.os.IInterface {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    public void addStudent(com.tct.aidlapplication.Student student)
        throws android.os.RemoteException;

    public void addTeacher(com.tct.aidlapplication.Teacher teacher)
        throws android.os.RemoteException;

    public void addWorker(com.tct.aidlapplication.Worker worker)
        throws android.os.RemoteException;

    /** Local-side IPC implementation stub class. */
    public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
        private static final java.lang.String DESCRIPTOR = "com.tct.aidlapplication.IAIDLControl";
        static final int TRANSACTION_addStudent = (android.os.IBinder.FIRST_CALL_TRANSACTION +
            0);
        static final int TRANSACTION_addTeacher = (android.os.IBinder.FIRST_CALL_TRANSACTION +
            1);
        static final int TRANSACTION_addWorker = (android.os.IBinder.FIRST_CALL_TRANSACTION +
            2);

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

        /**
         * Cast an IBinder object into an com.tct.aidlapplication.IAIDLControl interface,
         * generating a proxy if needed.
         */
        public static com.tct.aidlapplication.IAIDLControl asInterface(
            android.os.IBinder obj) {
            if ((obj == null)) {
                return null;
            }

            android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);

            if (((iin != null) &&
                    (iin instanceof com.tct.aidlapplication.IAIDLControl))) {
                return ((com.tct.aidlapplication.IAIDLControl) iin);
            }

            return new com.tct.aidlapplication.IAIDLControl.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_addStudent: {
                data.enforceInterface(descriptor);

                com.tct.aidlapplication.Student _arg0;

                if ((0 != data.readInt())) {
                    _arg0 = com.tct.aidlapplication.Student.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }

                this.addStudent(_arg0);
                reply.writeNoException();

                return true;
            }

            case TRANSACTION_addTeacher: {
                data.enforceInterface(descriptor);

                com.tct.aidlapplication.Teacher _arg0;
                _arg0 = new com.tct.aidlapplication.Teacher();
                this.addTeacher(_arg0);
                reply.writeNoException();

                if ((_arg0 != null)) {
                    reply.writeInt(1);
                    _arg0.writeToParcel(reply,
                        android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                } else {
                    reply.writeInt(0);
                }

                return true;
            }

            case TRANSACTION_addWorker: {
                data.enforceInterface(descriptor);

                com.tct.aidlapplication.Worker _arg0;

                if ((0 != data.readInt())) {
                    _arg0 = com.tct.aidlapplication.Worker.CREATOR.createFromParcel(data);
                } else {
                    _arg0 = null;
                }

                this.addWorker(_arg0);
                reply.writeNoException();

                if ((_arg0 != null)) {
                    reply.writeInt(1);
                    _arg0.writeToParcel(reply,
                        android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                } else {
                    reply.writeInt(0);
                }

                return true;
            }

            default:return super.onTransact(code, data, reply, flags);
            }
        }

        private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
            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 addStudent(com.tct.aidlapplication.Student student)
                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 ((student != null)) {
                        _data.writeInt(1);
                        student.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }

                    mRemote.transact(Stub.TRANSACTION_addStudent, _data,
                        _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public void addTeacher(com.tct.aidlapplication.Teacher teacher)
                throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_addTeacher, _data,
                        _reply, 0);
                    _reply.readException();

                    if ((0 != _reply.readInt())) {
                        teacher.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }

            @Override
            public void addWorker(com.tct.aidlapplication.Worker worker)
                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 ((worker != null)) {
                        _data.writeInt(1);
                        worker.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }

                    mRemote.transact(Stub.TRANSACTION_addWorker, _data, _reply,
                        0);
                    _reply.readException();

                    if ((0 != _reply.readInt())) {
                        worker.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
        }
    }
}

AIDL中的in,out,inout用法篇定义了三个方法用来传输对象,Student定义为in,Teacher定义为out,Worker定义为inout,对应的三个方法是addStudent,addTeacher,addWorker。
首先来看Student的传输,定向tag为in

Proxy .addStudent

private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
            @Override
            public void addStudent(com.tct.aidlapplication.Student student)
                    throws android.os.RemoteException {
                //创建两个Parcel对象,_data用于将client端对象数据写入
                //_reply传递给server端,tag为in用不到
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //如果client端传过来的对象不为空
                    if ((student != null)) {
                        //写入int 1
                        _data.writeInt(1);
                        //将student的数据写入_data
                        student.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    //调用BinderProxy的transact进行binder传输,标识为TRANSACTION_addStudent
                    mRemote.transact(Stub.TRANSACTION_addStudent, _data,
                            _reply, 0);
                    _reply.readException();
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
     }

student.writeToParcel

public class Student implements Parcelable {
    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(this.age);
        out.writeString(this.name);
    }
 }

我们看到调用student.writeToParcel方法就是将student的数据写入Parcel在内存中进行传输,mRemote.transact是进行binder传输,具体如何传输的非常复杂先不去深究,只要知道通过BinderProxy.transact传递标识就可以调到Binder.onTransact

mRemote.transact

public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
@Override
        public boolean onTransact(int code, android.os.Parcel data,
                                  android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
                ......
                case TRANSACTION_addStudent: {
                    data.enforceInterface(descriptor);
                    com.tct.aidlapplication.Student _arg0;
                    //如果client传过来的student不为空
                    if ((0 != data.readInt())) {
                        //调用student的createFromParcel方法,并将client端包装好student数据的Parcel
                        //传递进去
                        _arg0 = com.tct.aidlapplication.Student.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    //调用server端具体实现
                    this.addStudent(_arg0);
                    reply.writeNoException();
                    return true;
                }
}

student.createFromParcel

public class Student implements Parcelable {
public static final Creator<Student> CREATOR = new Creator<Student>() {

     private Student(Parcel in) {
           readFromParcel(in);
       }
        @Override
        public Student createFromParcel(Parcel in) {
            return new Student(in);
        }

        @Override
        public Student[] newArray(int size) {
            return new Student[size];
         }
     };
      public void readFromParcel(Parcel in){
         this.age = in.readInt();
         this.name = in.readString();
     }
}

createFromParcel方法重新创建了Student实例,构造方法中调用readFromParcel,readFromParcel中将client端包装好的数据反序列化出来并赋值给新创建的对象,接着调用server端addStudent方法将这个对象传进去,到这里我们就明白了,tag为in时,server端其实是重新创建的一个对象,并且将client端对象的数据一一赋值给新的对象,所以这两个对象互不影响

接着看Teacher传输,定向tag为out

private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
           @Override
            public void addTeacher(com.tct.aidlapplication.Teacher teacher)
                    throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();

                try {
                    _data.writeInterfaceToken(DESCRIPTOR);
                    mRemote.transact(Stub.TRANSACTION_addTeacher, _data,
                            _reply, 0);
                    _reply.readException();

                    if ((0 != _reply.readInt())) {
                        teacher.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
    }

和addStudent不同,addTeacher并没有调用writeToParcel方法将teacher数据写入Parcel

mRemote.transact

  public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
        ......
        @Override
        public boolean onTransact(int code, android.os.Parcel data,
                                  android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
				case TRANSACTION_addTeacher: {
                    data.enforceInterface(descriptor);

                    com.tct.aidlapplication.Teacher _arg0;
                    //通过new直接创建了新的teacher对象
                    _arg0 = new com.tct.aidlapplication.Teacher();
                    //调用addTeacher方法传入此对象
                    this.addTeacher(_arg0);
                    reply.writeNoException();

                    if ((_arg0 != null)) {
                        reply.writeInt(1);
                        _arg0.writeToParcel(reply,
                                android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }

                    return true;
                }

Teacher的无参构造里什么也没有做,关于此篇分析的代码全部在AIDL中的in,out,inout用法篇
所以tag为out时server端并不能收到client端对象的任何数据,调用server端addTeacher之后接着调用teacher的writeToParcel方法,使用的reply是client端传递过来Parcel,如果我们在server端addTeacher里对new出来的对象做了任何数据的修改则server端就会将数据写入reply传递给client端,Proxy.addTeacher中执行了mRemote.transact之后接着会执行teacher.readFromParcel(_reply);

teacher.readFromParcel

readFromParcel会读取server端给我们返回来的reply里的数据赋值给到client端的teacher

public class Teacher implements Parcelable {
    .....
    public void readFromParcel(Parcel in){
        this.age = in.readInt();
        this.name = in.readString();
    }
}

到这里我们明白了tag为out时,server端并不能收到client端对象的任何数据,因为client根本就没有将数据写入Parcel传递给server端,而server端则是重新创建的一个实例,对此实例的修改都会返回给到client端并覆盖掉client端对象的值,所以out tag会影响client端对象。

接着看Worker传输,定向tag为inout

private static class Proxy implements com.tct.aidlapplication.IAIDLControl {
              @Override
            public void addWorker(com.tct.aidlapplication.Worker worker)
                    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 ((worker != null)) {
                        _data.writeInt(1);
                        //将client端对象数据写入Parcel
                        worker.writeToParcel(_data, 0);
                    } else {
                        _data.writeInt(0);
                    }
                    //binder传输
                    mRemote.transact(Stub.TRANSACTION_addWorker, _data, _reply,
                            0);        
                    _reply.readException();

                    if ((0 != _reply.readInt())) {
                        //将server端对数据的修改返回的replay读取到client端对象
                        worker.readFromParcel(_reply);
                    }
                } finally {
                    _reply.recycle();
                    _data.recycle();
                }
            }
    }
  public static abstract class Stub extends android.os.Binder implements com.tct.aidlapplication.IAIDLControl {
        ......
        @Override
        public boolean onTransact(int code, android.os.Parcel data,
                                  android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
				case TRANSACTION_addWorker: {
                    data.enforceInterface(descriptor);

                    com.tct.aidlapplication.Worker _arg0;

                    if ((0 != data.readInt())) {
                       //调用createFromParcel创建新的对象,并将client端对象数据读取到新对象
                        _arg0 = com.tct.aidlapplication.Worker.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
                    //可以在此方法对对象数据进行修改
                    this.addWorker(_arg0);
                    reply.writeNoException();

                    if ((_arg0 != null)) {
                        reply.writeInt(1);
                        //将server端对象数据写入replay返回给client
                        _arg0.writeToParcel(reply,
                                android.os.Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
                    } else {
                        reply.writeInt(0);
                    }

                    return true;
                }
         }

input其实就是结合了in,out的特点,server端可以获取到client端对象的数据,并且server端对对象的修改可以影响到client端,具体代码就不细分析了,和in,out都一样的

附上log:

D/dongjiao( 2501): before in student age = :20,name = :Tom
D/dongjiao( 2517): in student addStudent...age = :20,name = :Tom
D/dongjiao( 2501): before in student age = :20,name = :Tom

D/dongjiao( 2501): before out teacher age = :30,name = :Jerry
D/dongjiao( 2517): out teacher addTeacher age = :0,name = :null
D/dongjiao( 2501): end out teacher age = :35,name = :Jerry_update

D/dongjiao( 2501): before inout worker age = :40,name = :Tony
D/dongjiao( 2517): inout worker addWorker age = :40,name = :Tony
D/dongjiao( 2501): end inout worker age = :45,name = :tony_update

log分别表示传输前,传输到server,传输后,对象的值
全部源码在AIDL中的in,out,inout用法篇

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值