美文网首页
IPC机制总结

IPC机制总结

作者: 济公大将 | 来源:发表于2018-03-07 17:16 被阅读0次

    本文基于《Android艺术探索》中知识的总结而创


    1 简介

    1.1 简述

    IPC 进程间通讯或跨进程通讯

    • android中IPC方式 Binder(AIDL)、Socket、Bundle、文件共享、Messenger、ContentProvider
    • IPC的基础场景是多进程:一般由两种,应用内多进程模式,应用间数据共享

    1.2 进程与线程

    • 线程是cpu调度的最小单位,是一种有限的系统资源
    • 进程指一个执行单元,是一个独立的应用或者程序
    • 一个进程可包含多个线程
    • ANR 主线程无响应,以多线程解决

    2 多进程模式

    2.1 开启

    • 一般只有一种方法 就是在AndroidMenifest文件中给四大组件指定android:process属性。
      当然也可以通过JNI的natice层去fork。但是很少这么玩
    • 查看当前进程的命令:adb shell ps | grep com.gjg.text
    • 进程名以":"开头的进程属于应用的私有进程,其它应用的组件不可以和它泡在同一个进程中,非":"开头的进程属于全局进程,其它应用可以要通过ShareUID方式(ShareUID相同且签名相同)和它跑在同一个进程中。

    2.2 多进程模式运行机制

    不同的进程有独立的虚拟机,Applicaition以及内存空间,所以开启了多进程模式的应用应注意一下问题:

    1 静态成员和单利模式完全失效
    2 线程同步机制完全失效
    3 SharedPreferences的可靠性下降
    4 Application会多次创建

    3 IPC基础载体

    3.1 Serializable

    • serialVersionUID:用来辅助序列化和反序列化过程的,原则上序列化后的数据中的serialVersionUID只有和当前类的serialVersionUID相同才能够被正常的反序列化。
    • 系统默认用hash值作为serialVersionUID,当变量数和类型改变时,hash会变化,所以系统默认情况下这种改变发生时反序列化会crash
    public class User implements Serializable{
    }
    //序列化过程
    User user = new User();
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("cache.txt"));
    out.writeObject(user);
    out.close();
    //反序列化过程
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("cache.txt"));
    User user = (User)in.readObject();
    in.close();
    

    3.2 Parcelable

    public class User implements Parcelable{
        private String name;
        private int age;
    
        public User() {
        }
    
        public User(String name, int age) {
            this.name = name;
            this.age = age;
        }
    
        //反序列化
        protected User(Parcel in) {
            name = in.readString();
            age = in.readInt();
        }
    
        //用于反序列化的创建器
        public static final Creator<User> CREATOR = new Creator<User>() {
            //从序列化的数据中创建原始对象
            @Override
            public User createFromParcel(Parcel in) {
                return new User(in);
            }
            //创建指定长度的原始对象数组
            @Override
            public User[] newArray(int size) {
                return new User[size];
            }
        };
    
        /**
         * 返回当前对象的内容描述
         * 如果含有文件描述符,返回1(CONTENTS_FILE_DESCRIPTOR),否则返回0
         * 多数都返回0
         * @return
         */
        @Override
        public int describeContents() {
            return 0;
        }
    
        /**
         * 序列化操作
         * @param dest
         * @param flags
         *  当为1(PARCELABLE_WRITE_RETURN_VALUE) 标示当前对象需要作为返回值返回,不能立即释放资源
         *  几乎所有情况都为0
         */
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeString(name);
            dest.writeInt(age);
        }
        /**
         * Parcel
         * 内部包装了可序列化的数据的native操作,例如
         *   @FastNative
         *   private static native void nativeWriteInt(long nativePtr, int val);
         *   @FastNative
         *   private static native void nativeWriteLong(long nativePtr, long val);
         */
    }
    
    • Serializabble 是java中的序列化接口,使用简单但开销大,序列化和反序列化过程需要大量IO操作,适用于序列化到设备或者网络传输中
    • Parcelable 是android 中的序列化方式,使用麻烦但是效率高,主要用于内存序列化上。

    3.3 Binder

    (1)Binder 继承在IBinder。是IPC的框进程通讯方式
    (2)还可以理解为一种虚拟的物理设备
    (3)从android framework层来说Binder是ServiceManager连接各种Manager(ActivityManager WindowManager)和响应ManagerService的桥梁。
    (4)从android 应用层来说是客户端和服务端进行通讯的媒介。当bindService时,返回段会返回一个包含服务端业务调用的Binder对象。

    AIDL创建及核心源码解析

    创建AIDL文件

    //1.创建User.java 同上
    //2.创建User在AIDL中的声明文件 User.aidl
    package gjg.com.fundemo.dbg;
    parcelable User;
    //3.创建User的管理aidl文件
    package gjg.com.fundemo.dbg;
    //这里要注意使用全包名,且User有对应的User.aidl文件,否则会提示找不到
    //aidl只支持方法生命,不支持静态变量
    import gjg.com.fundemo.dbg.User;
    interface IUserManager {
        List<User> getUserList();
       /**
        * in 输入型参数
        * out 输出型参数
        * inout 输入输出型参数
        */
        void addUser(in User user);
    }
    //4.重新编译后系统会生成IUserManager.java
    
    package gjg.com.fundemo.dbg;
    
    public interface IUserManager extends android.os.IInterface {
        /**
         * 集成Binder 实现了IUserManager接口本身
         * 这是个抽象方法,并没有实现IUserManager具体方法,需要在服务端自定义Binder时实现
         * 一般在服务端继承自改抽象类,并在onBind中返回其实现
         */
        public static abstract class Stub extends android.os.Binder implements gjg.com.fundemo.dbg.IUserManager {
            //Binder的唯一标示
            private static final java.lang.String DESCRIPTOR = "gjg.com.fundemo.dbg.IUserManager";
    
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * 用于将服务端的Binder对象转换成客户端所需的AIDL接口类型的对象
             */
            public static gjg.com.fundemo.dbg.IUserManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                //如果客户端和服务端在同一进程,返回的就是服务端的Stub对象本身Stub.Proxy对象
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof gjg.com.fundemo.dbg.IUserManager))) {
                    return ((gjg.com.fundemo.dbg.IUserManager) iin);
                }
                //如果客户端和服务端不在同一进程,返回的是封装后的
                return new gjg.com.fundemo.dbg.IUserManager.Stub.Proxy(obj);
            }
    
            /**
             * 用于返回当前Binder对象,在IInterface中定义的
             */
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            /**
             * 该方法运行在服务端中Binder线程池中
             * 当客户端发起请求时,远程请求会通过系统底层封装后交由此方法来处理
             * 只有跨进程时才会调用此方法
             * @param code
             *  服务端通过code可以确定所请求的目标方法
             * @param data
             *  data中存有目标方法所需的参数
             * @param reply
             *  当目标方法执行完后会将返回值写入reply中
             * @param flags
             * @return 返回false 证明客户端请求失败
             * @throws android.os.RemoteException
             */
            @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_getUserList: {
                        data.enforceInterface(DESCRIPTOR);
                        //调用服务端方法得到返回值
                        java.util.List<gjg.com.fundemo.dbg.User> _result = this.getUserList();
                        reply.writeNoException();
                        //返回值写入reply
                        reply.writeTypedList(_result);
                        return true;
                    }
                    case TRANSACTION_addUser: {
                        data.enforceInterface(DESCRIPTOR);
                        gjg.com.fundemo.dbg.User _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = gjg.com.fundemo.dbg.User.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        //调用服务端方法得到返回值
                        this.addUser(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            /**
             * 如果是跨进程通讯,该代理会被返回
             */
            private static class Proxy implements gjg.com.fundemo.dbg.IUserManager {
                //这个mRemote就是服务端继承自Stub的Binder对象
                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;
                }
    
                //在客户端调用,最终会通过transact调服务端方法
                @Override
                public java.util.List<gjg.com.fundemo.dbg.User> getUserList() throws android.os.RemoteException {
                    //创建所需的输入型Parcel对象
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    //创建输出型Parcel对象
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    //创建返回值对象
                    java.util.List<gjg.com.fundemo.dbg.User> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        //发起RPC(远程过程调用)请求,同时当前线程挂起
                        //transact被调用,知道RPC过程返回后,当前线程继续执行
                        //从reply中取出RPC过程的返回结果
                        mRemote.transact(Stub.TRANSACTION_getUserList, _data, _reply, 0);
                        _reply.readException();
                        //返回reply中的结果,反序列化,这里可以看出AIDL的对象需要细线parcelable接口
                        _result = _reply.createTypedArrayList(gjg.com.fundemo.dbg.User.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public void addUser(gjg.com.fundemo.dbg.User user) 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 ((user != null)) {
                            _data.writeInt(1);
                            //将参数写入输出型parcel对象中
                            user.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addUser, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
            static final int TRANSACTION_getUserList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_addUser = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
        //接口的方法定义
        public java.util.List<gjg.com.fundemo.dbg.User> getUserList() throws android.os.RemoteException;
        //接口的方法定义
        public void addUser(gjg.com.fundemo.dbg.User user) throws android.os.RemoteException;
    }
    // 5.给Binder设置死亡代理
    // 当服务端Binder连接断裂时,客户端可以收到通知,一遍再次发起请求从而恢复连接的解决方案
    //示例代码如下
    //服务端Service
    public class UserRemoteService extends Service {
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            return binder;
        }
        //返回个客户端的Binder
        IUserManager.Stub binder = new IUserManager.Stub() {
    
            @Override
            public List<User> getUserList() throws RemoteException {
                return null;
            }
    
            @Override
            public void addUser(User user) throws RemoteException {
    
            }
        };
    }
    public class UserTestActivity extends AppCompatActivity {
        //客户端对IUserManager
        private IUserManager mUserManager;
        //服务端Binder死亡代理对象
        private DeathRecipient mDeathRecipient = new DeathRecipient();
        private ServiceConnection mSc = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //根据服务端Binder创建客户端IUserManager对象
                mUserManager = IUserManager.Stub.asInterface(service);
                try {
                    //绑定服务端Binder死亡代理
                    service.linkToDeath(mDeathRecipient,0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            Intent intent = new Intent(this,UserRemoteService.class);
            //绑定服务
            bindService(intent,mSc,0);
            if(mUserManager != null){
                try {
                    List<User> users = mUserManager.getUserList();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
    
        /**
         * Binder死亡代理
         * 一般在bindService中Connection后创建并设置
         * IUserManager mServiceBinder = IUserManager.Stub.asInterface(binder);
         * binder.linkToDeath(this,0);
         */
        public  class DeathRecipient implements IBinder.DeathRecipient {
            //当Binder死亡是会回调此方法
            @Override
            public void binderDied() {
                if(mUserManager == null){
                    return;
                }
                //解绑服务端Binder死亡代理对象
                mUserManager.asBinder().unlinkToDeath(this,0);
                mUserManager = null;
            }
        }
    }
    

    4 Android中的IPC方式

    4.1 Bundle

    Bundle implements Parcelable 所以可以方便的在不同进程进行通讯

    4.2 使用文件共享

    适合同步要求不高的进程间通讯

    4.3 Messenger

    是对AIDL的简单封装,以Message作为载体

    4.4 AIDL

    流程:
    -->服务端创建AIDL文件,编译生成接口,服务端实现接口的.Stub返回
    -->客户端绑定Service,绑定成功后,将服务端返回的Binder对象转成AIDL文件对应的接口对象
    注意:
    aidl文件中不是所有类型都支持,支持的类型如下:

    基本数据类型
    String CharSequence
    List-ArrayList,里面的每个元素必须被aidl支持,这里指服务端最终会返回ArrayList类型
    Map-HashMap,里面的每个元素必须被aidl支持
    Parcelable,所有实现了Parcelable接口的对象
    AIDL:所有aidl接库本身也可以在aidl文件中使用

    自定义的Parcelable对象,在aidl中使用时,必须新建一个和它同名的AIDL文件,并在其中生命它为parcleable类型。例如:

    package com.gjg
    parcelable User;
    

    RemoteCallbackList

    • 跨进程传输对象的最想都会经过反序列化,也就是说两端针对相同内容的对象却不是真正的同一个对象,所以就会导致跨进程解注册时会出现问题,而RemoteCallbackList就为解决此问题而生。
    • RemoteCallbackList是专门提供的用于删除款进程listener的接口,它是一个泛型,支持管理任意的aidl接口,其声明如下:
      public class RemoteCallbackList<E extends IInterface>
      其本质就是利用了跨进程对象的相同对象在两端拥有相同的底层Binder对象

    安全验证,在androidMenifest中声明,可在服务端onBind或者onTransact中进行验证是否有权限

    4.5 ContentProvider

    • 底层也是Binder机制
    • 六个方法 onCreate() getType() CRUD
    • CRUD 在Binder线程池
    • android:authorities 声明 ContentResolver中Uri参数与之配对
    • UriMatcher 实现外界访问的匹配功能

    4.6 Socket

    通过网络了。不光能跨进程,还能跨设备

    5 Binder连接池

    • 背景有很多aidl时不可能对应创建很多Service
    • Binder连接池的作用就是将每个业务模块的Binder请求统一转发到远程的Service中去执行,从而避免重复创建Service的过程
    //1. 创建两个简单aidl文件
    package gjg.com.fundemo.binderchi;
    
    interface ICompute {
        int add(int a,int b);
    }
    package gjg.com.fundemo.binderchi;
    
    interface ISecurityCenter {
        String encrypt(String content);
        String decrypt(String password);
    }
    //2. 创建aidl文件对应的实现
    package gjg.com.fundemo.binderchi;
    
    import android.os.RemoteException;
    
    public class SecurityCenerImpl extends ISecurityCenter.Stub {
        @Override
        public String encrypt(String content) throws RemoteException {
            return null;
        }
    
        @Override
        public String decrypt(String password) throws RemoteException {
            return null;
        }
    }
    
    package gjg.com.fundemo.binderchi;
    
    public class ComputeImpl extends ICompute.Stub {
        @Override
        public int add(int a, int b) throws RemoteException {
            return 0;
        }
    }
    
    //3. 创建IBinderPool的aidl文件
    package gjg.com.fundemo.binderchi;
    
    interface IBinderPool {
        IBinder queryBinder(int binderCode);
    }
    
    //4. 创建IBinderPool的实现,作为BinderPool的内部类
    public static class BinderPoolImpl extends IBinderPool.Stub{
    
            @Override
            public IBinder queryBinder(int binderCode) throws RemoteException {
                IBinder binder = null;
                switch (binderCode){
                    case BINDER_SECURITY_CENTER:
                        binder = new SecurityCenerImpl();
                        break;
                    case BINDER_COMPUTE:
                        binder = new ComputeImpl();
                        break;
                }
                return binder;
            }
        }
    //5. 创建Binder连接池的Service
    public class BinderPoolService extends Service {
        private BinderPool.BinderPoolImpl mBinderPoolImpl = new BinderPool.BinderPoolImpl();
        @Nullable
        @Override
        public IBinder onBind(Intent intent) {
            //返回的是服务端的BinderPoolImpl
            return mBinderPoolImpl;
        }
    }
    // 6. 创建BinderPool
    public class BinderPool {
        public static final int BINDER_SECURITY_CENTER = 1;
        public static final int BINDER_COMPUTE = 2;
    
        private Context mContext;
        private IBinderPool mBinderPool;
        private static volatile BinderPool sInstance;
        private CountDownLatch mCountDownLatch;//用于保证线程同步
        private BinderPool(Context context){
            this.mContext = context;
            connectBinderPoolService();
        }
    
        public static BinderPool getsInstance(Context context){
            if(sInstance == null){
                synchronized (BinderPool.class){
                    sInstance = new BinderPool(context);
                }
            }
            return sInstance;
        }
        public IBinder queryBinder(int binderCode){
            IBinder iBinder = null;
            if(mBinderPool != null){
                try {
                    mBinderPool.queryBinder(binderCode);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            return iBinder;
        }
        private void connectBinderPoolService() {
            mCountDownLatch = new CountDownLatch(1);
            Intent service = new Intent(mContext,BinderPoolService.class);
            mContext.bindService(service,mBinderPoolConnection,Context.BIND_AUTO_CREATE);
            try {
                mCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //连接
        private ServiceConnection mBinderPoolConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBinderPool  = IBinderPool.Stub.asInterface(service);
                try {
                    mBinderPool.asBinder().linkToDeath(mBinderPoolDeathRecipient,0);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
                mCountDownLatch.countDown();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
        /**
         * Binder死亡监控
         */
        private IBinder.DeathRecipient mBinderPoolDeathRecipient = new IBinder.DeathRecipient() {
            @Override
            public void binderDied() {
                mBinderPool.asBinder().unlinkToDeath(mBinderPoolDeathRecipient,0);
                mBinderPool = null;
                connectBinderPoolService();
            }
        };
        public static class BinderPoolImpl extends IBinderPool.Stub{
    
            @Override
            public IBinder queryBinder(int binderCode) throws RemoteException {
                IBinder binder = null;
                switch (binderCode){
                    case BINDER_SECURITY_CENTER:
                        binder = new SecurityCenerImpl();
                        break;
                    case BINDER_COMPUTE:
                        binder = new ComputeImpl();
                        break;
                }
                return binder;
            }
        }
    }
    // 7. 使用
    public class BinderPoolTestActivity extends AppCompatActivity {
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            doWork();
        }
    
        private void doWork() {
            BinderPool binderPool = BinderPool.getsInstance(this.getApplicationContext());
            IBinder securityCenterBinder = binderPool.queryBinder(BinderPool.BINDER_SECURITY_CENTER);
            ISecurityCenter securityCenter = SecurityCenerImpl.asInterface(securityCenterBinder);
            try {
                securityCenter.encrypt("");
            } catch (RemoteException e) {
                e.printStackTrace();
            }
            IBinder computeBinder = binderPool.queryBinder(BinderPool.BINDER_COMPUTE);
            ICompute compute = ComputeImpl.asInterface(computeBinder);
            try {
                compute.add(1,2);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    

    相关文章

      网友评论

          本文标题:IPC机制总结

          本文链接:https://www.haomeiwen.com/subject/ydodfftx.html