深入Android系统(三)Binder-2-使用

如何使用 Binder

就开发语言而言,Binder服务可以用Java实现,也可以用C++实现,通常,我们在Java代码中调用Java语言实现的服务,在C++代码中调用C++编写的服务。但是从原理上讲,Binder并没有这种语言平台的限制,混合调用也是可以的。

应用可以在任意的进程和线程中使用Binder服务的功能,非常方便、灵活。也不用关心同步、死锁等问题

使用Binder服务

C++层和Java层使用Binder服务的方式基本一样,包括函数的接口类型都相同,这里以C++为例:

  • 使用Binder服务前要先得到它的引用对象,比如:

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService("serviceName");

    • defaultServiceManager()用来获得ServiceManager服务的Binder引用对象。前面已经说过ServiceManagerBinder引用对象是直接用数值0作为引用号构造出来的
    • sm->getService("media.camera")是查找注册的Binder服务,找到后会返回服务的IBinder对象,否则返回NULL
  • 返回的IBinder对象,其实是Binder引用对象,但是应用需要使用的是Binder代理对象,因此需要进行如下转化:

    ICameraService service = ICameraService.Stub.asInterface(binder)

    • 话说这部分应该是Java的转换方式,换成C++的版本应该是

    sp<ICameraService> service = ICameraService::asInterface(binder)

  • Binder中提供了asInterface方法来完成Binder代理对象的转换,asInterface会检查参数中的IBinder对象的服务类型是否相符,如果不符将返回NULL

正常情况下,ServiceManager进程会在所有应用启动前启动,而且不会停止服务,因此使用defaultServiceManager()不必检查返回为NULL的情况,但是对于方法getService()的返回值需要检查是否为NULL,因为服务可能不存在或者未启动。

Binder的混合调用

Binder是可以混合调用的,在C++中可以调用Java实现的Binder服务,在Java中也可以调用C++实现的Binder服务

ActivityManagerService服务为例,其中定义的方法为

public int checkPermission(String permission, int pid, int uid, int mode);

,我们看下C++调用的大体流程(有注释哈):

//获取Binder引用对象
sp<Binder> binder = defaultServiceManager()->getService("activity");
//创建Parcel data 放置方法调用是的参数信息
Parcel data = Parcel.obtain();
//创建Parcel reply 接收返回信息
Parcel reply = Parcel.obtain();
//添加接口识别Token
data.writeInterfaceToken("android.app.IActivityManager");
//添加请求的权限、pid、uid、mode等方法调用信息
data.writeString16(permission);
data.writeInt32(pid);
data.writeInt32(uid);
data.writeInt32(mode);
//调用远程函数号为54的远程服务
binder->transact(54, data, &reply, 0);

示例代码中最重要的是54这个参数,叫做远程函数号。这个号码在服务端代码中定义,而且随着系统版本不同可能会有所改变,所以示例方法并不是一个很科学和常用的方法,不要学坏哈。只是想说明Binder很强大。。。

Java层的Binder服务

我们先用组件Service来回顾一下流程:

首先,编写一个AIDL文件

interface ICommandService {
    void setResult_bool(String cmdid, boolean result);
    void setResult_byte(String cmdid, in byte[] resultMsg);
    void setResult_string(String cmdid, String resultMsg);
    void finishCommand(String cmdid, String param);
}

然后,我们创建一个自定义的Service,然后这样写:

public class CommandService extends Service{
    protected final ICommandService.Stub mBinder = new ICommandService.Stub() {
        @Override
        public void setResult_bool(String cmdid, boolean result) throws RemoteException {
            //do something
        }
        @Override
        public void setResult_byte(String cmdid, byte[] resultMsg) throws RemoteException {
            //do something
        }
        @Override
        public void setResult_string(String cmdid, String resultMsg) throws RemoteException {
            //do something
        }
        @Override
        public void finishCommand(String cmdid, String param) throws RemoteException {
            //do something
        }
    };
    @Override
    public IBinder onBind(Intent intent) {
        //do something
        return mBinder;
    }
}

ICommandService.Stub类就是真正的Binder服务类,它是通过我们前面定义的AIDL文件自动生成的,不过它是抽象的,所以我们需要继承并重写自己的业务逻辑。

C++层的Binder服务

C++层实现Bidner服务比较麻烦,主要是没有了AIDL的辅助,需要我们手动完成中间层的代码。

书中的源码部分看的有些没太看懂,本人从9.0项目源码中找了一份,我们来看下:

温馨提示:下面代码中会出现继承BnInterfaceIInterfaceBpInterface的操作,以及DECLARE_META_INTERFACEIMPLEMENT_META_INTERFACE两个宏,这里暂不做详细解释,后面会有Binder应用层的核心类详解。我们暂先理解为:继承BnInterface为实现服务端功能、继承BpInterface为实现客户端、继承IInterface表示定义要提供的服务接口

