Binder系统分析之Native层、framework层使用

上篇文章中,我们详细的了解了AIDL的使用流程。其关键点在于对系统编译生成的AIDL生成中间文件中Binder类以及IBinder接口的实现。系统提供的这两个类很关键,下面我们分别从Native层以及framework实现一下自定义的Binder程序。

在Native层实现Binder

Binder基于C/S架构,在这里,我们需要分别实现Server端和Client端,提取出公共的接口文件IService。同时还要注意几个关键类,他们在Binder实现中起到了关键作用,下面会具体介绍。源码程序参考罗升阳博客内的代码,删减了其内部打开设备,获取寄存器值等相关逻辑,还是很有参考性的。

项目基本文件结构

由源码目录层级展示如下:

  • 公共接口文件

    /external/binder/common
        IFregService.h
        IFregService.cpp
    
  • 服务端程序

    /external/binder/server
        FregService.cpp
        Android.mk
    
  • 客户端程序

    /external/binder/client
        FregClient.cpp
        Android.mk
    

Server端实现

FregServer.cpp
#define LOG_TAG "FregServer"
#include <stdlib.h>
#include <fcntl.h>
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include <binder/IPCThreadState.h>
#include "../common/IFregService.h"
#define FREG_DEVICE_NAME "/dev/freg"

// 实现Binder的本地对象FregService的具体实现,实现了IFregService接口
// 具体的Server端模块实现
class FregService : public BnFregService
{
public:
    // 构造函数实现
    FregService(){
    }

    // 析构函数
    virtual ~FregService(){
    }

public:
    // 讲台初始化函数
    static void instantiate()
    {
        // 获取ServiceManager,注册Server端服务FREG_SERVICE(shy.luo.FregService)
        defaultServiceManager()->addService(String16(FREG_SERVICE), new FregService());
    }

    // 方法的具体实现,由IFregService中父类传递调用,读取寄存器值
    int32_t getVal(){
        return mVal;
    }

    // 同上方法,设置寄存器值
    void setVal(int32_t val){
            mVal = val;
    }

private:
    int mVal = 100;
};

// 主程序
int main(int argc, char** argv)
{
    // 初始化
    FregService::instantiate();
    // 获取进程,开启Binder线程池
    ProcessState::self()->startThreadPool();
    // 获取线程,加入到Binder线程池中
    IPCThreadState::self()->joinThreadPool();
    return 0;
}

程序相关说明如下:

  1. FregService继承于BnFregService,BnFregService会在后面接口文件中涉及
  2. defaultServiceManager()用来获取系统服务关系程序ServiceManager,其是Binder架构中的上下文管理者,任何服务都要先在其中注册,然后再从中获取到对应服务的代理对象,完成相应逻辑
  3. addService()向SM注册服务,传入服务的描述名和服务对象,以便SM为其分配代理对象等
  4. ProcessState::self()用于获取本地进程,内部使用单例模式,返回本地进程
  5. startThreadPool开启本进程的线程池服务,用于等待客户端请求通知
  6. IPCThreadState::self()获取进程对应的当前线程,joinThreadPool则是将当前线程加入到线程池中进行处理
Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := ../common/IFregService.cpp \
    FregServer.cpp

LOCAL_SHARED_LIBRARIES:= libcutils libutils libbinder

LOCAL_MODULE := FregServer

include $(BUILD_EXECUTABLE)

编译文件内容,使用的共享库有三个,在要是在代码中使用了几个关键的类,编译为可执行程序。其他的这里不做过多介绍了。

Client端实现

FregClient.cpp

客户端实现基于服务端,需要从SM中获取在使用其提供的服务方法,具体代码如下:

#define LOG_TAG "FregClient"
#include <utils/Log.h>
#include <binder/IServiceManager.h>
#include "../common/IFregService.h"

// Client端模块
// 主程序
int main()
{
    // 由Servcer端注册的服务,这里通过ServiceManager获取相应服务
    sp<IBinder> binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
    if(binder == NULL) {
        ALOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
        return -1;
    }

    // 获取binder是实现了IFergService接口的对象,这里可以直接转
    sp<IFregService> service = IFregService::asInterface(binder);
    if(service == NULL) {
        ALOGE("Failed to get freg service interface.\n");
        return -2;
    }

    printf("Read original value from FregService:\n");

    // 通过代理对象,调用其getVal方法获取寄存器值
    int32_t val = service->getVal();
    printf(" %d.\n", val);

    printf("Add value 9 to FregService.\n");    
    val += 9;
    // 通过代理对象,调用setVal设置寄存器值
    service->setVal(val);

    printf("Read the value from FregService again:\n");

    // 在此读取寄存器值
    val = service->getVal();
        printf(" %d.\n", val); 

    return 0;
}

