美文网首页Android
Android Binder解析

Android Binder解析

作者: 漆先生 | 来源:发表于2022-03-11 16:54 被阅读0次

    Binder是Android中一种跨进程通信方式,还可以理解为一种虚拟的物理设备,它的设备驱动是/dev/binder。
    从Framework角度来说,Binder又是ServiceManager连接各种Manager和相应ManagerService的桥梁,从应用层来说,它是客户端和服务端进行通信的媒介,绑定服务的时候服务端会返回一个包含服务端业务调用的Binder对象,通过这个Binder对象,客户端就可以获取服务端提供的服务或者数据。

    一、创建AIDL

    //Book.java
    package com.qijinfeng.jvm;
    
    import android.os.Parcel;
    import android.os.Parcelable;
    
    class Book implements Parcelable {
        public int bookId;
        public String bookName;
    
        protected Book(Parcel in) {
            bookId = in.readInt();
            bookName = in.readString();
        }
    
        @Override
        public int describeContents() {
            return 0;
        }
    
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(bookId);
            dest.writeString(bookName);
        }
    
        public static final Creator<Book> CREATOR = new Creator<Book>() {
            @Override
            public Book createFromParcel(Parcel in) {
                return new Book(in);
            }
    
            @Override
            public Book[] newArray(int size) {
                return new Book[size];
            }
        };
    }
    
    //Book.aidl
    package com.qijinfeng.jvm;
    parcelable Book;
    
    //IBookManager.aidl
    package com.qijinfeng.jvm;
    import com.qijinfeng.jvm.Book;
    
    
    interface IBookManager {
        void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);
        List<Book> getBookList();
        void adddBook();
    }
    

    二、内部方法解析

    build/generated/aidl_source_output_dir/debug/out目录下会自动生成一个IBookManager.java文件,它继承了IInterface接口。

    IBookManager.java里边声明了两个方法getBookList和addBook

      public java.util.List<com.qijinfeng.jvm.Book> getBookList() throws android.os.RemoteException;
      public void adddBook() throws android.os.RemoteException;
    

    同时声明了两个整型的id,标识两个方法,用于在transact过程中判断客户端发送请求的到底是哪个方法。

        static final int TRANSACTION_getBookList = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
        static final int TRANSACTION_adddBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
    

    声明了一个内部类Stub,是一个Binder派生类,客户端和服务端都位于同一个进程时,方法不会走跨进程transact过程,而当连着处于不同的进程,就会走transact过程,这个邮它的内部类Proxy来完成。

     public static abstract class Stub extends android.os.Binder implements com.qijinfeng.jvm.IBookManager
      {
        private static class Proxy implements com.qijinfeng.jvm.IBookManager
        {
        }
      }
    

    1.DESCRIPTOR

    Binder的唯一标识,一般用单签Binder的类名标识。

        private static final java.lang.String DESCRIPTOR = "com.qijinfeng.jvm.IBookManager";
    

    2.asInterface(android.os.IBinder obj)

    用户将服务端的Binder对象转换陈客户端所需的AIDL对象,这种转换是区分进程的,同一进程返回的是服务端的Stub对象本身,否则是系统封装后的Stub.proxy对象。

    3.asBinder()

    返回当前的Binder对象。

    4.onTransact

    这个方法运行于服务端的Binder线程池中,当客户端发起跨进程请求时,远程请求会通过系统底层封装后交由次方法来处理。参数code确定客户端的请求目标方法,参数data存放数据,请求完成后,reply中写入返回值,onTransact如果返回false,客户端会请求失败,可以用这个特性来做权限验证。

    5.Proxy#getBookList和Proxy#addBook

    这个方法运行在客户端,当客户端远程调用次方法时。

    • 先创建方法需要的输入性Parcel对象_data,输出型Parcel对象_reply和返回对象
    • 然后把该方法的参数信息写书_data
    • 调用transact方法发起RPC请求,同时线程挂起
    • 服务器会调用onTransact方法
    • 直到RPC请求返回,当前线程继续执行
    • 从_reply中取出RPC的返回结果,最后返回reply中的数据。
    image.png

    6.linkToDeath和unlinkToDeath

    Binder运行于服务端,可能由于某种原因异常终止,这个时候我们到服务端的Binder连接已经断裂。会导致调用远程失败,客户端功能受到影响。
    Binder中提供linkToDeath和unlinkToDeath方法,通过linkToDeath给Binder设置死亡代理,当Binder死亡时,我们会收到用纸,就可以重新发起连接请求,从而恢复连接。

    class MainActivity2 : AppCompatActivity() {
    
        var mIBookManager: IBookManager? = null
    
        val mConn = object : ServiceConnection {
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                mIBookManager = IBookManager.Stub.asInterface(service);
                try {
                    service!!.linkToDeath(mDeathRecipient!!, 0);
                } catch (e: RemoteException) {
                    e.printStackTrace()
                }
            }
    
            override fun onServiceDisconnected(name: ComponentName?) {
    
            }
        }
        var mDeathRecipient: IBinder.DeathRecipient? = null
    
    
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main2)
    
            mDeathRecipient = IBinder.DeathRecipient {
                if (mIBookManager == null)
                    return@DeathRecipient
                mIBookManager!!.asBinder().unlinkToDeath(mDeathRecipient!!, 0);
                mIBookManager = null
                val intent = Intent(this, BookService::class.java)
                bindService(intent, mConn, AppCompatActivity.BIND_AUTO_CREATE);
            }
            val intent = Intent(this, BookService::class.java)
            bindService(intent, mConn, BIND_AUTO_CREATE);
        }
    
        override fun onDestroy() {
            unbindService(mConn)
            super.onDestroy()
        }
    
    

    三、Binder连接池

    Binder连接池的主要作用是将每个业务模块请求统一发到远程Service中去执行,从而避免重复创建Service的过程。


    image.png

    1.创建两个或者多个AIDL接口

    ISecurityCenter.aidl

    interface ISecurityCenter {
        String encrypt(String content);
        String decrypt(String password);
    }
    

    IComputer .aidl

    interface IComputer {
        int add(int a,int b);
    }
    

    2.实现AIDL接口

    SecurityCenterImpl.java

    public class SecurityCenterImpl extends ISecurityCenter.Stub {
       private static final char SECRET_CODE = '^';
        @Override
        public String encrypt(String content) throws RemoteException {
            char[] chars = content.toCharArray();
            for (int i = 0; i < chars.length; i++) {
                chars[i] ^=SECRET_CODE;
            }
            return new String(chars);
        }
    
        @Override
        public String decrypt(String password) throws RemoteException {
            return encrypt(password);
        }
    }
    

    ComputerImpl.java

    public class ComputerImpl extends IComputer.Stub {
        @Override
        public int add(int a, int b) throws RemoteException {
            return a + b;
        }
    }
    

    3.创建Binder连接池AIDL

    interface IBinderPool {
        IBinder queryBinder(int binderCode);
    }
    

    4.创建Service

    class BinderPoolService : Service() {
        private val mBinderPool = BinderPool.BinderPoolImpl()
        override fun onBind(intent: Intent?): IBinder? {
            return mBinderPool
        }
    }
    

    Binder连接池实现

    public class BinderPool {
        public static final int BINDER_NONE = -1;
        public static final int BINDER_COMPUTE = 0;
        public static final int BINDER_SECURITY_CENTER = 1;
    
        private Context mContext;
        private IBinderPool mBinderPool;
        private static volatile BinderPool mInstance;
        private CountDownLatch mConnectBinderPoolCountDownLatch;
    
        private BinderPool(Context context) {
            mContext = context.getApplicationContext();
            connectBinderPoolService();
        }
    
        public static BinderPool getInstance(Context context) {
            if (mInstance == null) {
                synchronized (BinderPool.class) {
                    if (mInstance == null) {
                        mInstance = new BinderPool(context);
                    }
                }
            }
            return mInstance;
        }
    
        private synchronized void connectBinderPoolService() {
            mConnectBinderPoolCountDownLatch = new CountDownLatch(1);
            Intent intent = new Intent(mContext, BinderPoolService.class);
            mContext.bindService(intent, mBindPoolConnection, Context.BIND_AUTO_CREATE);
            try {
                mConnectBinderPoolCountDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    
        public IBinder queryBinder(int binderCode) {
            IBinder binder = null;
            if (mBinderPool != null) {
                try {
                    binder = mBinderPool.queryBinder(binderCode);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
            return binder;
        }
    
        private ServiceConnection mBindPoolConnection = 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();
                }
                mConnectBinderPoolCountDownLatch.countDown();
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
                System.out.println("123456"+name);
            }
        };
    
        private IBinder.DeathRecipient mBinderPoolDeathRecipient = () -> {
            mBinderPool.asBinder().unlinkToDeath(mInstance.mBinderPoolDeathRecipient, 0);
            mBinderPool = null;
            connectBinderPoolService();
        };
    
        public static class BinderPoolImpl extends IBinderPool.Stub {
    
            public BinderPoolImpl(){
                super();
            }
    
            @Override
            public IBinder queryBinder(int binderCode) {
                IBinder binder = null;
                switch (binderCode) {
                    case BINDER_SECURITY_CENTER:
                        binder = new SecurityCenterImpl();
                        break;
                    case BINDER_COMPUTE:
                        binder = new ComputerImpl();
                        break;
                    default:
                        break;
                }
                return binder;
            }
        }
    }
    

    首先去绑定服务,绑定服务后,客户端可以通过它的queryBinder方法区获取各自对应的Binder。
    通过CountDownLatch将bindService这一异步的操作转换成同步操作。Binder的调用过程可能是耗时的,因此不建议在主线程执行。
    BinderPool可以方便日常AIDL的开发,如果需要添加新的AIDL,只需要实现自己的AIDL之后,把BinderPoolImpl中的queeyBinder方法进行修改,添加一个新的binderCode并返回对应的Binder对象即可。

    相关文章

      网友评论

        本文标题:Android Binder解析

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