首先,是一个IImagePlayerService.h的头文件,定义了:

  • IImagePlayerService:通过纯虚函数函数定义计划提供的Binder服务接口
  • BnImagePlayerService:根据IImagePlayerService中提供的接口,定义对应的枚举对象;重载onTransact()虚拟函数

我们看下代码:

    class IImagePlayerService: public IInterface {
      public:
        DECLARE_META_INTERFACE(ImagePlayerService);
        
        virtual int init() = 0;
        virtual int start() = 0;
        virtual int release() = 0;
        virtual int setTranslate(float tx, float ty) = 0;
    };
    class BnImagePlayerService: public BnInterface<IImagePlayerService> {
      public:
        enum {
            IMAGE_INIT = IBinder::FIRST_CALL_TRANSACTION,
            IMAGE_START,
            IMAGE_RELEASE,
            IMAGE_SET_TRANSLATE,
        };
        virtual status_t onTransact(uint32_t code, const Parcel& data,
                                    Parcel* reply, uint32_t flags = 0);
    };

IImagePlayerService.h这部分的意思大概是:我们自己的Binder服务要提供哪些功能,先把这部分定义出来。

我们再来看下IImagePlayerService.h的实现IImagePlayerService.cpp的内容:

    class BpImagePlayerService : public BpInterface<IImagePlayerService> {
      public:
        BpImagePlayerService(const sp<IBinder>& impl)
            : BpInterface<IImagePlayerService>(impl) {
        }
        virtual int init() {
            Parcel data, reply;
            data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
            remote()->transact(BnImagePlayerService::IMAGE_INIT, data, &reply);
            return NO_ERROR;
        }
        virtual int start() {
            Parcel data, reply;
            data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
            remote()->transact(BnImagePlayerService::IMAGE_START, data, &reply);
            return NO_ERROR;
        }
        virtual int release() {
            Parcel data, reply;
            data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());
            remote()->transact(BnImagePlayerService::IMAGE_RELEASE, data, &reply);
            return NO_ERROR;
        }
        virtual int setTranslate(float tx, float ty) {
            Parcel data, reply;
            data.writeInterfaceToken(IImagePlayerService::getInterfaceDescriptor());

            data.writeFloat(tx);
            data.writeFloat(ty);
            remote()->transact(BnImagePlayerService::IMAGE_SET_TRANSLATE, data, &reply);
            return NO_ERROR;
        }
    };
    
    IMPLEMENT_META_INTERFACE(ImagePlayerService, "droidlogic.IImagePlayerService");
    
    status_t BnImagePlayerService::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
        switch (code) {
            case IMAGE_INIT: {
                CHECK_INTERFACE(IImagePlayerService, data, reply);
                int result = init();
                reply->writeInt32(result);
                return NO_ERROR;
            }
            case IMAGE_START: {
                CHECK_INTERFACE(IImagePlayerService, data, reply);
                int result = start();
                reply->writeInt32(result);
                return NO_ERROR;
            }
            case IMAGE_RELEASE: {
                CHECK_INTERFACE(IImagePlayerService, data, reply);
                int result = release();
                reply->writeInt32(result);
                return NO_ERROR;
            }
            case IMAGE_SET_TRANSLATE: {
                CHECK_INTERFACE(IImagePlayerService, data, reply);
                int result = setTranslate(data.readFloat(), data.readFloat());
                reply->writeInt32(result);
                return NO_ERROR;
            }
            default: {
                return BBinder::onTransact(code, data, reply, flags);
            }
        }
        // should be unreachable
        return NO_ERROR;
    }

IImagePlayerService.cpp 做了这几件事情:

  • 实现BnImagePlayerService类的onTransact函数。
    • BnImagePlayerService类的对象实例会运行在服务进程中
    • onTransact函数在运行时会被底层的IPCThreadState类调用。
    • 函数实现比较公式化,根据参数中的函数号来调用对应的函数。
    • 函数中的CHECK_INTERFACE用来检查Parcel对象中的数据是否正确
      • 检查原理是先取出Parcel对象中客户端传来的类描述字符串
      • 与当前类中定义的字符串比较,相同则正确
    • 然后按照函数参数的排列顺序取出参数,并使用这些参数调用服务端的函数
      • 可以参考case IMAGE_SET_TRANSLATE
  • 定义BpImagePlayerService类。
    • Binder服务在客户端的接口类
    • BpImagePlayerService类的对象实例会运行在客户端的进程中
    • 继承BpInterface<IImagePlayerService>
    • 实现IImagePlayerService中定义的纯虚函数,把函数调用的信息发送给远端
      • data.writeInterfaceToken把类的描述字符串放到Parcel
      • 通过remote()函数得到Binder引用对象的指针
      • 调用Binder引用对象transact()函数把数据传给底层
      • IBindertransact()函数其实有4个参数,由于第四个参数flags定义了默认值0,因此调用transact()常常只使用3个参数。
      • 如果客户端调用Binder服务是不打算等待对方运行结束就继续执行,可以使用TF_ONE_WAY作为第四个参数以异步的方式调用Binder服务。这种方式也就意味着无法得到返回值了。