代码相关说明:

  1. defaultServiceManager()->getService()同样通过SM上下文管理者获取指定传入服务
  2. 获取到的服务统一以接口IBinder类型返回,有强引用sp维护生命周期
  3. IFregService::asInterface()用于将获取的接口实例转换成需要的服务实例,具体在下面接口文件中分析
  4. service->getVal(),setVal()根绝获取服务,调用其服务方法

从这里,不免可以看出之前AIDL文章中分析到的中间文件内容,在下面的接口文件分析中将更加清晰。

Android.mk
LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE_TAGS := optional

LOCAL_SRC_FILES := ../common/IFregService.cpp \
    FregClient.cpp

LOCAL_SHARED_LIBRARIES:= libcutils libutils libbinder

LOCAL_MODULE := FregClient

include $(BUILD_EXECUTABLE)

和上面的编译文件基本相似,最后同样生成可执行程序。

IFregService接口文件实现

IFregService.h
#ifndef IFREGSERVICE_H_
#define IFREGSERVICE_H_

#include <utils/RefBase.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>

#define FREG_SERVICE "shy.luo.FregService"

using namespace android;

// 接口声明
class IFregService: public IInterface
{
public:
    // 特定宏,声明IFregService的元接口
    DECLARE_META_INTERFACE(FregService);
    // 两个虚方法,子类实现
    virtual int32_t getVal() = 0;
    virtual void setVal(int32_t val) = 0;
};

// 本地(Binder)FregService对象
class BnFregService: public BnInterface<IFregService>
{
public:
    // 模板类BnInterface的成员函数onTransact
    virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0);
};

#endif

代码说明集中如下:

  1. 导包中有<binder/IInterface.h>,其为底层Binder为上层提供跨进程通信的函数模版,具体内容等待介绍
  2. 导包中有<binder/Parcel.h>,Parcel类为数据在Binder机制中传输的媒介,任何数据进行传输都要进行封包Parcel,然后再拆包
  3. FREG_SERVICE为服务唯一描述符,注册,获取均要使用它
  4. IFregService继承于IInterface,这里可以看出AIDL中自定义的接口也是继承IInterface
  5. DECLARE_META_INTERFACE,为IInterface模版函数提供的元接口,后续讲到
  6. BnFregService为本地服务Binder服务,相同的Bp…则是远程,其继承BnInterface,范型
    为IFregService,其代表服务端收到请求处理onTransact方法

由上,引出来一个重要的文件IInterface.h,下面我们集中分析它。

IFregService.cpp

头文件已经分析完了,下面来看看IFregService.cpp文件具体内容

#define LOG_TAG "IFregService"
#include <utils/Log.h>
#include "IFregService.h"

using namespace android;
// 枚举,对应通信两个方法
enum {
    GET_VAL = IBinder::FIRST_CALL_TRANSACTION,
    SET_VAL
};

// 模板类BpInterface的实现类,Binder远程代理实现
class BpFregService: public BpInterface<IFregService>{
public:
    // 构造函数
    BpFregService(const sp<IBinder>& impl) 
        : BpInterface<IFregService>(impl){
    }

public:
    //代理对象,具体实现
    int32_t getVal(){
        Parcel data;
        data.writeInterfaceToken(IFregService::getInterfaceDescriptor());
        Parcel reply;
        // remote()函数来获取BpBinder代理对象
        // 调用代理对象的transact请求运行在Server进程的一个Binder对象执行GET_VAL方法
        remote()->transact(GET_VAL, data, &reply);
        int32_t val = reply.readInt32();
        return val;
    }

    void setVal(int32_t val){
        Parcel data;
        data.writeInterfaceToken(IFregService::getInterfaceDescriptor());
        data.writeInt32(val);
        Parcel reply;
        // remote()函数来获取BpBinder代理对象
        // 调用代理对象的transact请求运行在Server进程的一个Binder对象执行SET_VAL方法
        remote()->transact(SET_VAL, data, &reply);
    }
};

// 特定宏,实现IFregService类的元接口,有头文件DECLARE_META_INTERFACE相对应
IMPLEMENT_META_INTERFACE(FregService, "shy.luo.IFregService");

// 模板类BnInterface实现类BnFregService的成员函数onTransact的实现
// 将具体方法分发给实现其的子类FregService处理,这里只是分发,不具体实现
status_t BnFregService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code)
    {
        case GET_VAL:{
            CHECK_INTERFACE(IFregService, data, reply);
            int32_t val = getVal();
            reply->writeInt32(val);
            return NO_ERROR;
        }
        case SET_VAL:{
            CHECK_INTERFACE(IFregService, data, reply);
            int32_t val = data.readInt32();
            setVal(val);
            return NO_ERROR;
        }
        default:{
            return BBinder::onTransact(code, data, reply, flags);
        }
    }
}

