Binder 驱动详解(上)

作者: SharryChoo | 来源:发表于2019-01-31 11:46 被阅读64次

    前言

    我们知道 Binder 驱动主要用于跨进程的通信, 它的身影出现在 Androrid 系统方方面面, 是 Android 系统框架中非常重要, 又非常难懂以搞懂的一部分

    关于 Binder 驱动, 以前看别人分享文章的时候, 很多都会在前面写上 "关于 Binder 驱动相关的知识, 我有些难以下笔", 今天产生整理这篇文章的时候, 笔者忽然之间感觉, 前辈们说的真是太有道理了, 忽然之间, 我也有些难以下笔, 因为它覆盖面太过于庞大了, 牵扯到了 应用开发层, Java 应用框架层, 运行时库层, HAL 层, 以及 Linux 内核层, 想要将之阐述清楚, 可真是不是一篇文章能够搞定的, 不过这里还是尝试写一写

    本文主要从以下几个方面阐述

    • Java 层通信实例
    • Binder 代理对象的创建
    • Binder 实体对象的创建

    一. Java 层的通信实例

    熟悉 Android 开发的我们都知道, 在 Android 项目中进行跨进程通信可以使用 AIDL 接口定义语言, 快捷生成相应的代码进行跨进程通信, 这里为了弄清楚代码生成背后故事, 我们手动实现一下

    服务提供接口

    /**
     * 定义一个服务的提供的功能接口
     *
     * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
     * @version 1.0
     * @since 2018/9/29 16:29
     */
    public interface IRemoteService extends IInterface {
    
        /*
          跨进程提供服务的接口描述
         */
        String DESCRIPTOR = IRemoteService.class.getName();
        /*
          跨进程提供服务的接口中 getServiceName 这个方法 Transaction id.
         */
        int TRANSACTION_getServiceName = (IBinder.FIRST_CALL_TRANSACTION + 0);
    
        String getServiceName() throws RemoteException;
    
    }
    

    服务实现类 和 Binder 实体对象

    /**
     * 接口 IRemoteService 在服务端的实现类
     * {@link #mBinder } 这个对象是让 IRemoteService 拥有跨进程提供数据能力的 Binder 本地实现类
     *
     * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
     * @version 1.0
     * @since 2018/9/29 17:48
     */
    public class RemoteServiceImpl implements IRemoteService {
    
        private IBinder mBinder;
    
        public RemoteServiceImpl(IBinder binder) {
            this.mBinder = binder;
        }
    
        @Override
        public String getServiceName() {
            return "This this RemoteService support function.";
        }
    
        @Override
        public IBinder asBinder() {
            return mBinder;
        }
    
    }
    
    /**
     * Service 端 Binder 实体对象实现类
     * 其向外提供的功能接口为 {@link IRemoteService}
     *
     * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
     * @version 1.0
     * @since 2018/9/28 20:50
     */
    public class RemoteServiceBinder extends Binder {
    
        /*
          持有其对应接口实现类的引用
         */
        private IRemoteService mImpl;
    
        public RemoteServiceBinder() {
            mImpl = new RemoteServiceImpl(this);
            // 调用了 attachInterface 之后, 父类 Binder 将会持有当前 IInterface 接口的描述
            // 在 onTransact 中 会自动处理 INTERFACE_TRANSACTION 类型的事务
            // 在 queryLocalInterface 中可以找到本地接口
            this.attachInterface(mImpl, mImpl.DESCRIPTOR);
        }
    
        @Override
        protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            switch (code) {
                // 调用了 attachInterface 之后, 父类会处理该类型的 code.
    //            case INTERFACE_TRANSACTION: {
    //                reply.writeString(DESCRIPTOR);
    //                return true;
    //            }
                case IRemoteService.TRANSACTION_getServiceName: {
                    data.enforceInterface(mImpl.DESCRIPTOR);
                    reply.writeNoException();
                    reply.writeString(mImpl.getServiceName());
                    return true;
                }
                default:
                    return super.onTransact(code, data, reply, flags);
            }
        }
    
    }
    

    好的, 可以看到这里定义了两个类, 它们分别是

    • RemoteServiceImpl: 远程服务的实现类
    • RemoteServiceBinder: IRemoteService 服务的 Binder 驱动

    可以发现 RemoteServiceImpl 与 RemoteServiceBinder 内部是相互持有对方引用的

    • RemoteServiceImpl 若未持有 IBinder 对象, 它仅仅是一个接口的实现类而已, 正是这个 IBinder 对象让它提供了跨进程通信的可能
    • 这里的 RemoteServiceBinder 对象它作用于服务端的实现接口, 我们称之为 Binder 实体对象

    实现客户端接口的代理实现类

    /**
     * 接口 IRemoteService 在客户端的代理实现类
     * {@link #mBinderProxy } 这个对象即 BinderProxy {@link android.os.Binder#BinderProxy} 实例的引用
     *
     * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
     * @version 1.0
     * @since 2018/9/29 16:36
     */
    public class RemoteServiceProxyImpl implements IRemoteService {
    
        private IBinder mBinderProxy;
    
        public RemoteServiceProxyImpl(IBinder binder) {
            mBinderProxy = binder;
        }
    
        @Override
        public String getServiceName() throws RemoteException {
            String result = null;
            Parcel data = Parcel.obtain();
            Parcel replay = Parcel.obtain();
            try {
                // 1. 写入调用方法所对应接口的描述
                data.writeInterfaceToken(DESCRIPTOR);
                // 2. 向 Service 端发起 invocation 请求
                mBinderProxy.transact(IRemoteService.TRANSACTION_getServiceName, data, replay, 0);
                // 3. 读取 Service 端扔出来的异常信息
                replay.readException();
                // 4. 读取异常结果
                result = replay.readString();
            } finally {
                replay.recycle();
                data.recycle();
            }
            return result;
        }
    
        @Override
        public IBinder asBinder() {
            return mBinderProxy;
        }
    
    }
    

    好的, 可以看到这里我们也创建了一个 IRemoteService 的实现类 RemoteServiceProxyImpl 从名字我们就可以知道它是 IRemoteService 接口的代理实现类, 相同的它内部也持有一个 IBinder 对象, 不过这里我们没有自己创建这个 IBinder 的实现类, **那这个 IBinder 实现类是谁呢? **, 其实我们无需为代理接口对象创建其特定的 BinderProxy 实现类, 因为系统给我们提供了, 这个 IBinder 的实现类其实是 android.os.BinderProxy: IBinder

    用于将 IBinder 转为接口的工具类

    /**
     * 用于将一个 Binder 对象转为对应的接口
     *
     * @author Sharry <a href="SharryChooCHN@Gmail.com">Contact me.</a>
     * @version 1.0
     * @since 2018/9/29 16:35
     */
    public class RemoteServiceUtils {
    
        /**
         * Cast an IBinder object into an com.frank.aidldemo.IServiceInteraction interface,
         * generating a proxy if needed.
         */
        public static IRemoteService asInterface(IBinder obj) {
            if (null == obj) {
                return null;
            }
            // 若想获取 Service 端 RemoteServiceImpl 对象, 需要在 Binder 本地对象构建时, 调用 attachInterface
            IInterface iin = obj.queryLocalInterface(IRemoteService.DESCRIPTOR);
            if (null != iin && iin instanceof IRemoteService) {
                return ((IRemoteService) iin);
            }
            return new RemoteServiceProxyImpl(obj);
        }
    
    }
    

    UML 图解析

    Binder 依赖类图.png

    二. Binder 实体对象的创建

    Binder(android.os.Binder: IBinder) 是 Binder 本地对象 Java 层的实现, 在 Server 端实例化, 对应我们上面的 RemoteServiceBinder, 它的作用是在 onTransact 中接收 Client 端通过 Binder 驱动传来的 IPC 请求, 并将请求结果通过 Binder 驱动返回给 Client 端

    接下来我们就看看如何实例化一个 Binder 实体对象

    创建一个 Binder 对象

    使用过 Service 的都知道, 在 onBind 中会 new 一个我们实现好的 Binder 对象

    public class RemoteService extends Service {
    
        public IBinder onBind(Intent intent) {
            return new RemoteServiceBinder();
        }
        
    }
    

    这个样子我们就创建了一个 Binder 本地对象, 我们看看他的构造方法

    public class Binder implements IBinder {
    
        private final long mObject;//
        
        /**
         * Binder.constructor
         */
        public Binder() {
            // 调用了 getNativeBBinderHolder 方法, 获取一个 Native 层的 BBinderHolder 对象句柄值
            mObject = getNativeBBinderHolder();
            ......
        }
        
        private static native long getNativeBBinderHolder();
        
    }
    

    可以看见 Binder 中主要调用了 native 方法, 获取了一个句柄值, 当然这个 mObject 句柄值也非常重要, 因为 Binder 类内部很多方法都是由它代理实现的

    getNativeBBinderHolder

    // frameworks/base/core/jni/android_util_Binder.cpp
    static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
    {
        // new 了一个 JavaBBinderHolder 这个对象
        JavaBBinderHolder* jbh = new JavaBBinderHolder();
        return (jlong) jbh;
    }
    

    非常简单的实现 new 了一个 JavaBBinderHolder 这个对象, 然后将它的句柄返回给 Java 中 Binder 对象的 mObject 属性, 接下来我们看看这个 JavaBBinderHolder 的构造函数中做了哪些操作

    // frameworks/base/core/jni/android_util_Binder.cpp
    class JavaBBinderHolder
    {
    public:
        // 获取 JavaBBinder 对象
        sp<JavaBBinder> get(JNIEnv* env, jobject obj)
        {
            AutoMutex _l(mLock);
            // 尝试将 mBinder 这个若指针升级为强指针
            sp<JavaBBinder> b = mBinder.promote();
            // 升级失败则重新创建 JavaBBinder 对象
            if (b == NULL) {
                b = new JavaBBinder(env, obj);
                mBinder = b;
            }
            // 返回一个 JavaBinder
            return b;
        }
    
    private:
        Mutex           mLock;   // 互斥锁
        wp<JavaBBinder> mBinder; // 一个 JavaBBinder 的弱指针
    };
    

    可以看到 JavaBBinderHolder 顾名思义果真持有了一个 JavaBBinder 的对象, 并且可以通过 get 方法获取到, 结下来看看这个 JavaBinder

    // frameworks/base/core/jni/android_util_Binder.cpp
    class JavaBBinder : public BBinder
    {
    public:
        // 构造函数
        JavaBBinder(JNIEnv* env, jobject /* Java Binder */ object)
            : mVM(jnienv_to_javavm(env)), mObject(env->NewGlobalRef(object))
        {
            ......
        }
    
        // 获取我们 Java 中实例化的 Binder 对象
        jobject object() const
        {
            return mObject;
        }
    
    protected:
        // Native 层 JavaBBinder 的 onTransact 函数
        virtual status_t onTransact(
            uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0)
        {   
            // 将 JavaVM convert2 JNIEnv
            JNIEnv* env = javavm_to_jnienv(mVM);
            // 回调 java 中 Binder 对象的 execTransact 方法
            jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
                code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
            
            // ......
            if (code == SYSPROPS_TRANSACTION) {
                // 回调父类的 onTransact 函数
                BBinder::onTransact(code, data, reply, flags);
            }
            
            return res != JNI_FALSE ? NO_ERROR : UNKNOWN_TRANSACTION;
        }
    
    private:
        JavaVM* const   mVM;      // JavaVM 指针对象, 用于转为 JNIEnv*
        jobject const   mObject;  // Java 中的 Binder 对象, 即我们在 Java 中创建的实例
    };
    

    看到 JavaBBinder 的实现, 一切就变得很明了了

    • JavaBBinder 继承了 BBinder , 它即是应用框架中的 Binder 本地对象
    • 可以看到构造函数中将我们 Java 中实例化的 Binder 对象传了近来, 保存在 JavaBBinder 的成员变量中

    如此一来, Binder 驱动发送的 IPC 请求, 就可以通过 JavaBBinder 的 onTransact 函数回溯到 Java 的 Binder 方法中了

    三. Binder 代理对象的创建

    BinderProxy(android.os.BinderProxy: IBinder) 是 Binder 代理对象 Java 层代理对象, 实现了 IBinder 接口, 它在 Client 进程实例化, 它的作用是让 Client 端调用 transact 方法通过 Binder 驱动向 Server 端发起 IPC 请求, 并等待 Server 端返回的结果, 接下来我们就看看它实例化的过程

    构造函数

        /**
         * BinderProxy.getInstance 是私有化的
         */
        private static BinderProxy getInstance(long nativeData, long iBinder) {
            BinderProxy result;
            ......
            result = new BinderProxy(nativeData);
            ......
            return result;
        }
    
        /**
         * BinderProxy 的构造方法也是私有化的
         */
        private BinderProxy(long nativeData) {
            mNativeData = nativeData;
        }
    

    可以看到 BinderProxy 这个 java 的 Class 两个获取实例的方式都是私有化的, 而且其构造方法的形参是一个 Native 指针的句柄值, 那么只有一种可能性, BinderProxy 这个对象是在 Native 层使用 JNI 实例化再返回 java 层的, 带着这个疑问我们去探究一下

    BinderProxy 对象的获取方式

    了解 Binder 驱动相关知识的小伙伴都知道, BinderProxy 一般可以通过两种方式来获取

    方式一

    我们在 Client 进程, 通过调用 Context.bindService(), 启动一个远程的 Service, 这时候需要需要传入一个 ServiceConnection 参数对象, 在其 onServiceConnected 方法中会收到一个 IBinder 对象的回调, 这个对象即为 BinderProxy, 如下图

       private val connect: ServiceConnection = object : ServiceConnection {
    
            override fun onServiceDisconnected(name: ComponentName?) {
    
            }
    
            override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
                // 这个 service 即一个 BinderProxy 的实例对象
            }
            
        }
    

    因为这里还会牵扯到 Service 的启动流程, 所以我们使用方式二的思路往下解析

    方式二

    通过 ServiceManager 获取一个系统注册好的服务, Activity 启动流程中的 AMS 相信大家再熟悉不过了, 看看它是如何获取的

        private static final Singleton<IActivityManager> IActivityManagerSingleton =
                new Singleton<IActivityManager>() {
                    @Override
                    protected IActivityManager create() {
                        final IBinder b = ServiceManager.getService(Context.ACTIVITY_SERVICE);
                        final IActivityManager am = IActivityManager.Stub.asInterface(b);
                        return am;
                    }
                };
    

    可以看到第二种方式是通过 ServiceManager.getService(Context.ACTIVITY_SERVICE) 获取的, 我们继续往下剖析

        /**
         * ServiceManager.getService 获取服务的 IBinder 对象
         */
        public static IBinder getService(String name) {
            try {
                // 尝试从缓存中获取
                IBinder service = sCache.get(name);
                if (service != null) {
                    return service;
                } else {
                    // 关注一下这个地方
                    // 1. getIServiceManager() 获取 IServiceManager 服务提供对象
                    // 2. 调用 IServiceManager.getService(name) 获取服务
                    return Binder.allowBlocking(getIServiceManager().getService(name));
                }
            } catch (RemoteException e) {
                Log.e(TAG, "error in getService", e);
            }
            return null;
        }
    

    可以看到 ServiceManager 其实是一个壳, 其方法的主要实现是通过 IServiceManager 实现的, 接下来我们看看 getIServiceManager 是如何获取 IServiceManager 对象的

        /**
         * ServiceManager.getIServiceManager
         */
        private static IServiceManager getIServiceManager() {
            if (sServiceManager != null) {
                return sServiceManager;
            }
            // 关注这里
            // 1. 这里通过 BinderInternal.getContextObject() 这个方法获取到了 BinderProxy 对象
            // 2. 通过 asInterface 将这个 BinderProxy 对象封装成了 ServiceManagerProxy 
            sServiceManager = ServiceManagerNative
                    .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
            return sServiceManager;
        }
        
        /**
         * BinderInternal.getContextObject 这就是获取 BinderProxy 对象的关键
         */
        public static final native IBinder getContextObject();
        
        /**
         * ServiceManagerNative.asInterface
         */
        static public IServiceManager asInterface(IBinder obj)
        {
            if (obj == null) {
                return null;
            }
            IServiceManager in =
                (IServiceManager)obj.queryLocalInterface(descriptor);
            if (in != null) {
                return in;
            }
            // 将 IBinder 对象封装成 ServiceManagerProxy 对象, 这个对象是 IServiceManager 提供给 Client 端使用的实现类
            return new ServiceManagerProxy(obj);
        }
        
    }
    

    我们看到了一个非常重要的线索 BinderInternal.getContextObject() 这是一个非常关键的方法, 系统就是通过它获取了 IServiceManager 的 Binder 代理对象

    至此 Java 层的旅程就告一段落了, 接下来附上一张 ServiceManager 在 java 层的关系依赖图

    ServiceManager .png

    接下来我们就要深入到 Native 层去看看 BinderInternal.getContextObject() 的实现了

    BinderInternal.getContextObject()

    // frameworks/base/core/jni/android_util_Binder.cpp
    static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
    {
        // 调用了 ProcessState 的 getContextObject 获取一个句柄值为 NULL 的 IBinder 对象
        sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
        // 调用 javaObjectForIBinder 返回一个 Java 中的 Binder 对象
        return javaObjectForIBinder(env, b);
    }
    

    可以看到 Native 层中的 getContextObject 中主要做了两步操作

    • 通过 ProcessState->getContextObject(NULL) 获取了一个 IBinder 对象
      • 若为 ServiceManger 的创建进程, 则为 BBinder 本地对象
      • 若非创建进程, 则为 BpBinder 代理对象
    • 通过 javaObjectForIBinder 这个方法获取 Java 的代理对象
    // frameworks/base/core/jni/android_util_Binder.cpp
    jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
    {
        if (val == NULL) return NULL;
    
        // 若为本地对象, 则返回 Java 中的 Binder 对象
        // 很显然这个 val 为 BpBinder, 我们关注下面的代码
        if (val->checkSubclass(&gBinderOffsets)) {
            jobject object = static_cast<JavaBBinder*>(val.get())->object();
            return object;
        }
    
        // 互斥锁
        AutoMutex _l(mProxyLock);
    
        // 1. 判断是否已经为当前驱动创建了 BinderProxy 对象了
        jobject object = (jobject)val->findObject(&gBinderProxyOffsets);
        if (object != NULL) {
            // 通过引用升级的方式, 判断这个 BinderProxy 对象是否有效
            jobject res = jniGetReferent(env, object);
            if (res != NULL) {
                // 若有效则返回到 java 层
                return res;
            }
            ......
            // 若无效则解除这个对象与 BpBinder 的关联
            val->detachObject(&gBinderProxyOffsets);
            ......
        }
        // 2. 这里通过 JNI 的方式调用了 BinderProxy 的构造函数
        object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
        if (object != NULL) {
            // 3. 给 BinderProxy 中的 mObject 对象赋值, 值为 BpBinder 的句柄
            // 如此一来 Java 中的 BinderProxy 就可以通过它找到 BpBinder 了
            env->SetLongField(object, gBinderProxyOffsets.mObject, (jlong)val.get());
            val->incStrong((void*)javaObjectForIBinder);
            // 4. 将这个 BinderProxy 缓存到 BpBinder 中
            jobject refObject = env->NewGlobalRef(
                    env->GetObjectField(object, gBinderProxyOffsets.mSelf));
            val->attachObject(&gBinderProxyOffsets, refObject,
                    jnienv_to_javavm(env), proxy_cleanup);
            ......
        }
    
        return object;
    }
    

    可以看到这个方法中做了如下几件事情

    • 若 val 为 BBinder, 则返回其关联的 Java 层的 Binder 对象
    • 若 val 为 BpBinder
      • 从缓存中查找对应的 BinderProxy 对象, 若有效则返回给 Java 层
      • 若无效则通过 JNI 实例化一个 BinderProxy 对象
        • 给 BinderProxy.mObject 赋值, 指向 Native 层对应的 BpBinder 对象
        • 将这个 BinderProxy 对象加入 BpBinder 的缓存

    至此 Java 中的 BinderProxy 就在 Native 层创建出来了

    总结

    好的分析到这里我们知道了 Binder 实体对象与 代理对象的实例化过程, 并且也悄悄的解开了 Binder 驱动在应用框架层的面纱

    • 在 Client 端
      • Binder 提供了 BinderProxy 对象
      • BinderProxy 对象对应 Binder运行时库中的 BpBinder
    • 在 Service 端
      • Binder 提供了 Binder 对象, 需要根据接口我们自行实现
      • Binder 对象对应了 Binder 运行时库中的 BBinder

    好的, 至此 Binder 驱动的上篇就结束了, 下篇中会着重分析 Binder 运行时库和一次 Binder 通信的流程

    相关文章

      网友评论

        本文标题:Binder 驱动详解(上)

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