Binder & Ashmem

221 阅读3分钟

设计思路

基于代理的思想,用户无需关心底层实现细节,驱动层实现了内存一次拷贝以及FD、Binder句柄的传递

接口设计

IBinder:transact、remoteBinder、localBinder、queryLocalInterface


class IInterface : public virtual RefBase
{
public:
    IInterface();
    static sp<IBinder>  asBinder(const IInterface*);
    static sp<IBinder>  asBinder(const sp<IInterface>&);
protected:
    virtual                     ~IInterface();
    virtual IBinder*            onAsBinder() = 0;
};


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();
};


template<typename INTERFACE>
class BpInterface : public INTERFACE, public BpRefBase
{
public:
    explicit                    BpInterface(const sp<IBinder>& remote);
protected:
    typedef INTERFACE           BaseInterface;
    virtual IBinder*            onAsBinder();
};


#define DECLARE_META_INTERFACE(INTERFACE)                               \
public:                                                                 \
    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();                                            \


#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 != nullptr) {                                           \
            intr = static_cast<I##INTERFACE*>(                          \
                obj->queryLocalInterface(                               \
                        I##INTERFACE::descriptor).get());               \
            if (intr == nullptr) {                                      \
                intr = new Bp##INTERFACE(obj);                          \
            }                                                           \
        }                                                               \
        return intr;                                                    \
    }                                                                   \


class IAudioManager : public IInterface
{
public:
    DECLARE_META_INTERFACE(AudioManager)

    virtual audio_unique_id_t trackPlayer(player_type_t playerType) = 0;
    /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
    virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
    /*oneway*/ virtual status_t releaseRecorder(audio_unique_id_t riid) = 0;
};


class BpAudioManager : public BpInterface<IAudioManager>
{
public:
    explicit BpAudioManager(const sp<IBinder>& impl)
        : BpInterface<IAudioManager>(impl)
    {
    }
    ...
}
IMPLEMENT_META_INTERFACE(AudioManager, "android.media.IAudioService");

image.png

驱动原理

BpBinder -> handle -> binder_ref -> binder_node -> BBinder

image.png

涉及到Flat_binder数据结构(Binder、FD),内核自动转换

ProcessState

打开Binder驱动文件、设置mmap共享内存(1M - 8K)、保存进程内的所有BpBinder对象、扩展Binder线程

IPCThreadState

使用ioctl和驱动通信:常见的协议格式有:

#define BINDER_WRITE_READ             _IOWR('b', 1, struct binder_write_read)
#define BINDER_SET_IDLE_TIMEOUT       _IOW('b', 3, int64_t)
#define BINDER_SET_MAX_THREADS        _IOW('b', 5, size_t)
#define BINDER_SET_IDLE_PRIORITY      _IOW('b', 6, int)
#define BINDER_SET_CONTEXT_MGR        _IOW('b', 7, int)
#define BINDER_THREAD_EXIT            _IOW('b', 8, int)
#define BINDER_VERSION                _IOWR('b', 9, struct binder_version)

其中还涉及到BC、BR命令,以及是否等待的逻辑(BR_TRANSACTION_COMPLETE、BR_REPLY)

一次拷贝原理

mmap时,内核保存各个进程的地址控件和内核空间的对应关系,当执行数据传递时,发送端会将数据写入到目标进程对应的内核控件,然后根据偏移量返回目标进程的用户空间地址

匿名内存原理

进程A打开ashmem驱动并获取到FD,当通过Binder传递对应FD时,驱动会在目标进程空间创建指向相同文件节点的句柄。当执行mmap时,如果没有创建file文件,则创建对应文件,如果已创建则复用,然后将vm_area_struct的vm_file指针指向真正操作的file

Binder线程

RuntimeInit.zygoteInit时初始化Binder环境:

nativeZygoteInit();
    virtual void onZygoteInit() {
        sp proc = ProcessState::self();
        //启动新binder线程loop
        proc->startThreadPool();
    }
applicationInit(targetSdkVersion, argv);

参考文献