代码相关说明:

  1. enum用于声明两个方法,Binder底层通信会使用到后面的IBinder::FIRST_CALL_TRANSACTION,用于区分服务的不同请求
  2. BpFregService为远程代理服务实现,依旧是由模版类中的BpInterface提供支持。其构造函数传递对象为IBinder类型,由强引用sp维持
  3. BpFregService中方法getVal和setVal,有客户端通过SM获取到远程代理对象,调用代理对象服务方法会走此流程,remote()函数来获取BpBinder代理对象,之后进入Binder驱动中,从数据封装到了Parcel中可以看出
  4. IMPLEMENT_META_INTERFACE,特定宏,实现IFregService类的元接口,IInterface中会介绍
  5. BnFregService为Server端得到Binder驱动传入的请求消息,响应走onTransact方法。其最终调用实现类FregService的具体的方法,FregService继承了BnFregService

IInterface.h

前面文件分析中,多次提到这个文件,下面我们来具体分析一下。

#ifndef ANDROID_IINTERFACE_H
#define ANDROID_IINTERFACE_H

#include <binder/Binder.h>
namespace android {
// ----------------------------------------------------------------------
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;
};
// ----------------------------------------------------------------------

//模板函数
//interface_cast(const sp<IServiceManager>) == IServiceManager::asInterface()
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

// ----------------------------------------------------------------------

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

protected:
    virtual IBinder*            onAsBinder();
};

// ----------------------------------------------------------------------

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

protected:
    virtual IBinder*            onAsBinder();
};

// ----------------------------------------------------------------------
//主要声明asInterface(),getInterfaceDescriptor()方法
#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();                                            \


#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() { }                                   \


#define CHECK_INTERFACE(interface, data, reply)                         \
    if (!data.checkInterface(this)) { return PERMISSION_DENIED; }       \


// ----------------------------------------------------------------------
// No user-serviceable parts after this...

template<typename INTERFACE>
inline sp<IInterface> BnInterface<INTERFACE>::queryLocalInterface(
        const String16& _descriptor)
{
    if (_descriptor == INTERFACE::descriptor) return this;
    return NULL;
}

template<typename INTERFACE>
inline const String16& BnInterface<INTERFACE>::getInterfaceDescriptor() const
{
    return INTERFACE::getInterfaceDescriptor();
}

template<typename INTERFACE>
IBinder* BnInterface<INTERFACE>::onAsBinder()
{
    return this;
}

template<typename INTERFACE>
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
    //先初始化BpRefBase()
    : BpRefBase(remote)
{
}

template<typename INTERFACE>
inline IBinder* BpInterface<INTERFACE>::onAsBinder()
{
    return remote();
}

// ----------------------------------------------------------------------

}; // namespace android

#endif // ANDROID_IINTERFACE_H

内容比较多,我们根据代码一一分析:

DECLARE_META_INTERFACE(…)

在头文件中使用到宏指令DECLARE_META_INTERFACE,其目的是方便在C层声明asInterface等方法,具体传入参数为FregService,根据代码展开如下:

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

C层头文件通过一条宏指令,便可以完成Binder通信架构的声明,下面便是具体实现宏IMPLEMENT_META_INTERFACE。

IMPLEMENT_META_INTERFACE(…)

其是一条宏,传入参数为(INTERFACE, NAME),这里INTERFACE对应FregService;NAME对应于 “shy.luo.IFregService”。根据宏内容展开如下:

const android::String16 FregService::descriptor(shy.luo.IFregService);             
const android::String16&                                            
        FregService::getInterfaceDescriptor() const {              
    return FregService::descriptor;                                
}                                                                   
android::sp<FregService> FregService::asInterface(                
        const android::sp<android::IBinder>& obj)                   
{                                                                  
    android::sp<FregService> intr;                                 
    if (obj != NULL) {                                              
        intr = static_cast<FregService*>(                          
            obj->queryLocalInterface(                               
                    FregService::descriptor).get());               
        if (intr == NULL) {                                         
            intr = new Bp##INTERFACE(obj);                          
        }                                                           
    }                                                               
    return intr;                                                    
}                                                                   
FregService::FregService() { }                                    
FregService::~FregService() { }     
  1. 其根据宏,声明了FregService的descriptor,getInterfaceDescriptor,asInterface,构造函数和析构函数
  2. 其中descriptor描述为shy.luo.IFregService,asInterface传入的参数是范型为IBinder常引用
  3. 其内部逻辑是首先通过BInder对象的queryLocalInterface方法,根据descriptor查看本地是否存在,(同一个进程,直接返回),不存在就其自身新建Bp##INTERFACE(obj)

