百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

Android 系统核心机制binder(03)binder C++层实现

itomcoil 2025-06-15 16:59 8 浏览

本章关键点总结 & 说明:

这里主要关注 Binder C++部分即可,看到,也是本章节的核心内容,主要就是以C++封装的框架为主来解读binder。

之前主要针对于底层驱动binder的 数据交互以及 如何注册服务、获取服务、使用服务;而android的C++层实际上仅仅是换了一种方式,加了框架的理念来更好的复用驱动层的代码而已;同时java层的封装更是为了上层的使用方便。

1 binder C++层实现框架案例

1.1 binder的C++ 相关类图 关系说明:

这里仅仅从 Binder的 客户端和服务端通信IPC角度 来看Binder的 C++实现框架,红色部分的mRemote在使用中 实际上就是 BpBinder,蓝色部分为 用户在使用 该binder C++框架时 需要自己编写的类,而其他未标明的类是系统本身自带的。该图描述了BpBinder BBinder IBinder BpRefBase IInterface BpInterface BnInterface BpHelloService BnHelloService之间的关系。

1.2 binder C++层 HelloService demo 代码实现

这里以HelloService为例,解读 binder的C++框架,看看几个关键类IHelloService、BpHelloService、BnHelloService 如何使用?

@1 IHelloService.h的实现如下:

C++
#ifndef ANDROID_IHELLOERVICE_H
#define ANDROID_IHELLOERVICE_H

#include <utils/Errors.h> // for status_t
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#define HELLO_SVR_CMD_SAYHELLO 1
#define HELLO_SVR_CMD_SAYHELLO_TO 2
#define HELLO_SVR_CMD_GET_FD 3 //后面会单独分析这个部分

namespace android {
class IHelloService: public IInterface
{
public:
DECLARE_META_INTERFACE(HelloService);
virtual void sayhello(void) = 0;
virtual int sayhello_to(const char name) = 0;
virtual int get_fd(void) = 0;
};

class BnHelloService: public BnInterface<IHelloService>
{
private:
int fd;
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel reply,
uint32_t flags = 0);
virtual void sayhello(void);
virtual int sayhello_to(const char *name);
virtual int get_fd(void); //后面会单独分析这个部分

BnHelloService();
BnHelloService(int fd);
};
}
#endif

@2 BnHelloService.cpp的实现如下(这里参考了 frameworks\av\media\libmedia\IMediaPlayerService.cpp):

