简谈源码-AIDL

进程

  1. 线程和进程

    线程是系统调度的最小单位;进程是资源分配的最小单位

  2. 多进程

    在清单文件中给四大组件设置android:process属性,两种方式

    a. :remote

    b. cc.catface.xapp.remote

    a方式为当前应用的私有进程,其他应用进程不能访问之,进程名参考cc.catface.xapp:remote

    b方式为全局进程,其他应用进程可以访问之,进程名参考cc.catface.xapp.remote

    系统会为每个应用分配唯一UID,以隔离内存数据访问

  3. 四大组件多进程存在的问题

    android为每个应用分配一个独立的虚拟机,系统会在创建新进程的同时,分配独立的虚拟机,所以进程间无法通过共享同一片内存区域来共享数据

    1. 静态成员和单例模式完全失效
    2. 线程同步机制完全失效
    3. SP可靠性下降[I/O并发读/写]
    4. Application会多次创建[运行不同进程需要分配不同的虚拟机]

序列化Serializable和Parcelable(*)

参考https://blog.youkuaiyun.com/itCatface/article/details/85948341

Binder

安卓中常见IPC方式及使用场景

方式优点缺点使用场景
Bundle数据类型限制四大组件
文件共享并发大量IO
AIDL安卓独有快速功能强大为第三方app提供各种服务方法
Messengeraidl的封装传递Message对象消息配合Handler和Message传递简单标识
ContentProvideraidl的封装操作数据库跨进程CRUD
Socket网络