分析到这里,基本的函数模版就清晰可见了。IInterface.h头文件,通过两条特定的宏,完成了C层代码实现基于系统提供的Binder跨进程通信的架构规范,而其最终结果便是生成远程代理对象Bp##INTERFACE,方便Client端调用。

BpFregService实例化
  1. BpFregService创建过程,首先实例化父类

    --> IFregService.cpp
    
    BpFregService(const sp<IBinder>& impl) 
            : BpInterface<IFregService>(impl){
        }
    
  2. BpInterface初始化,会先初始化BpRefBase

    --> IInterface.h
    
    inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
        //先初始化化BpRefBase()
        : BpRefBase(remote){
    }
    
  3. BpRefBase初始化,建立引用关系

    --> Binder.cpp
    
    BpRefBase::BpRefBase(const sp<IBinder>& o)
        : mRemote(o.get()), mRefs(NULL), mState(0)
    {
        extendObjectLifetime(OBJECT_LIFETIME_WEAK);
    
        if (mRemote) {
            mRemote->incStrong(this);
            mRefs = mRemote->createWeak(this);
        }
    }
    

BpFregService在初始化过程中,经过层层调用,进入到Binder驱动程序中,通过传入的IBinder,为其建立引用关系,增加其对应的强弱引用值等。

  • 以上部分参考Gityuan博客相关内容,有兴趣读者可以自行查看,链接如下:

    戳我

其他注意点

在理解这部分时,我们不妨这样理解,采用分层的形式来理解,具体如下:

  1. BpInterface 对应远程代理对象,持有对象为IBinder类型的remote,由Client端直接持有,存在于底层Binder中
  2. BnInterface 对应本地对象,由sp强引用维持生命周期,继承自BBinder,此处由BnFregService持有,存在于底层Binder中
  3. Client端从SM中获取的IBinder类型对象obj,其是底层Binder对应Server端分配为其分配的BpInterface远程代理对象
  4. 底层Binder接受Client传递的跨进程消息,首先传递到对应的BnInterface本地对象,然后在传递给其子类BnFregService的onTransact中处理,而FregService正是继承自BnFregService,实现了onTransact中的具体方法

由上解释了跨进程通信的具体流程,其中分层的意思就是Binder底层自动的为Client和Server端都建立了链接关系,通过BpInterface和BnInterface在底层实现跨进程交互。

运行结果

编译获取文件
// 编译完成得到FregServer
mmm external/binder/server/

// 编译得到FregClient
mmm external/binder/client
放置程序,提权
adb connect ...
// push文件到sdcard下
adb push FregServer FregClient /sdcard/

adb shell
su
// 重挂在分区读写
mount -o remount,rw /system
cp /sdcard/Freg* /system/bin
// 读权
chmod 755 Freg*
运行,查看结果
// 后台运行
/system/bin/FregServer &
/system/bin/FregClient

log日志如下:

root@makena:/system # /system/bin/FregClient                                   
Read original value from FregService:
 100.
Add value 9 to FregService.
Read the value from FregService again:
 109.

在framework层实现Binder通信

以上介绍了Native层Binder通信的实现,至于framework层实现也基本相似,这里就不详细说明了。其大概流程就是像之前AIDL分析章节中提到的编译中间接口文件那样,使用其中几个重要类和方法,基于底层Binder实现好的框架,实现跨进程通信。如果有读者想尝试,可以参考Gityuan博客中的代码自己实现测试一下即可。

戳我

总结

本章节详细的介绍了Binder通信在Native层具体实现。其本质还是基于底层Binder驱动实现好框架,借助于IInterface.h中提供的几个重要方法,按照一定的规范实现,便可以轻松的实现跨进程通信。

本着前篇的AIDL的介绍和本章节的Binder在Native层实现,相信读者基本了解了Binder跨进程通信机制的原理,至于更多更深层次的介绍,可能会更多的集中在C层和驱动层,后续章节会针对这些方面再具体分析。

基本上层的Binder实现到此就结束了。下面章节再介绍Binder就会从C层乃至驱动层进行分析。读者本人刚开始学习也是一脸懵逼,咬牙坚持,耐着性子看了两三遍才稍微有点想法。世上无难事,只怕有心人。Jsut do it!

共勉:Fucking source code!!!

相关推荐

参考代码: Android系统源代码情景分析

Gityuan博客

坚持原创技术分享,您的支持将鼓励我继续创作!