会不会有个疑惑IImagePlayerService.cpp为什么把这两个类定义在一起来?

  • 主要原因是两个类中都是用了相同的函数号码和类的描述字符串。如果分开,需要维护两份,容易失误

到这里和Binde服务相关的定义就结束了,接下来就是最后一步了,实现我们Binder服务的业务逻辑了,我们看下ImagePlayerService.h的头文件定义

    class ImagePlayerService :  public BnImagePlayerService {
      public:
        ImagePlayerService();
        virtual ~ImagePlayerService();

        virtual int init();
        virtual int start();
        virtual int release();
        virtual int setTranslate(float tx, float ty);
    };

这里我们需要注意的是继承BnImagePlayerService。具体函数的实现其实在ImagePlayerService.cpp完成:

int ImagePlayerService::init() {
    //.....
}
//.....省略部分方法
int ImagePlayerService::setTranslate(float tx, float ty) {
    //.....
}

书中并没有定义头文件,直接做了服务类的实现。

到这里C++版本的Binder服务就完成了,我们看下整体代码结构:
image

Google的HIDL

不过,上面的这种操作已经过OUT,Android 从8.0开始做了架构调整(一个称为Treble的模式),增加了HIDL接口定义语言进行HAL层和应用层的解耦合优化。

HAL 接口定义语言(简称 HIDL,发音为“hide-l”)是用于指定 HAL 和其用户之间的接口的一种接口描述语言 (IDL)。HIDL 允许指定类型和方法调用(会汇集到接口和软件包中)。从更广泛的意义上来说,HIDL 是用于在可以独立编译的代码库之间进行通信的系统。

HIDL 旨在用于进程间通信 (IPC)。进程之间的通信采用 Binder 机制。对于必须与进程相关联的代码库,还可以使用直通模式(在 Java 中不受支持)。

从介绍来看,HIDLBinder机制的基础上增加了一个直通模式,这部分暂不深入深究哈,当前紧要任务还是看完Binder的核心实现,官方传送门:HIDL

暂且把它当成和AIDL一样的接口定义语言就好,只是AIDL用与Java层的服务实现,而HIDL用于C++层的服务实现。

应用层的核心类

前面我们了解了Binder的使用,都是基于libbinder库来实现的,我们看下libbinder库中的一些核心类,源码位置:frameworks/native/libs/binder

libbinder库中的IInterface类、BpInterface类、BnInterface类、BBinder类、BpBinder类、IBinder类共同构成了Binder应用层的核心类。

IInterface类中的两个宏

C++层Binder服务实现中,还有一些知识没有细说,包括IInterface接口类、BpInterface模板类、BnInterface模板类,以及宏DECLARE_META_INTERFACE和宏IMPLEMENT_META_INTERFACE

我们先来看下宏DECLARE_META_INTERFACE的定义:

#define DECLARE_META_INTERFACE(INTERFACE)                               \
    static const ::android::String16 descriptor;                        \
    static ::android::sp<I##INTERFACE> asInterface(                     \
            const ::android::sp<::android::IBinder>& obj);              \
    virtual const ::android::String16& getInterfaceDescriptor() const;  \
    I##INTERFACE();                                                     \
    virtual ~I##INTERFACE();            

这个宏定义了一些成员变量和方法,在类中使用这个宏就意味着将这些成员变量和方法加入到了这个类中。转换逻辑也比较简单,##INTERFACE替换成传入的参数即可,对于前面的例子,相当于添加了如下代码:

    static const ::android::String16 descriptor;
    static ::android::sp<IImagePlayerService> asInterface(
            const ::android::sp<::android::IBinder>& obj);
    virtual const ::android::String16& getInterfaceDescriptor() const;
    IImagePlayerService();
    virtual ~IImagePlayerService();  

这里添加了静态成员变量descriptor、静态函数asInterface,以及类构造函数析构函数。可能这些变量和函数是每个Binder服务必须实现的,为了方便开发,Android把它们定义成了宏。

我们再来看下宏IMPLEMENT_META_INTERFACE的定义:

#define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
    const ::android::String16 I##INTERFACE::descriptor(NAME);           \
    const ::android::String16&                                          \
            I##INTERFACE::getInterfaceDescriptor() const {              \
        return I##INTERFACE::descriptor;                                \
    }                                                                   \
    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != NULL) {                                              \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == NULL) {                                         \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \
    I##INTERFACE::I##INTERFACE() { }                                    \
    I##INTERFACE::~I##INTERFACE() { }                                   \

对于实例代码中的

IMPLEMENT_META_INTERFACE(ImagePlayerService, "droidlogic.IImagePlayerService");

则会转换为:

    const ::android::String16 IImagePlayerService::descriptor("droidlogic.IImagePlayerService");
    const ::android::String16&
            IImagePlayerService::getInterfaceDescriptor() const {
        return IImagePlayerService::descriptor;
    }
    ::android::sp<IImagePlayerService> IImagePlayerService::asInterface(
            const ::android::sp<::android::IBinder>& obj)
    {
        ::android::sp<IImagePlayerService> intr;
        if (obj != NULL) {
            intr = static_cast<IImagePlayerService*>(
                obj->queryLocalInterface(
                        IImagePlayerService::descriptor).get());
            if (intr == NULL) {
                intr = new BpImagePlayerService(obj);
            }
        }
        return intr;
    }
    IImagePlayerService::IImagePlayerService() { }
    IImagePlayerService::~IImagePlayerService() { }    
  • 变量descriptor是一个字符串,用来描述Bidner服务。在检查客户端传来的参数是否合法时会用到。
  • 函数asInterface主要用来把Binder引用对象转换为Binder代理对象。这个函数很关键,但我们目前还不能看明白,先记住这个方法,我们继续学习核心类。

Binder核心类的关系

我们先来看下核心类的继承关系图:
image

继承关系中虚线代表了什么?

上图中实线表示的继承关系可以从源码中找到,关键是虚线的继承部分,没有找到明显的继承关系,我们根据示例代码来分析下。

我们看下BnInterface的定义先:

template<typename INTERFACE>
class BnInterface : public INTERFACE, public BBinder
{
public:
    virtual sp<IInterface>      queryLocalInterface(const String16& _descriptor);
    virtual const String16&     getInterfaceDescriptor() const;

protected:
    typedef INTERFACE           BaseInterface;
    virtual IBinder*            onAsBinder();
};

这是一个模板类,而在C++版本Binder服务中,我们的类是这样定义的:

class IImagePlayerService: public IInterface{};
class BnImagePlayerService: public BnInterface<IImagePlayerService>{};

对于模板类BnInterface,我们使用的时候要给一个INTERFACE,也就是IImagePlayerService

其实很像Java的泛型不是?

我们看到,模板类BnInterface的定义中,类继承部分是这样写的:

class BnInterface : public INTERFACE, public BBinder

而对于示例代码中的BnInterface<IImagePlayerService>则意味BnInterface会把IImagePlayerService当做INTERFACE继承,也就转化为

class BnInterface : public IImagePlayerService, public BBinder

IImagePlayerService又是继承自IInterface

所以模板类BnInterface最后还是会继承IInterface,可能这层关系有些隐晦,所以就用虚线表示了。同样BpInterface也是如此。

一张更容易理解的核心类图

image

图解一:BpInterfaceBpBinder的聚合关系

这张图中,多了一个BpInterfaceBpBinder的聚合关系,我们通过源码来认识下:

首先是BpInterface模板类的定义:

template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
    explicit                    BpInterface(const sp<IBinder>& remote);

protected:
    typedef INTERFACE           BaseInterface;
    virtual IBinder*            onAsBinder();
};

我们这次重点关注的是:

  • 显式构造函数BpInterface(const sp<IBinder>& remote)
    • 传入了一个IBinder类型的指针,其实就是BpBinder
    • 这个指针会在父类BpRefBase的构造函数中做一系列的处理
    • 很多远程方法调用都是使用这个BpBinder
  • 继承类BpRefBase
    • 真正关联BpBinder的操作
    • 主要成员mRemote,一个指向IBinder的指针
    • 定义了remote()方法

我们看下BpRefBase类的部分信息:

class BpRefBase : public virtual RefBase
{
protected:
    explicit                BpRefBase(const sp<IBinder>& o);
    virtual                 ~BpRefBase();
    //......
    inline  IBinder*        remote()                { return mRemote; }
private:
    //......
    IBinder* const          mRemote;
    //......
};
图解二:服务端的调用逻辑

BnInterface类是开发Binder服务必须继承的一个模板类,它继承BBinder的同时也继承了IInterface类(这部分的继承逻辑前面已经细讲了哈)。

BBinder是服务端的核心,实际的函数实现都在BBinder的继承类中。先看下BBinder的部分函数定义:

class BBinder : public IBinder
{
public:
    //......
    virtual const String16& getInterfaceDescriptor() const;
    virtual bool        isBinderAlive() const;
    virtual status_t    pingBinder();
    virtual status_t    dump(int fd, const Vector<String16>& args);

    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    transact(   uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0) final;
    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    linkToDeath(const sp<DeathRecipient>& recipient,
                                    void* cookie = nullptr,
                                    uint32_t flags = 0);
    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t    unlinkToDeath(  const wp<DeathRecipient>& recipient,
                                        void* cookie = nullptr,
                                        uint32_t flags = 0,
                                        wp<DeathRecipient>* outRecipient = nullptr);
//......
};

BBinder负责和更底层的IPCThread打交道。但是,当Binder调用Binder驱动传递过来时,IPCThread会调用BBindertransact()函数,然后transact()函数会调用继承类的onTransact()函数。

这部分其实要和IPCThread结合起来看,先跟着书本走吧,等下返个场,哈哈

图解三:客户端的调用逻辑

BpBinder类是客户端Binder的核心,也是继承自IBinder类。我们在图解一已经说过:BpInterface类并不是从BpBinder类继承来的,而是继承自BpRefBaseBpBinderBpInterface聚合关系

这么做是主要是为了:

  • 使得上层开发更加灵活
  • Binder的内部实现和上层应用完全隔离开,用户类完全不知道BpBinder的存在
  • BpBinder改动了,用户类不用重新编译也能运行

BpBinder负责和更底层的IPCThread打交道。客户端通过remote()->transact(...)调用IBindertransact虚函数,实际调用的是BpBindertransact函数。transact函数会调用IPCThread类的函数来向驱动传递数据。

Binder类继承关系的总结

  • 从继承关系上看IBinderBBinderBpBinder的基类。
  • 在应用层看见的只是IBinderBBinderBpBinder都藏在后面
    • 这样在概念上就统一了
    • Binder的使用角度,不用刻意地区分当前对象是实体对象还是引用对象
    • 只要获得IBinder对象,就可以使用服务
  • IBinder中有两个接口,localBinderremoteBinder,从返回值我们就可以知道他们代表的Binder服务对象了:
    • virtual BBinder* localBinder();
    • virtual BpBinder* remoteBinder();
    • 对于服务端,Binder服务就在本进程中,可以用localBinder获取IBinder对象,而remoteBinder则会返回NULL
    • 对于客户端,Binder服务在其他进程中,可以用remoteBinder获取IBinder对象,而localBinder则会返回NULL
    • 如果想确定一个IBInder对象到底是BpBinder还是BBinder对象时,通过这两个接口就可以判断

函数asInterface的奥秘

理解了Binder核心类关系后,我们再来看下asInterface()函数

asInterface()函数就是把Binder引用对象转换成代理对象的关键,asInterface()函数的宏定义如下:

    ::android::sp<I##INTERFACE> I##INTERFACE::asInterface(              \
            const ::android::sp<::android::IBinder>& obj)               \
    {                                                                   \
        ::android::sp<I##INTERFACE> intr;                               \
        if (obj != nullptr) {                                           \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == nullptr) {                                      \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    } 

上面代码中变量obj的类型是IBinder,但是obj是参数,它既可能是BpBinder对象,也可能是BBinder对象,判断逻辑如下:

  • 如果obj传入的是一个BpBinder对象
    • BpBinder类中没有重载queryLocalInterface函数,因此,调用的是其基类IBinder的函数,直接返回sp<NULL>
    • 通过sp<NULL>.get结果还是NULL
    • 所以intrNULL
    • 这样接下来就会new一个Bp##INTERFACE对象
  • 如果obj传入的是一个BBinder对象,在这种情形下,因为继承关系,BBinder对象同时也会是一个BnInterface对象,在BnInterface类中重载了queryLocalInterface函数,代码如下:
    template<typename INTERFACE>
    inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
            const String16& _descriptor)
    {
        if (_descriptor == INTERFACE::descriptor) return this;
        return nullptr;
    }
    
    • 如果参数传递的描述字符串和类的描述字符串相同,则返回this指针,也就是obj本身
    • 否则,返回NULL

asIntreface函数的作用总结如下:

  • 在客户端调用asInterface,会创建一个Binder代理对象,代理对象中包含了Binder引用对象
  • 在服务端调用asInterface,直接返回参数的指针。因为在服务进程中可以直接调用服务类,无需创建Binder代理对象

Binder的死亡通知

作为Binder服务的提供者,Binder实体对象也会死亡,可能是正常退出,也可能是意外崩溃。一旦实体对象死亡,Binder引用对象需要有机制来得到通知。

注册接收Binde的死亡通知