简谈AIDL源码

  1. aidl案例

    package cc.catface.aidls.login;
    
    interface Test {
        void hello(String name);
    }
    
  2. 根据aidl生成的接口

    package cc.catface.aidls.login;
    
    public interface Test extends android.os.IInterface {
        
        public static class Default implements cc.catface.aidls.login.Test {}
        
        public static abstract class Stub extends android.os.Binder implements cc.catface.aidls.login.Test {}
        
        public void hello(java.lang.String name) throws android.os.RemoteException;
    }
    

    2.1、Test接口,继承IInterface,IInterface包含唯一抽象方法IBinder asBinder(),用于检索并返回与此接口关联的Binder对象;

    2.2、Default类,Test接口的默认实现;

    2.3、Stub[桩类],实现Test接口,其asBinder方法会根据,C/S在同一进程,返回当前Stub,即Binder对象;若C/S不在同一进程,返回远程Binder对象;

    2.4、hello抽象方法,aidl中的方法声明;

    2.5、IInterface接口[系统]

    public interface IInterface {
        public IBinder asBinder();
    }
    

    IInterface是Binder接口的基类;asBinder方法用于检索并返回与此接口关联的Binder对象;

  3. Default类

    public static class Default implements cc.catface.aidls.login.Test {
        @Override public void hello(java.lang.String name) throws android.os.RemoteException {}
    
        @Override public android.os.IBinder asBinder() {
            return null;
        }
    }
    

    Default是Test接口的默认空实现类,内部方法也为空实现,asBinder方法返回null;

  4. Stub类

    public static abstract class Stub extends android.os.Binder implements cc.catface.aidls.login.Test {
        private static final java.lang.String DESCRIPTOR = "cc.catface.aidls.login.Test";
        
        public Stub() {//...}
        public static cc.catface.aidls.login.Test asInterface(android.os.IBinder obj) {//...}
                
        @Override public android.os.IBinder asBinder() {//...}
        @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {//...}
                
        private static class Proxy implements cc.catface.aidls.login.Test {
            private android.os.IBinder mRemote;
            Proxy(android.os.IBinder remote) {//...}
            @Override public android.os.IBinder asBinder() {//...}
            public java.lang.String getInterfaceDescriptor() {//...}
            @Override public void hello(java.lang.String name) throws android.os.RemoteException {//...}
            public static cc.catface.aidls.login.Test sDefaultImpl;
        }
                    
        static final int TRANSACTION_hello = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
                    
        public static boolean setDefaultImpl(cc.catface.aidls.login.Test impl) {//...}
        public static cc.catface.aidls.login.Test getDefaultImpl() {//...}
    }
    

    4.1、桩类Stub,继承Binder,客户端通过Stub拿到Binder实例,来调用服务端方法;

    4.2、DESCRIPTOR常量,描述服务的标识,即当前服务标识为cc.catface.aidls.login.Test;参考getSystemService(Context.CAMERA_SERVICE);getSystemService(Context.ACTIVITY_SERVICE);等;

    4.3、Stub构造方法

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

    4.3.1、attachInterface为Binder中的方法

    public class Binder implements IBinder {	
        private IInterface mOwner;
        private String mDescriptor;
        
    	public void attachInterface(@Nullable IInterface owner, @Nullable String descriptor) {
            mOwner = owner;
            mDescriptor = descriptor;
        }
        //...
    }
    

    将接口与Binder关联,便于后续的asInterface方法获取对应的本地或远程Binder对象;

    4.4、asInterface方法

    public static cc.catface.aidls.login.Test asInterface(android.os.IBinder obj) {
        if ((obj == null)) {
            return null;
        }
        android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
        if (((iin != null) && (iin instanceof cc.catface.aidls.login.Test))) {
            return ((cc.catface.aidls.login.Test) iin);
        }
        return new cc.catface.aidls.login.Test.Stub.Proxy(obj);
    }
    

    将Stub(IBinder)对象转换为Test接口,通过queryLocalInterface方法判断C/S是否在同一进程,若在同一进程,直接返回Stub.this即当前Stub;若不在同一进程,inn为空,并通过Proxy代理创建远程IBinder对象,即提供远程Test服务的Binder;

    4.4.1、queryLocalInterface方法

    public class Binder implements IBinder {
        public @Nullable IInterface queryLocalInterface(@NonNull String descriptor) {
            if (mDescriptor != null && mDescriptor.equals(descriptor)) {
                return mOwner;
            }
            return null;
        }
        //...
    }
    

    检索descriptor描述的Binder对象的本地实现,如果返回null,则需要实例化一个代理类,以便通过transact方法对调用进行编组处理;通过实际调用得出结论,对于同样的Test.Stub.asInterface(service);方法调用,C/S在不同进程,返回的iin为null,在同一进程,返回的iin为TestService$Binder@11064;

    4.5、asBinder方法

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

    返回当前Binder对象

    4.6、onTransact方法

    @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_hello: {
                data.enforceInterface(descriptor);
                java.lang.String _arg0;
                _arg0 = data.readString();
                this.hello(_arg0);
                reply.writeNoException();
                return true;
            }
            default: {
                return super.onTransact(code, data, reply, flags);
            }
        }
    }
    

    服务端调用,code为方法标识,参考4.8;data为客户端传参,其中的_arg0为hello方法的入参name;reply为hello方法处理后的返回值;return true标识该方法在服务端成功处理并响应;不在同一进程的客户端会通过Proxy中的mRemote对象,即远程Binder对象,调用transact方法,最终调用到当前服务端的onTransact方法;

    4.7、Proxy代理,当C/S不在同一进程,就要用Proxy来实例化远程Binder对象,并执行transact方法;详见5.

    4.8、TRANSACTION_hello标识,aidl中声明的方法标识

    4.9、setDefaultImpl方法和getDefaultImpl方法

    public static boolean setDefaultImpl(cc.catface.aidls.login.Test impl) {
        if (Stub.Proxy.sDefaultImpl != null) {
            throw new IllegalStateException("setDefaultImpl() called twice");
        }
        if (impl != null) {
            Stub.Proxy.sDefaultImpl = impl;
            return true;
        }
        return false;
    }
    
    public static cc.catface.aidls.login.Test getDefaultImpl() {
        return Stub.Proxy.sDefaultImpl;
    }
    

    public static cc.catface.aidls.login.Test sDefaultImpl;声明在Proxy内部,参考5.,用来操作默认的Test对象,并在Proxy进行服务方法处理时使用,如Proxy=>hello(){getDefaultImpl().hello(name)};

  5. Proxy代理类

    private static class Proxy implements cc.catface.aidls.login.Test {
        private android.os.IBinder mRemote;
        Proxy(android.os.IBinder remote) {//...}
        @Override public android.os.IBinder asBinder() {//...}
        public java.lang.String getInterfaceDescriptor() {//...}
        @Override public void hello(java.lang.String name) throws android.os.RemoteException {//...}
        public static cc.catface.aidls.login.Test sDefaultImpl;
    }
    

    5.1、Proxy

    private static class Proxy implements cc.catface.aidls.login.Test {
        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 hello(java.lang.String name) 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.writeString(name);
                boolean _status = mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);
                if (!_status && getDefaultImpl() != null) {
                    getDefaultImpl().hello(name);
                    return;
                }
                _reply.readException();
            } finally {
                _reply.recycle();
                _data.recycle();
            }
        }
        
        public static cc.catface.aidls.login.Test sDefaultImpl;
    }
    

    5.2、mRemote

    调用远程服务的Binder对象

    5.5、hello方法

    客户端调用hello方法,_data为客户端入参,mRemote.transact调用远程服务端的onTransact方法,_status为服务端处理成功失败标志,参考4.6,若是成功,_reply为方法返回值;

    5.6、boolean _status = mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);

    _status为服务端的onTransact方法处理返回值,但一般好像都是true;onTransact方法的源码注释为,成功调用时返回true;返回false通常用于表示您没有理解事务代码;

aidl调用补充

当C/S不在同一进程,C调用hello方法的流程为,先调用本地Test里Proxy的hello方法,通过boolean _status = mRemote.transact(Stub.TRANSACTION_hello, _data, _reply, 0);调用远程服务端的Test里Stub的public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags)方法,若该方法返回false;

这里常见的都是返回true,如何返回false呢,可以删除服务端的aidl文件,直接将Test复制进src相应目录下,手动改成返回false;

此时_status即为false,再判断getDefaultImpl()是否为空,sDefaultImpl可以在客户端连接服务后调用Test.Stub.setDefaultImpl(new Test() {})设置一个由客户端实现的本地默认处理类;

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值