C++
#define LOG_TAG "HelloService"
#include "IHelloService.h"
namespace android {
BnHelloService::BnHelloService()
{
}

BnHelloService::BnHelloService(int fd)
{
this->fd = fd;
}

status_t BnHelloService::onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags)
{
switch (code) {
case HELLO_SVR_CMD_SAYHELLO: {
sayhello();
reply->writeInt32(0); /* no exception /
return NO_ERROR;
} break;

case HELLO_SVR_CMD_SAYHELLO_TO: {
//@1 读取传入参数,并转换
int32_t policy = data.readInt32();
String16 name16_tmp = data.readString16(); / IHelloService /
String16 name16 = data.readString16();
String8 name8(name16);
//@2 调用对应函数
int cnt = sayhello_to(name8.string());

//@3 返回值转换,并发送
reply->writeInt32(0); / no exception /
reply->writeInt32(cnt);

return NO_ERROR;
} break;

case HELLO_SVR_CMD_GET_FD: {
int fd = this->get_fd();
reply->writeInt32(0); / no exception /
reply->writeDupFileDescriptor(fd);
return NO_ERROR;
} break; 
default:
return BBinder::onTransact(code, data, reply, flags);
}
}

void BnHelloService::sayhello(void)
{
static int cnt = 0;
ALOGI("say hello : %d\n", ++cnt);
}

int BnHelloService::sayhello_to(const char name)
{
static int cnt = 0;
ALOGI("say hello to %s : %d\n", name, ++cnt);
return cnt;
}

int BnHelloService::get_fd(void)
{
return fd;
}
}

@3 BpHelloService.cpp的实现如下:

C++
#include "IHelloService.h"
namespace android {

class BpHelloService: public BpInterface<IHelloService>
{
public:
BpHelloService(const sp<IBinder>& impl): BpInterface<IHelloService>(impl)
{
}

void sayhello(void)
{
Parcel data, reply;
data.writeInt32(0);
data.writeString16(String16("IHelloService"));
remote()->transact(HELLO_SVR_CMD_SAYHELLO, data, &reply);
}

int sayhello_to(const char *name)
{
Parcel data, reply;
int exception;

data.writeInt32(0);
data.writeString16(String16("IHelloService"));
data.writeString16(String16(name));
remote()->transact(HELLO_SVR_CMD_SAYHELLO_TO, data, &reply);
exception = reply.readInt32();
if (exception)
return -1;
else
return reply.readInt32();
}

int get_fd(void)
{
Parcel data, reply;
int exception;

data.writeInt32(0);
data.writeString16(String16("IHelloService"));
remote()->transact(HELLO_SVR_CMD_GET_FD, data, &reply);

exception = reply.readInt32();
if (exception)
return -1;
else
{
int rawFd = reply.readFileDescriptor();
return dup(rawFd);
}
}
};
IMPLEMENT_META_INTERFACE(HelloService, "android.media.IHelloService");
}

@4 客户端代码 Test_client.cpp的实现如下:

C++
#define LOG_TAG "TestService"
//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <unistd.h>

#include "IHelloService.h"

using namespace android;

/* ./test_client <hello>
* ./test_client <readfile>
* ./test_client <hello> <name>
/

int main(int argc, char argv)
{
int cnt;

if (argc < 2){
ALOGI("Usage:\n");
ALOGI("%s <readfile>\n", argv[0]);
ALOGI("%s <hello|goodbye>\n", argv[0]);
ALOGI("%s <hello|goodbye> <name>\n", argv[0]);
return -1;
}

/ getService /
/ 打开驱动, mmap /
sp<ProcessState> proc(ProcessState::self());

/ 获得BpServiceManager /
sp<IServiceManager> sm = defaultServiceManager();

if (strcmp(argv[1], "hello") == 0)
{
sp<IBinder> binder = sm->getService(String16("hello"));
if (binder == 0)
{
ALOGI("can't get hello service\n");
return -1;
}

// service肯定是BpHelloServie指针
sp<IHelloService> service = interface_cast<IHelloService>(binder);

/ 调用Service的函数 /
if (argc < 3) {
service->sayhello();
ALOGI("client call sayhello");
}
else {
cnt = service->sayhello_to(argv[2]);
ALOGI("client call sayhello_to, cnt = %d", cnt);
}
}
else if (strcmp(argv[1], "readfile") == 0)
{

sp<IBinder> binder =
sm->getService(String16("hello"));

if (binder == 0)
{
ALOGI("can't get hello service\n");
return -1;
}

/ service肯定是BpHelloServie指针 /
sp<IHelloService> service = interface_cast<IHelloService>(binder);

/ 调用Service的函数 /
int fd = service->get_fd();

ALOGI("client call get_fd = %d", fd);

char buf[500];
int len;
int cnt = 0;

while (1)
{
//向 test_server 进程数据: Hello, test_server /
len = sprintf(buf, "Hello, test_server, cnt = %d", cnt++);
write(fd, buf, len);
len = read(fd, buf, 500);
buf[len] = '\0';
ALOGI("%s\n", buf);
sleep(5);
}
}
return 0;
}

@5 服务端Test_server.cpp的实现如下:

C++
#define LOG_TAG "TestService"
//#define LOG_NDEBUG 0

#include <fcntl.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/socket.h>
#include "IHelloService.h"
#define SOCKET_BUFFER_SIZE (32768U)

using namespace android;

class MyThread: public Thread { 
private:
int fd;
public: 
MyThread() {}
MyThread(int fd) { this->fd = fd; }

//说明:若返回true,循环调用此函数,返回false下一次不会再调用此函数 
bool threadLoop()
{
char buf[500];
int len;
int cnt = 0;

while(1)
{
len = read(fd, buf, 500);
buf[len] = '\0';
ALOGI("%s\n", buf);

/* 向 test_client 发出: Hello, test_client */
len = sprintf(buf, "Hello, test_client, cnt = %d", cnt++);
write(fd, buf, len);
}

return true; 
}

}; 

int main(void)
{
int sockets[2];

socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets);

int bufferSize = SOCKET_BUFFER_SIZE;
setsockopt(sockets[0], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[0], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));

// 创建线程, 和test_client使用socketpiar通信
sp<MyThread> th = new MyThread(sockets[0]);
th->run(); 

// 关键点1 初始化binder
sp<ProcessState> proc(ProcessState::self());

// 关键点2 获得BpServiceManager
sp<IServiceManager> sm = defaultServiceManager();

// 关键点3
sm->addService(String16("hello"), new BnHelloService(sockets[1]));

// 关键点4 创建新的子线程,并开始处理驱动上报的消息
ProcessState::self()->startThreadPool();

// 关键点5 主线程 循环,循环并处理驱动上报的消息
IPCThreadState::self()->joinThreadPool();//辅助类 IPCThreadState的分析

return 0;
}

@6 最后描述下 Android.mk的实现

Bash
LOCAL_PATH:= $(call my-dir)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
BnHelloService.cpp \
BpHelloService.cpp \
test_server.cpp

LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
libbinder 


