上篇文章中,我们详细的了解了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;
}
程序相关说明如下:
- FregService继承于BnFregService,BnFregService会在后面接口文件中涉及
- defaultServiceManager()用来获取系统服务关系程序ServiceManager,其是Binder架构中的上下文管理者,任何服务都要先在其中注册,然后再从中获取到对应服务的代理对象,完成相应逻辑
- addService()向SM注册服务,传入服务的描述名和服务对象,以便SM为其分配代理对象等
- ProcessState::self()用于获取本地进程,内部使用单例模式,返回本地进程
- startThreadPool开启本进程的线程池服务,用于等待客户端请求通知
- 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;
}
代码相关说明:
- defaultServiceManager()->getService()同样通过SM上下文管理者获取指定传入服务
- 获取到的服务统一以接口IBinder类型返回,有强引用sp维护生命周期
- IFregService::asInterface()用于将获取的接口实例转换成需要的服务实例,具体在下面接口文件中分析
- 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
代码说明集中如下:
- 导包中有<binder/IInterface.h>,其为底层Binder为上层提供跨进程通信的函数模版,具体内容等待介绍
- 导包中有<binder/Parcel.h>,Parcel类为数据在Binder机制中传输的媒介,任何数据进行传输都要进行封包Parcel,然后再拆包
- FREG_SERVICE为服务唯一描述符,注册,获取均要使用它
- IFregService继承于IInterface,这里可以看出AIDL中自定义的接口也是继承IInterface
- DECLARE_META_INTERFACE,为IInterface模版函数提供的元接口,后续讲到
- 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);
}
}
}
代码相关说明:
- enum用于声明两个方法,Binder底层通信会使用到后面的IBinder::FIRST_CALL_TRANSACTION,用于区分服务的不同请求
- BpFregService为远程代理服务实现,依旧是由模版类中的BpInterface提供支持。其构造函数传递对象为IBinder类型,由强引用sp维持
- BpFregService中方法getVal和setVal,有客户端通过SM获取到远程代理对象,调用代理对象服务方法会走此流程,remote()函数来获取BpBinder代理对象,之后进入Binder驱动中,从数据封装到了Parcel中可以看出
- IMPLEMENT_META_INTERFACE,特定宏,实现IFregService类的元接口,IInterface中会介绍
- 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() { }
- 其根据宏,声明了FregService的descriptor,getInterfaceDescriptor,asInterface,构造函数和析构函数
- 其中descriptor描述为shy.luo.IFregService,asInterface传入的参数是范型为IBinder常引用
- 其内部逻辑是首先通过BInder对象的queryLocalInterface方法,根据descriptor查看本地是否存在,(同一个进程,直接返回),不存在就其自身新建Bp##INTERFACE(obj)
分析到这里,基本的函数模版就清晰可见了。IInterface.h头文件,通过两条特定的宏,完成了C层代码实现基于系统提供的Binder跨进程通信的架构规范,而其最终结果便是生成远程代理对象Bp##INTERFACE,方便Client端调用。
BpFregService实例化
BpFregService创建过程,首先实例化父类
--> IFregService.cpp BpFregService(const sp<IBinder>& impl) : BpInterface<IFregService>(impl){ }
BpInterface初始化,会先初始化BpRefBase
--> IInterface.h inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote) //先初始化化BpRefBase() : BpRefBase(remote){ }
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博客相关内容,有兴趣读者可以自行查看,链接如下:
其他注意点
在理解这部分时,我们不妨这样理解,采用分层的形式来理解,具体如下:
- BpInterface 对应远程代理对象,持有对象为IBinder类型的remote,由Client端直接持有,存在于底层Binder中
- BnInterface 对应本地对象,由sp强引用维持生命周期,继承自BBinder,此处由BnFregService持有,存在于底层Binder中
- Client端从SM中获取的IBinder类型对象obj,其是底层Binder对应Server端分配为其分配的BpInterface远程代理对象
- 底层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系统源代码情景分析