IBinder中提供了一个纯虚函数linkToDeath,定义如下:

    virtual status_t        linkToDeath(const sp<DeathRecipient>& recipient,
                                        void* cookie = nullptr,
                                        uint32_t flags = 0) = 0;

函数具体实现暂不深究,我们看下使用方式:

class HeapCache : public IBinder::DeathRecipient
{
public:
    HeapCache(sp<IBinder> binder){
        mService=binder
    };
    virtual void binderDied(const wp<IBinder>& who);

private:
    wp<IBinder> mService;
};
void HeapCache::binderDied(const wp<IBinder>& binder)
{
    //死亡会调用此方法
}

在继承DeathRecipient类中需要重载binderDied函数,当Binder服务死亡时,这个函数会被回调。

linkToDeath函数会调用IPCThreadState的函数来告诉驱动需要接收某个Binder服务死亡的通知消息,我们看下BpBinder的相关代码:

status_t BpBinder::linkToDeath(
    const sp<DeathRecipient>& recipient, void* cookie, uint32_t flags)
{
    //......
    IPCThreadState* self = IPCThreadState::self();
    self->requestDeathNotification(mHandle, this);
    self->flushCommands();
    //......
}

发送Binder死亡通知

一旦驱动检测到某个Binder服务已经死亡,会根据设置向应用层发送消息,IPCThreadState中检测到死亡消息后,利用保存在消息中的BpBinder的指针,调用其sendObituary函数,IPCThreadState.cpp中代码定义如下:

    case BR_DEAD_BINDER:
        {
            BpBinder *proxy = (BpBinder*)mIn.readPointer();
            proxy->sendObituary();
            mOut.writeInt32(BC_DEAD_BINDER_DONE);
            mOut.writePointer((uintptr_t)proxy);
        } break;

sendObituary函数的主要工作是调用reportOneDeath函数通知上次应用,代码定义如下:

void BpBinder::sendObituary()
{
    //......
    //这部的代码没看懂是干啥用的
    Vector<Obituary>* obits = mObituaries;
    if(obits != nullptr) {
        ALOGV("Clearing sent death notification: %p handle %d\n", this, mHandle);
        IPCThreadState* self = IPCThreadState::self();
        self->clearDeathNotification(mHandle, this);
        self->flushCommands();
        mObituaries = nullptr;
    }
    //这部的代码没看懂是干啥用的
    //......
    
    const size_t N = obits->size();
    for (size_t i=0; i<N; i++) {
        reportOneDeath(obits->itemAt(i));
    }
    //......
}
void BpBinder::reportOneDeath(const Obituary& obit)
{
    sp<DeathRecipient> recipient = obit.recipient.promote();
    ALOGV("Reporting death to recipient: %p\n", recipient.get());
    if (recipient == nullptr) return;

    recipient->binderDied(this);
}

监听死亡通知对象都被保存在了Vector类型的成员变量mObituaries中,然后通过循环来调用reportOneDeath通知所有对象。

而在reportOneDeath函数中把弱引用转变成强引用后再调用binderDied

到这里就和注册接收Binde的死亡通知的操作接上拉。

Java 层的 Binder 类

了解了C++层Binder类体系后,我们再来看下Java层提供的Binder体系。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mfKoORTU-1599285250647)(http://cdn.hualee.top/Java%E5%B1%82Binder%E7%B1%BB%E5%9B%BE.png)]
Java层Binder虽然设计了自己的框架,但最后还是通过native层BpBinderBBinderJava层Binder框架C++层的原理是一样的,而且Java层可以通过AIDL来生成相关的细节代码,所以我们这次重点关注:Java框架是通过什么方式和C++中的BpBinderBBinder关联起来的?

Java 层的 Binder 服务类

开发一个Java服务,必须继承android.os.Binder类。Binder类中最重要的成员变量如下:

public class Binder implements IBinder {
    //......
    private final long mObject;
    private IInterface mOwner;
    private String mDescriptor;
    //......
    
    public Binder(@Nullable String descriptor)  {
        //获取 JavaBBinderHolder 类的实例
        mObject = getNativeBBinderHolder();
        //registerNativeAllocation 是在 Android8.0(API27)引入的一种辅助回收native内存的机制,本身并不复杂,抽个时间好好看看它
        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mObject);
        //......
        mDescriptor = descriptor;
    }
}

static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    return (jlong) jbh;
}
  • mObject 存放的是native层关联对象额指针
  • mOwner 存放的是Binder继承类的引用,实际上就是 Java Binder对象本身
  • mDescriptor 存放的是类的描述字符串

android.os.Binder类在构造方法中会通过getNativeBBinderHolder()本地方法获取JavaBBinderHolder类的实例,并把指针保存在Java层mObject变量中。我们看下JavaBBinderHolder是干啥的:

class JavaBBinderHolder
{
public:
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            //......
            mBinder = b;
            //......
        }

        return b;
    }
    //......
private:
    Mutex           mLock;
    wp<JavaBBinder> mBinder;
    //......
};

JavaBBinderHolder类在第一次调用get函数时创建一个JavaBBinder对象,并通过mBinder保存JavaBBinder对象的弱引用。而JavaBBinder是从BBinder类继承过来的,我们看下JavaBBinder的核心定义:

class JavaBBinder : public BBinder
{
    //......
    status_t onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) override
    {
        JNIEnv* env = javavm_to_jnienv(mVM);

        IPCThreadState* thread_state = IPCThreadState::self();
        const int32_t strict_policy_before = thread_state->getStrictModePolicy();

        jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
            code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
    }
    
private:
    JavaVM* const   mVM;
    jobject const   mObject;  // GlobalRef to Java Binder
    //......
};
  • mVM 保存的是Java虚拟机的指针
  • mObject 保存的是android.os.Bindernative层JNI对象,就是调用JavaBBinderHolderget函数是参入的jobject obj参数

到这里,我们就可以梳理出Java层native层Binder服务关系:

  • 首先,Java层Binder对象在构造方法中,通过JNI调用,是的mObject属性,持有了nativeJavaBBinderHolder对象的指针
  • 而在JavaBBinderHolder中,mBinder变量持有一个JavaBBinder对象的弱引用
  • JavaBBinder继承自BBinder,并重写了onTransact
    • onTransact方法中会通过JNI调用Java层android.os.BinderexecTransact方法

Java层的Binder引用类

应用在Java层调用Binder的操作同样也是通过Binder代理对象来完成的,和C++中一样,代理对象的生成也是通过接口类中的asIntreface方法来完成。Java中的接口类一般都可以通过AIDL自动生成。格式如下:

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