LOCAL_MODULE:= test_server
LOCAL_32_BIT_ONLY := true

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
BpHelloService.cpp \
test_client.cpp

LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
liblog \
libbinder 


LOCAL_MODULE:= test_client
LOCAL_32_BIT_ONLY := true

include $(BUILD_EXECUTABLE)

几段代码的整体说明:

前三段代码实现了HelloService整个服务(接口IHelloService 和BpHelloService 和 BnHelloService)

服务端TestServer实现了Hello服务的注册和socket通信架构机制(读& 写)。

客户端TestClient实现了Hello服务的获取和使用,同时 获取了fd(服务端的socket句柄)并使用

Android.mk的实现,可以直接编译即可使用。

根据上面的例子基本上就可以写出一个基于Binder的 C++ demo程序,如果仅仅是使用binder的话,那已经足够了。

2 binder C++层实现 BpServiceManager

这一部分专门解读下 BpServiceManager的通信流程框架和部分代码,因为针对于系统的ServiceManager服务而言,它本身就相当于BnServiceManager的角色,而我们在分析Binder C++层代码时,当时也陷入了一个误区,觉得有BpXXX就一定要有BnXXX,实际上是不一定的,ServiceManager本身就是一个很好的例子。

2.1 BpServiceManager 的单边类关系框架图如下:

跟1.1的框架图相比,实际上是少了BnInterface那一半的,而这一半实际上就是开机启动的那个程序 servicemanager,在下一章节中我们会专门讲解到。

2.2 IServiceManager的实现说明

@1 IServiceManager.h的实现如下:

C++
#ifndef ANDROID_ISERVICE_MANAGER_H
#define ANDROID_ISERVICE_MANAGER_H

#include <binder/IInterface.h>
#include <binder/IPermissionController.h>
#include <utils/Vector.h>
#include <utils/String16.h>

namespace android {
class IServiceManager : public IInterface
{
public:
DECLARE_META_INTERFACE(ServiceManager);

virtual sp<IBinder> getService( const String16& name) const = 0;
virtual sp<IBinder> checkService( const String16& name) const = 0;
virtual status_t addService( const String16& name,
const sp<IBinder>& service,
bool allowIsolated = false) = 0;
virtual Vector<String16> listServices() = 0;

enum {
GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
CHECK_SERVICE_TRANSACTION,
ADD_SERVICE_TRANSACTION,
LIST_SERVICES_TRANSACTION,
};
};

sp<IServiceManager> defaultServiceManager();

template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
const sp<IServiceManager> sm = defaultServiceManager();
if (sm != NULL) {
outService = interface_cast<INTERFACE>(sm->getService(name));
if ((outService) != NULL) return NO_ERROR;
}
return NAME_NOT_FOUND;
}
//...

class BnServiceManager : public BnInterface<IServiceManager>
{
public:
virtual status_t onTransact( uint32_t code,
const Parcel& data,
Parcel* reply,
uint32_t flags = 0);
};
}; // namespace android

#endif // ANDROID_ISERVICE_MANAGER_H

@2 IServiceManager.cpp的实现如下:

C++
#define LOG_TAG "ServiceManager"

#include <binder/IServiceManager.h>

#include <utils/Log.h>
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#include <utils/SystemClock.h>

#include <private/binder/Static.h>

#include <unistd.h>

namespace android {

sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;

{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}

return gDefaultServiceManager;
}
//。。。
class BpServiceManager : public BpInterface<IServiceManager>
{
public:
BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{
}

virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name);
if (svc != NULL) return svc;
ALOGI("Waiting for service %s...\n", String8(name).string());
sleep(1);
}
return NULL;
}

virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}

virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated)
{
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}

virtual Vector<String16> listServices()
{
Vector<String16> res;
int n = 0;

for (;;) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeInt32(n++);
status_t err = remote()->transact(LIST_SERVICES_TRANSACTION, data, &reply);
if (err != NO_ERROR)
break;
res.add(reply.readString16());
}
return res;
}
};

IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager");

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

status_t BnServiceManager::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
//printf("ServiceManager received: "); data.print();
switch(code) {
case GET_SERVICE_TRANSACTION: {
CHECK_INTERFACE(IServiceManager, data, reply);
String16 which = data.readString16();
sp<IBinder> b = const_cast<BnServiceManager*>(this)->getService(which);
reply->writeStrongBinder(b);
return NO_ERROR;
} break;
//...
default:
return BBinder::onTransact(code, data, reply, flags);
}
}

}; // namespace android

总结下,这两个文件主要实现了IServiceManager,BpServiceManager,BnServiceManager,然而这里最让人疑惑的就是BnServiceManager不是由 servicemanager替换了吗?那为什么还有BnServiceManager的存在?

