美文网首页
andorid:Binder机制学习笔记

andorid:Binder机制学习笔记

作者: 你在心上_b28f | 来源:发表于2019-05-26 12:09 被阅读0次

    一、概念
    1.从IPC角度来说,binder是一种跨进程通讯的方式
    2.从Android Frameworke角度来说:ServiceManager连接各种Manager(ActivityManager、windowManager等等)和相应ManagerService的桥梁
    3.从Android应用层来说:binder是客户端和服务端通讯的媒介,bindService的时候,服务端会返回一个包含了服务端业务调用的Binder对象,客户端可以获取服务端提供的服务或者数据,这里的服务包括普通服务和基于AIDL的服务

    二、分析
    Android开发中,Binder主要用再Service中,包括AIDL和Messager,普通的service中不涉及进程间通讯,无法触及Binder的核心。Messager的底层是AIDL,所以可以分析AIDL来分析Binder的工作过程。

    在定义了aidl接口的时候,系统会为我们为生成binder的工具类
    eg:IBookManager.aidl---->IBookManager.java

    接着我们可以分析IBookManager.java这个类就能知道Binder的工作原理

    package com.yicooll.aidldemo.aidl;
    
    public interface IBookManager extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.yicooll.aidldemo.aidl.IBookManager {
            private static final java.lang.String DESCRIPTOR = "com.yicooll.aidldemo.aidl.IBookManager";
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.yicooll.aidldemo.aidl.IBookManager interface,
             * generating a proxy if needed.
             */
            public static com.yicooll.aidldemo.aidl.IBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.yicooll.aidldemo.aidl.IBookManager))) {
                    return ((com.yicooll.aidldemo.aidl.IBookManager) iin);
                }
                return new com.yicooll.aidldemo.aidl.IBookManager.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_getBookList: {
                        data.enforceInterface(descriptor);
                        java.util.List<com.yicooll.aidldemo.aidl.Book> _result = this.getBookList();
                        reply.writeNoException();
                        reply.writeTypedList(_result);
                        return true;
                    }
                    case TRANSACTION_addBook: {
                        data.enforceInterface(descriptor);
                        com.yicooll.aidldemo.aidl.Book _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = com.yicooll.aidldemo.aidl.Book.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        this.addBook(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                    default: {
                        return super.onTransact(code, data, reply, flags);
                    }
                }
            }
    
            private static class Proxy implements com.yicooll.aidldemo.aidl.IBookManager {
                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.
                 *//*  void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);*/
                @Override
                public java.util.List<com.yicooll.aidldemo.aidl.Book> getBookList() throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    java.util.List<com.yicooll.aidldemo.aidl.Book> _result;
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        mRemote.transact(Stub.TRANSACTION_getBookList, _data, _reply, 0);
                        _reply.readException();
                        _result = _reply.createTypedArrayList(com.yicooll.aidldemo.aidl.Book.CREATOR);
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                    return _result;
                }
    
                @Override
                public void addBook(com.yicooll.aidldemo.aidl.Book book) 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 ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
            static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         *//*  void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
                double aDouble, String aString);*/
        public java.util.List<com.yicooll.aidldemo.aidl.Book> getBookList() throws android.os.RemoteException;
    
        public void addBook(com.yicooll.aidldemo.aidl.Book book) throws android.os.RemoteException;
    }
    

    IBookManager方法,变量进行说明

    1.DESCRIPTOR
    binder的唯一标识,一般用当前的类名表示eg:com.yicooll.aidl.IBookManager

    2.asInterface(android.os.IBinder obj)
    服务端的Binder对象转换成客户端所需的AIDL接口类型对象,转换过程区分进程。
    如果客户端和服务端是位于同一进程,方法返回服务端stub对象本身,否则返回系统封装的Stub.proxy对象

    3.asBinder
    返回当前Binder对象

    4.onTransact(int code,android.os.Parcel data,android.os.Parce reply,int flags)
    运行在服务端的Binder线程池中,客户端发起跨进程请求时,远程请求会通过系统底层封装后交由此方法处理,code 确定请求的目标方法,data取出目标方法的参数(有参数的情况下),当目标方法执行完毕后,向reply中写入返回值

    5.Proxy#getBookList 代理对象中的具体方法,也是aidl中定义的接口方法,这里就用getBookList来说明
    该方法调用在客户端,客户端远程调用的时候会创建所需要的输入型Parcel对象_data,
    输出型Parcel对象_reply和返回值对象list,并将方法参数写入_data(如果有参数)
    接着调用transact方法来发起RPC(远程过程调用)请求,同时当前线程挂起。服务端的onTransact方法会被调用,直到RPC过程返回后,当前线程继续执行,并从_reply中取出RPC的放回结果,最后返回_reply中的数据

    流程图如下


    binder机制png.png

    三、Binder运行在服务端进程,如果服务端进程由于某种原因异常终止,binder连接就会断裂,binder提供了两个重要方法解决这个问题,linkToDeath、和unLinkToDeath.
    可以通过binder设置死亡代理,binder死亡的时候,会受到通知,重新发起连接请求而恢复连接。

    private IBinder.DeathRecipient mDeathRecipient=new IBinder.DeathRecipient(){
          @Override
          public void binderDied(){
            if(mBookManager==null)
                return ;
      mBookManager.asBinder().unlinkToDeath(DeathRecipient,0)
      mBookManager=null
      //TODO:这里重新绑定远程Service  
       }
    }
    

    其次,在客户端绑定远程服务成功后,给binder设置死亡代理

    mService=IMessageBoxManager.Stub.asInterface(binder);
    binder.linkToDeath(DeathRecipient,0)
    

    binderDied是进程保活的一种,还有一种是onServiceDisConnected
    binderDied()是运行在binder线程池中,不能访问Ui
    onServiceDisConnected是运行在客户端UI线程

    相关文章

      网友评论

          本文标题:andorid:Binder机制学习笔记

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