Android插件化基础--Binder机制

Binder是一套基于CS的架构。下面以一个极简的例子来学习Binder

1.首先定义一个IMedia.aidl文件。
interface IMedia {
    boolean start();
    boolean stop();
}
2.然后IDE会帮我们自动生成一个IMedia.java文件
public interface IMedia extends android.os.IInterface {

        public static abstract class Stub extends android.os.Binder implements com.cmeiyuan.pluginstudy.IMedia {
                
                public android.os.IBinder asBinder(){
                    return this;
                }
                
                public static com.cmeiyuan.pluginstudy.IMedia asInterface(android.os.IBinder obj) {
                    ...
                }
                
                public boolean onTransact(...){
                    ...
                    start();
                    ...
                }
                
                private static class Proxy implements com.cmeiyuan.pluginstudy.IMedia {
                    ...
                }
        }
    }
    public boolean start() throws android.os.RemoteException;
}

IMedia是一个继承于android.os.IInterface的接口,它的内部类Stub实现了android.os.IInterfaceasBinder()方法,直接返回了Sub类实例。我们继续看Sub类的asInterface()方法

public static com.cmeiyuan.pluginstudy.IMedia asInterface(android.os.IBinder obj) {
    if ((obj == null)) {
        return null;
    }
    android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
    if (((iin != null) && (iin instanceof com.cmeiyuan.pluginstudy.IMedia))) {
        return ((com.cmeiyuan.pluginstudy.IMedia) iin);
    }
    return new com.cmeiyuan.pluginstudy.IMedia.Stub.Proxy(obj);
}

这个方法的作用是将远程Binder对象转换为方便使用的IMedia接口对象,这个远程Binder对象是我们bindService()时返回的。首选通过obj.queryLocalInterface(DESCRIPTOR)查询是否有本地接口对象,这种情况是当Server端和Client端处于同一进程,没有必要进行多进程通信。如果没有本地接口对象,那么直接new一个Stub.Proxy(obj)实例返回。我们来看一下这个Proxy类的具体实现

private static class Proxy implements com.cmeiyuan.pluginstudy.IMedia {
    private android.os.IBinder mRemote;

    Proxy(android.os.IBinder remote) {
        mRemote = remote;
    }
    
    @Override
    public boolean start() throws android.os.RemoteException {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        boolean _result;
        try {
            _data.writeInterfaceToken(DESCRIPTOR);
            mRemote.transact(Stub.TRANSACTION_start, _data, _reply, 0);
            _reply.readException();
            _result = (0 != _reply.readInt());
        } finally {
            _reply.recycle();
            _data.recycle();
        }
        return _result;
    }
}

这个Proxy类是Stub类的内部类,其实就是对obj的一层封装(代理),那么我们通过这个代理类,就很容易和Server端进行通信了。具体实现也很简单,就是调用远程Binder对象mRemotetransact()方法,将数据发送给Server端。

Stub是一个抽象类,继承于Binder类,实现了父类的onTransact()方法,onTransact()方法的作用是执行Server端的操作,并将操作的结果返回给Client端。一般情况,我们需要写一个子类继承于Stub类,然后实现IMedia的接口方法,这些方法会被父类onTransact()方法调用到。

3.总结一下多进程通信过程:

(1)通过bindService()得到远程Binder对象obj
(2)通过IMedia.Stub.asInterface(obj)得到一个远程代理类Sub.Proxy对象mediaRemoteProxy
(3)调用mediaRemoteProxy.start()方法,事实上是调用了其内部远程Binder对象mRemotetransact()方法,将数据发送给Server
(4)服务端收到Client端发送过来的数据时onTransact()会被调用,有一个子类继承于IMedia.Stub类,实现了start()方法,onTransact()被调用时,自然调用到了子类里的start()方法。换言之,Server端的操作被Client调用执行了。

4.start()方法是在哪个线程被执行的
private IMedia.Stub stub = new IMedia.Stub() {
    @Override
    public boolean start() throws RemoteException {
        Log.d("cmy", "media start:" + Thread.currentThread().getId());
        return true;
    }
};

通过调试程序发现start()方法被执行在名为binder1binder2的线程中,而不是主线程。这也解释了系统的ActivityManagerService向应用进程发送消息时,需要使用H类把消息转发到UI线程,而且也必须这么做,因为UI线程调用了Looper.loop()开启了循环,线程是被阻塞的。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 原文:http://weishu.me/2016/01/12/binder-index-for-newer/ 要点...
    指尖流逝的青春阅读 2,618评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,924评论 18 139
  • 原文链接: http://weishu.me/2016/01/12/binder-index-for-newer/...
    miniminiming阅读 740评论 1 6
  • 毫不夸张地说,Binder是Android系统中最重要的特性之一;正如其名“粘合剂”所喻,它是系统间各个组件的桥梁...
    weishu阅读 17,943评论 29 246
  • 不知你有没有过这样的感觉,每每在一件事上追赶上别人,还没来得及兴奋和激动,就发现自己又落后了。 这种相比较的落后无...
    茶几酱阅读 241评论 0 0