美文网首页
binder学习笔记

binder学习笔记

作者: 迦乐 | 来源:发表于2021-05-19 14:15 被阅读0次

    进程间通信方式

    • 1、为什么android需要采用binder
    bind1.png

    IPC

    bind4.png
    • 两次拷贝,先调用cope_form_user拷贝到缓存区,然后再拷贝到缓存区

    Bind

    bind5.png
    • 服务端和客户端都会映射到同一个空间
    • 通过mmap的内存映射,内核缓存区和服务端是两个都处于同一个空间
    • 共享内存是客户端,服务端和内核缓存区是处于一个空间,所以无需拷贝,问题是需要多次同步,所以存在问题
    • 很安全,APP是由系统分配UID的,并且支持实名

    AIDL

    自动生成的AIDL文件解析

    客户端

    public interface  ILeoAidl extends android.os.IInterface {
        /** 继承了binder 和aidl类  抽象类*/
        public static abstract class Stub extends android.os.Binder implements com.xx.leo_service.ILeoAidl{
        
            private static final java.lang.String DESCRIPTOR = "com.xx.leo_service.ILeoAidl";
                public Stub(){
            //
             this.attachInterface(this, DESCRIPTOR);
        }
        
    
        public static com.xx.leo_service.ILeoAidl asInterface(android.os.IBinder obj){
            //判断是否为空
            if ((obj==null)) {
              return null;
            }
            //查询本地的接口是否相等
          android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
            //如果在同一个进程,就直接返回,否则就代理
            if (((iin!=null)&&(iin instanceof com.xx.leo_service.ILeoAidl))) {
            //直接返回
                  return ((com.xx.leo_service.ILeoAidl)iin);
            }
            //返回代理
            return new com.xx.leo_service.ILeoAidl.Stub.Proxy(obj);
        }
        
        @Override 
        public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException   {
          switch (code)   {
        case TRANSACTION_addPerson:  {
            data.enforceInterface(DESCRIPTOR);
            com.xx.leo_service.Person _arg0;
            if ((0!=data.readInt())) {
            _arg0 = com.xx.leo_service.Person.CREATOR.createFromParcel(data);
        }  else {
            _arg0 = null;
        }
            this.addPerson(_arg0);
            reply.writeNoException();
            return true;
        }
        
        case TRANSACTION_getPersonList: {
            data.enforceInterface(DESCRIPTOR);
            java.util.List<com.xx.leo_service.Person> _result = this.getPersonList();
            reply.writeNoException();
            reply.writeTypedList(_result);
            return true;
        }
        }
             return super.onTransact(code, data, reply, flags);
        }
        
        //实体类 直接实现AIDL
        private static class Proxy implements com.xx.leo_service.ILeoAidl{
        private android.os.IBinder mRemote;
        Proxy(android.os.IBinder remote)   {
        mRemote = remote;
        }
        
        
        //直接实现自定义方法
        @Override 
        public void addPerson(com.xx.leo_service.Person person) throws android.os.RemoteException   {
            android.os.Parcel _data = android.os.Parcel.obtain();
            android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
            //校验,每个服务都有唯一的DESCRIPTOR
            _data.writeInterfaceToken(DESCRIPTOR);
            
            if ((person!=null)) {
                //传入数据  
                _data.writeInt(1);
                person.writeToParcel(_data, 0); 
              }else {
        _data.writeInt(0);
        }
            mRemote.transact(Stub.TRANSACTION_addPerson, _data, _reply, 0);
            _reply.readException();
        }
        finally {
            _reply.recycle();
            _data.recycle();
        }
        }
            @Override
            public java.util.List<com.xx.leo_service.Person> getPersonList() throws android.os.RemoteException {
                android.os.Parcel _data = android.os.Parcel.obtain();
                android.os.Parcel _reply = android.os.Parcel.obtain();
                java.util.List<com.xx.leo_service.Person> _result;
                try {
                //校验,每个服务都有唯一的DESCRIPTOR
                    _data.writeInterfaceToken(DESCRIPTOR);
                    //调用服务端的代码
                    mRemote.transact(Stub.TRANSACTION_getPersonList, _data, _reply, 0);
                    //读取看是否有
                    _reply.readException();
                    _result = _reply.createTypedArrayList(com.xx.leo_service.Person.CREATOR);
                }
                finally {
                    _reply.recycle();
                    _data.recycle();
                } 
                return _result;
                }
        }
        
        //传入一个整型,按顺序拿到方法
            static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            
    
            static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
        public void addPerson(com.xx.leo_service.Person person) throws android.os.RemoteException;
        
        public java.util.List<com.xx.leo_service.Person> getPersonList() throws android.os.RemoteException;
    }
    
    

    服务端

    public interface ILeoAidl extends android.os.IInterface {
        public void addPerson(com.xx.leo_service.Person person)
            throws android.os.RemoteException;
    
        public java.util.List<com.xx.leo_service.Person> getPersonList()
            throws android.os.RemoteException;
    
        /** L核心方法  stub*/
        public static abstract class Stub extends android.os.Binder implements com.xx.leo_service.ILeoAidl {
            private static final java.lang.String DESCRIPTOR = "com.xx.leo_service.ILeoAidl";
            static final int TRANSACTION_addPerson = (android.os.IBinder.FIRST_CALL_TRANSACTION +
                0);
            static final int TRANSACTION_getPersonList = (android.os.IBinder.FIRST_CALL_TRANSACTION +
                1);
    
            /** Construct the stub at attach it to the interface. */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
    
          public static com.xx.leo_service.ILeoAidl asInterface(
                android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
    
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    
                if (((iin != null) && (iin instanceof com.xx.leo_service.ILeoAidl))) {
                    return ((com.xx.leo_service.ILeoAidl) iin);
                }
    
                return new com.xx.leo_service.ILeoAidl.Stub.Proxy(obj);
            }
    
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            //对应客户端的onTransact方法
            @Override
            public boolean onTransact(int code, android.os.Parcel data,
                android.os.Parcel reply, int flags)
                throws android.os.RemoteException {
               //根据整型来拿到方法
                switch (code) {
    case TRANSACTION_addPerson: {
                    data.enforceInterface(DESCRIPTOR);
    
                    com.xx.leo_service.Person _arg0;
    
                    if ((0 != data.readInt())) {
                        _arg0 = com.xx.leo_service.Person.CREATOR.createFromParcel(data);
                    } else {
                        _arg0 = null;
                    }
    
                    this.addPerson(_arg0);
                    reply.writeNoException();
    
                    return true;
                }
    
                case TRANSACTION_getPersonList: {
                    data.enforceInterface(DESCRIPTOR);
    
                    java.util.List<com.xx.leo_service.Person> _result = this.getPersonList();
                    reply.writeNoException();
                    reply.writeTypedList(_result);
    
                    return true;
                }
                }
    
                return super.onTransact(code, data, reply, flags);
            }
    
     }
    }
    
    
    bind7.png

    ServiceManager

    我们自动生成的aidl和系统的服务是一一对应的。

    bind6.png

    ServiceManage负责管理所有的ServiceManager服务,在APP启动的时候,会调用电量,媒体等多个服务,都是通过binder来进行调用的,所有的服务端和客户端通信都是通过ServiceManager来注册和获取服务的。

    bind2.png

    A进程访问B进程时的几种状态

    1. 进程B,整个进程都没有启动
    2. 进程B启动了,但是里面的Service没创建出来
    3. 进程B启动了,里面的Service也创建了,但是Service没有被绑定过,回调onBind()
    4. 进程B启动了,里面的Service也创建了,但是Service已经被绑定过,回调onRebind()

    5个角度来分析Binder

    1. 从性能的角度 数据拷贝次数:Binder数据拷贝只需要一次,而管道、消息队列、Socket都需要2次,但共享内存方式一次内存拷贝都不需要;从性能角度看,Binder性能仅次于共享内存
    2. 从稳定性的角度
      • Binder是基于C/S架构的 C/S 相对独立,稳定性较好
      • 共享内存实现方式复杂,没有客户与服务端之别, 需要充分考虑到访问临界资源的并发同步问题,否则可能会出现死锁等问题
    3. 从安全的角度
      • 传统Linux IPC的接收方无法获得对方进程可靠的UID/PID,从而无法鉴别对方身份
        1. 传统IPC只能由用户在数据包里填入UID/PID
        2. 可靠的身份标记只有由IPC机制本身在内核中添加
        3. 传统IPC访问接入点是开放的,无法建立私有通道
      • Android为每个安装好的应用程序分配了自己的UID,故进程的UID是鉴别进程身份的重要标志,前面提到C/S架构,Android系统中对外只暴露Client端,Client端将任务发送给Server端,Server端会根据权限控制策略,判断UID/PID是否满足访问权限,目前权限控制很多时候是通过弹出权限询问对话框,让用户选择是否运行
      • Android的UID权鉴是如何做的?
    4. 从语言层面的角度
      • Linux是基于C语言(面向过程的语言),而Android是基于Java语言(面向对象的语句)
      • Binder恰恰也符合面向对象的思想 Binder模糊了进程边界,淡化了进程间通信过程,整个系统仿佛运行于同一个面向对象的程序之中
      • Android OS中的Zygote进程的IPC采用的是Socket(套接字)机制,Android中的Kill Process采用的signal(信号)机制等等。而Binder更多则用在system_server进程与上层App层的IPC交互。
    5. 从公司战略的角度
      总所周知,Linux内核是开源的系统,所开放源代码许可协议GPL保护,该协议具有“病毒式感染”的能力,怎么理解这句话呢?受GPL保护的Linux Kernel是运行在内核空间,对于上层的任何类库、服务、应用等运行在用户空间,一旦进行SysCall(系统调用),调用到底层Kernel,那么也必须遵循GPL协议。 而Android 之父 Andy Rubin对于GPL显然是不能接受的,为此,Google巧妙地将GPL协议控制在内核空间,将用户空间的协议采用Apache-2.0协议(允许基于Android的开发商不向社区反馈源码),同时在GPL协议与Apache-2.0之间的Lib库中采用BSD证授权方法,有效隔断了GPL的传染性,仍有较大争议,但至少目前缓解Android,让GPL止步于内核空间,这是Google在GPL Linux下 开源与商业化共存的一个成功典范。

    mmap:

    void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);

    • 1、在物理内存开辟物理区域(用于存储数据)
    • 2、将这个物理区域与磁盘进行映射
    • 3、将物理地址转化为虚拟地址,返回给应用层

    总结

    bind8.png

    相关文章

      网友评论

          本文标题:binder学习笔记

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