这个asIntreface方法的逻辑其实和C++中的asIntreface一样:

  • 先通过queryLocalInterface方法的返回值判断传入的参数是否是在服务端调用传入的Binder服务对象,如果是直接返回该对象
  • 否就就认为objBinder引用对象,这时需要新创建一个Binder代理对象,也就是return new com.example.factory.ICommandService.Stub.Proxy(obj);
    • com.example.factory.ICommandService.Stub.Proxy就是AIDL自动生成的代理对象。这个类实现了ICommandService接口
    • 这样对于应用开发,只需要关系ICommandService接口包含了哪些方法即可,真正实现细节无需关心。
      • 只能说Binder设计的很是巧妙,整个体系在功能实现上基本形式化了
  • Java层Binder代理对象实现的思路和C++层如出一辙,可以阅读源码frameworks/base/core/java/android/os/*Binder*来加深印象

我们再来看下asInterface方法的参数android.os.IBinder obj,通常情况我们都是通过ServiceManagergetService方法来得到这个IBinder对象,我们看下getService的部分代码(由于和Android 5.0不太一样,加注释了哟):

//Android 9 的这部分源码和书中有些不同,不过原理性的东西还是一样的
    //file::ServiceManager.java
    public static IBinder getService(String name) {
        try {
            // 查看缓存
            IBinder service = sCache.get(name);
            if (service != null) {
                // 有缓存,直接返回缓存对象
                return service;
            } else {
                // allowBlocking是在设置mWarnOnBlocking属性,看样子是将属性设置为可接受不受信任代码的调用
                // 真正获取Binder对象的是rawGetService
                // rawGetService 最后调用了 ServiceManagerNative的getService()
                //真正触发binder通信并获取到binder对象的,就是在ServiceManagerNative中
                return Binder.allowBlocking(rawGetService(name));
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
    //file::Binder.java
    //建议看看英文注释吧,木有完全理解。
    public static IBinder allowBlocking(IBinder binder) {
        try {
            if (binder instanceof BinderProxy) {
                //仅仅在binder对象是客户端时进行设置
                ((BinderProxy) binder).mWarnOnBlocking = false;
            } else if (binder != null && binder.getInterfaceDescriptor() != null
                    && binder.queryLocalInterface(binder.getInterfaceDescriptor()) == null) {
                Log.w(TAG, "Unable to allow blocking on interface " + binder);
            }
        } catch (RemoteException ignored) {
        }
        return binder;
    }
    
    //file::ServiceManager.java
    private static IBinder rawGetService(String name) throws RemoteException {
        //......
        final IBinder binder = getIServiceManager().getService(name);
        //忽略很多代码
        return binder;
    }
    //file::ServiceManager.java
    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        // 最后执行到了ServiceManagerNative
        sServiceManager = ServiceManagerNative
                .asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
        return sServiceManager;
    }

再看下ServiceManagerNative的部分代码,已添加注释:

    //file::ServiceManagerNative.java
    public IBinder getService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        //设置要获取的Binder服务的描述符
        data.writeInterfaceToken(IServiceManager.descriptor);
        //设置要获取的Binder服务的名称
        data.writeString(name);
        //通过 transact 发送Binder请求,怎么发送的据说后面原理会讲到
        // GET_SERVICE_TRANSACTION 就是获取特定binder服务请求号
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        
        //通过Parcel类的readStrongBinder来获得IBinder对象
        //readStrongBinder是一个本地方法,它的实现是nativeReadStrongBinder
        //然后调用到了android_os_Parcel_readStrongBinder
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }
    
    //file::android_os_Parcel.cpp
    //方法中的 parcel->readStrongBinder() 会返回一个C++层的IBinder对象
    //这个C++层的IBinder对象怎么创建的据说后面原理部分会讲
    //javaObjectForIBinder则根据C++层的IBinder对象创建一个Java层的BinderProxy对象
    static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

javaObjectForIBinder实现了在native层创建Java类实例,我们仔细看下这个神奇的方法:

// android_util_binder.cpp
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {
        // 如果是JavaBBinder 说明在服务端,直接返回该对象
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    // For the rest of the function we will hold this lock, to serialize
    // looking/creation/destruction of Java proxies for native Binder proxies.
    //加锁
    AutoMutex _l(gProxyLock);

    // 查看缓存中是否存在 BinderProxyNativeData,没有就新建
    // BinderProxyNativeData就是一结构体,存放了BpBinder的指针和对应注册Binder服务死亡通知的对象List的指针
    BinderProxyNativeData* nativeData = gNativeDataCache;
    if (nativeData == nullptr) {
        nativeData = new BinderProxyNativeData();
    }
    // gNativeDataCache is now logically empty.
    // 通过JNI调用CallStaticObjectMethod创建BinderProxy对象
    // 这里的JNI调用其实就是在调用Java层BinderProxy类的getInstance方法
    // getInstance 需要传入long nativeData, long iBinder两个指针
    // 所以,在创建完Java层的BinderProxy对象后,它已经持有了BpBinder和BinderProxyNativeData的指针
    jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
            
    if (env->ExceptionCheck()) {
        //异常检查
        // In the exception case, getInstance still took ownership of nativeData.
        gNativeDataCache = nullptr;
        return NULL;
    }
    //通过 getBPNativeData 获取object对象中的mNativeData字段的数据
    //并转化为BinderProxyNativeData指针
    BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        // 两个指针相等
        // New BinderProxy; we still have exclusive access.
        // 新建死亡通知注册表
        nativeData->mOrgue = new DeathRecipientList;
        // 把 mObject 指针指向 传入的IBiner,也就是BpBinder
        nativeData->mObject = val;
        gNativeDataCache = nullptr;
        //.....
    } else {
        // nativeData wasn't used. Reuse it the next time.
        gNativeDataCache = nativeData;
    }

    return object;
}

经过这个方法的操作,Java层获得了一个在native层创建的BinderProxy实例,同时也关联上了BpBinder对象。

如果从Java调用Binder服务,会使用BinderProxy类的transact方法,这最后也是调用了一个本地方法,我们看下实现:

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
        jint code, jobject dataObj, jobject replyObj, jint flags) // throws RemoteException
{
    //......
    //省略参数合法性判断
    //......
    
    // 获取 BpBinder 指针
    IBinder* target = getBPNativeData(env, obj)->mObject.get();
    
    //......
    
    // 执行 BpBinder 的 transact
    status_t err = target->transact(code, *data, reply, flags);
    
    //......
}

中期总结

学习到这里,我们了解了如何使用Binder以及Binder的一些基本知识

  • 数据通信通过Parcel来传递
  • 对于客户端
    • 客户端可以通过linkToDeath来注册监听服务端的死亡通知
    • 不管是从C++还是Java的客户端调用,都会走到BpBinder这里
    • 客户端触发Binder调用的操作是BpBindertransact
    • BpBindertransact调用的是IPCThreadState::self()->transact()
  • 对于服务端
    • AIDL支持的Java层,在服务端的业务实现上很简单
    • 支持HIDLC++,在实现上也变得比较容易
    • 不管是C++还是Java,最后都是通过继承BBinder来实现
    • onTransact中实现不同方法调用的case

但是,我还有这么几个疑问:

  • 客户端transact后是怎么通知到服务端的?
  • 服务端reply.write*怎么把数据给到客户端的?
  • onTransact在什么时候被调用的?
  • 服务端何时启动运行的呢?

那我们就带着疑问,继续学习Binder的实现原理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值