BnServiceManager并没有在系统中注册,因此也就无法在驱动层生成对应的binder_node节点,事实上也没必要注册;因为servicemanager开机就启动,已经替代了所谓的BnServiceManager,同时在驱动层 给自己创建了对应的binder_node节点,所以最后的答案很简单,因为BnServiceManager压根就没有使用,只是一个摆设而已,真正实现功能的是servicemanager。

相关推荐

Java 如何从一个 List 中随机获得元素

概述从一个List中随机获得一个元素是有关List的一个基本操作,但是这个操作又没有非常明显的实现。本页面主要向你展示如何有效的从List中获得一个随机的元素和可以使用的一些方法。选择一个...

想月薪过万吗?计算机安卓开发之&quot;集合&quot;

集合的总结:/***Collection*List(存取有序,有索引,可以重复)*ArrayList*底层是数组实现的,线程不安全,查找和修改快,增和删比较慢*LinkedList*底层是...

China Narrows AI Talent Gap With U.S. as Research Enters Engineering Phase: Report

ImagegeneratedbyAITMTPOST--ChinaisclosinginontheU.S.intheAIindustry-academia-research...

大促系统优化之应用启动速度优化实践

作者:京东零售宋维飞一、前言本文记录了在大促前针对SpringBoot应用启动速度过慢而采取的优化方案,主要介绍了如何定位启动速度慢的阻塞点,以及如何解决这些问题。希望可以帮助大家了解如何定位该类问...

MyEMS开源能源管理系统核心代码解读004

本期解读:计量表能耗数据规范化算法:myems/myems-normalization/meter.py代码见底部这段代码是一个用于计算和存储能源计量数据(如电表读数)的小时值的Python脚本。它主...

Java接口与抽象类:核心区别、使用场景与最佳实践

Java接口与抽象类:核心区别、使用场景与最佳实践一、核心特性对比1.语法定义接口:interface关键字定义,支持extends多继承接口javapublicinterfaceDrawabl...

超好看 vue2.x 音频播放器组件Vue-APlayer

上篇文章给大家分享了视频播放器组件vue-aliplayer,这次给大家推荐一款音频插件VueAplayer。vue-aplayer一个好看又好用的轻量级vue.js音乐播放器组件。清爽漂亮的U...

Linq 下的扩展方法太少了,MoreLinq 来啦

一:背景1.讲故事前几天看同事在用linq给内存中的两个model做左连接,用过的朋友都知道,你一定少不了一个叫做DefaultIfEmpty函数,这玩意吧,本来很流畅的from......

MapReduce过程详解及其性能优化(详细)

从JVM的角度看Map和ReduceMap阶段包括:第一读数据:从HDFS读取数据1、问题:读取数据产生多少个Mapper??Mapper数据过大的话,会产生大量的小文件,由于Mapper是基于虚拟...

手把手教你使用scrapy框架来爬取北京新发地价格行情(实战篇)

来源:Python爬虫与数据挖掘作者:霖hero前言关于Scrapy理论的知识,可以参考我的上一篇文章,这里不再赘述,直接上干货。实战演练爬取分析首先我们进入北京新发地价格行情网页并打开开发者工具,如...

屏蔽疯狂蜘蛛,防止CPU占用100%(mumu模拟器和雷电模拟器哪个更占用cpu)

站点总是某个时间段莫名的cpu100%,资源占用也不高,这就有必要怀疑爬虫问题。1.使用"robots.txt"规范在网站根目录新建空白文件,命名为"robots.txt&#...

Web黑客近年神作Gospider:一款基于Go语言开发的Web爬虫,要收藏

小白看黑客技术文章,一定要点首小歌放松心情哈,我最爱盆栽!开始装逼!Gospider是一款运行速度非常快的Web爬虫程序,对于爱好白帽黑客的小白来说,可谓是佳作!Gospider采用厉害的Go语言开发...

用宝塔面板免费防火墙屏蔽织梦扫描网站

今天教大家在免费的基础上屏蔽织梦扫描,首先您要安装宝塔面板,然后再安装免费的防火墙插件,我用的是Nginx免费防火墙,然后打开这个插件。设置GET-URL过滤设置一条简单的宝塔面板的正则规则就可以屏蔽...

蜘蛛人再捞4千万美元 连续三周蝉联北美票房冠军

7月15日讯老马追踪票房数据的北美院线联盟今天表示,“蜘蛛人:离家日”(Spider-Man:FarFromHome)击退两部新片的挑战,连续第2周勇夺北美票房冠军,海捞4530万美元。法新...

夏天到了,需要提防扁虱,真是又小又恐怖的动物

夏天马上要到了,你知道吗,扁虱是这个夏天最危险的动物之一,很少有动物能比它还凶猛。Whenitcomestosummer'slittledangers,fewarenastiert...