android binder(二)应用层编程实例 - 指南

news/2025/10/7 18:41:11/文章来源:https://www.cnblogs.com/tlnshuju/p/19128749

android binder(二)应用层编程实例 - 指南

2025-10-07 18:38  tlnshuju  阅读(0)  评论(0)    收藏  举报

一、binder驱动浅析

从上图看出,binder的通讯主要涉及三个步骤。

  • 在 Binder Server 端定义好服务,然后向 ServiceManager 注册服务
  • 在 Binder Client 中向 ServiceManager 获取到服务
  • 发起远程调用,调用 Binder Server 中定义好的服务

整个流程都是建立在 Binder 驱动提供的跨进程调用能力之上,bingde驱动的实现比较复杂,现阶段我们先以黑盒的方式去了解它:

Binder 是一个 Linux 字符驱动,对外提供了以下函数供应用程序使用:

ioctl(文件描述符,ioctl命令,数据)

文件描述符是在调用 open 时的返回值,ioctl 命令和第三个参数"数据"的类型是相关联的,具体如下:

ioctl命令数据类型函数动作
BINDER_WRITE_READstruct binder_write_read应用层向内核层收发数据
BINDER_SET_MAX_THREADSsize_t设置最大线程数
BINDER_SET_CONTEXT_MGRint or flat_binder_object设置当前进程为ServiceManager
BINDER_THREAD_EXITint删除 binder 线程
BINDER_VERSIONstruct binder_version获取 binder 协议版本

二、安卓提供的封装 

servicemanager - OpenGrok cross reference for /frameworks/native/cmds/servicemanager/

frameworks/native/cmds/servicemanager 目录下的 binder.cbctest.c 针对应用编写的需求,对open mmap ioctl 等基本操作做了封装,提供了以下几个函数:

三、 ServiceManager 源码分析

  • 打开 Binder 驱动
  • 告知驱动自身为 service manager
  • 循环处理
    • 从驱动读取数据
    • 解析数据并调用
      • 处理service端的注册服务请求:其实就是在一个链表记录服务名
      • 处理client获取服务请求:
        • 在链表查询服务
        • 返回 server 进程的 handle
service_manager.c
binder_open //打开 Binder 驱动
binder_become_context_manager //告知驱动自身为 service manager
binder_loop
binder_parse //从驱动读取数据并解析
svcmgr_handler//根据不同的命令,进入不同的处理流程
do_add_service //添加服务
do_find_service//获取服务

四、编写自定义service代码

参考代码:bctest.c - OpenGrok cross reference for /frameworks/native/cmds/servicemanager/bctest.c

1、主流程:

2、消息处理流程

当 client 发起远程调用时,server 端会收到数据,并将这些数据传递给服务回调函数,这个回调函数需要我们自己来定义:也就是binder_loop(bs, test_server_handler)传入的test_server_handler函数。

3、服务处理流程:hello_service_handler

我们在注册服务的时候,传入了一个func handle, hello_service_handler。当收到client请求服务的时候,会进入这个函数进行处理。

#include 
#include 
#include 
#include 
#include
#include #include "binder.h"#define LOG_TAG "BinderServer"
#include #define HELLO_SVR_CMD_SAYHELLO 1
#define HELLO_SVR_CMD_SAYHELLO_TO 2void sayhello(void)
{
static int cnt = 0;
//fprintf(stderr, "say hello : %d\n", ++cnt);
ALOGW("say hello : %d\n", ++cnt);
}int sayhello_to(char *name)
{
static int cnt = 0;
//fprintf(stderr, "say hello to %s : %d\n", name, ++cnt);
ALOGW("say hello to %s : %d\n", name, ++cnt);
return cnt;
}int hello_service_handler(struct binder_state *bs,
struct binder_transaction_data_secctx *txn_secctx,
struct binder_io *msg,
struct binder_io *reply)
{
struct binder_transaction_data *txn = &txn_secctx->transaction_data;/* 根据txn->code知道要调用哪一个函数
 * 如果需要参数, 可以从msg取出
 * 如果要返回结果, 可以把结果放入reply
 *//* sayhello
 * sayhello_to
 */uint16_t *s;
char name[512];
size_t len;
//uint32_t handle;
uint32_t strict_policy;
int i;// Equivalent to Parcel::enforceInterface(), reading the RPC
// header with the strict mode policy mask and the interface name.
// Note that we ignore the strict_policy and don't propagate it
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);switch(txn->code) {
case HELLO_SVR_CMD_SAYHELLO:
sayhello();
bio_put_uint32(reply, 0); /* no exception */
return 0;case HELLO_SVR_CMD_SAYHELLO_TO:
/* 从msg里取出字符串 */
s = bio_get_string16(msg, &len); //"IHelloService"
s = bio_get_string16(msg, &len); // name
if (s == NULL) {
return -1;
}
for (i = 0; i < len; i++)
name[i] = s[i];
name[i] = '\0';/* 处理 */
i = sayhello_to(name);/* 把结果放入reply */
bio_put_uint32(reply, 0); /* no exception */
bio_put_uint32(reply, i);break;default:
fprintf(stderr, "unknown code %d\n", txn->code);
return -1;
}return 0;
}int test_server_handler(struct binder_state *bs,
struct binder_transaction_data_secctx *txn_secctx,
struct binder_io *msg,
struct binder_io *reply)
{
struct binder_transaction_data *txn = &txn_secctx->transaction_data;int (*handler)(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply);handler = (int (*)(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply))txn->target.ptr;return handler(bs, txn, msg, reply);
}int main(int argc, char **argv)
{
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
uint32_t handle;
int ret;//打开驱动
bs = binder_open("/dev/binder",128*1024);
if (!bs) {
fprintf(stderr, "failed to open binder driver\n");
return -1;
}//添加服务
ret = svcmgr_publish(bs, svcmgr, "hello", hello_service_handler);
if (ret) {
fprintf(stderr, "failed to publish hello service\n");
return -1;
}binder_loop(bs, test_server_handler);return 0;
}

五、编写自定义client 代码

编写 Client 程序的主要流程如下:

  • open  binder 驱动
  • 向service manager查询服务,获取到服务的句柄 handle
  • 通过 handle 调用远程调用函数
#include 
#include 
#include 
#include 
#include 
#include 
#include "binder.h"#define HELLO_SVR_CMD_SAYHELLO 1
#define HELLO_SVR_CMD_SAYHELLO_TO 2int g_handle = 0;
struct binder_state *g_bs;void sayhello(void)
{
unsigned iodata[512/4];
struct binder_io msg, reply;/* 构造binder_io */
bio_init(&msg, iodata, sizeof(iodata), 4);/* 放入参数 */
bio_put_uint32(&msg, 0); // strict mode header
bio_put_string16_x(&msg, "IHelloService");/* 调用binder_call */
if (binder_call(g_bs, &msg, &reply, g_handle, HELLO_SVR_CMD_SAYHELLO))
return ;/* 从reply中解析出返回值 */
binder_done(g_bs, &msg, &reply);}int main(int argc, char **argv)
{
int fd;
struct binder_state *bs;
uint32_t svcmgr = BINDER_SERVICE_MANAGER;
int ret;bs = binder_open("/dev/binder",128*1024);
if (!bs) {
fprintf(stderr, "failed to open binder driver\n");
return -1;
}g_bs = bs;/* get service */
g_handle = svcmgr_lookup(bs, svcmgr, "hello");
if (!g_handle) {
return -1;
}//调用服务
sayhello();}

六、梳理(待整理)

ref:

https://juejin.cn/post/7214342319347712057

Android系统--Binder系统具体框架分析(一) - lkq1220 - 博客园

https://juejin.cn/post/7210245482861264955

第5课第1节_Binder系统_C程序示例_框架分析_哔哩哔哩_bilibili

XRefAndroid - Support AOSP 15.0 AndroidXRef & OpenHarmony 5.0

【Android ServiceManager】从源码入手,剖析ServiceManager是如何处理客户端的请求的?_bnservicemanager 源码实现-CSDN博客

https://cs.android.com/android/platform/superproject/main

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/930723.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

做网站 需要什么样的服务器西安房产网最新楼盘

本文整理自曹操出行实时计算负责人林震基于 HologresFlink 的曹操出行实时数仓建设的分享&#xff0c;内容主要分为以下六部分&#xff1a; 曹操出行业务背景介绍曹操出行业务痛点分析HologresFlink 构建企业级实时数仓曹操出行实时数仓实践曹操出行业务成果分析未来展望 一、曹…

高校学校网站建设广州番禺区属于什么风险地区

分词 分词是最基本的第一步。无论对于英文文本&#xff0c;还是中文文本都离不开分词。英文的分词相对比较简单&#xff0c;因为一般的英文写法里通过空格来隔开不同单词的。但对于中文&#xff0c;我们不得不采用一些算法去做分词。 常用的分词工具 # encodingutf-8 import …

网站建设完工报告那些网站建设的好

1.什么是设计模式 软件设计模式&#xff08;Design pattern&#xff09;&#xff0c;又称设计模式&#xff0c;是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性、程序的重用性。 …

netdata

https://blog.gitiu.com/posts/19026/ 默认用的db engine 并不是做持久化的, 持久化用外部的DB https://learn.netdata.cloud/docs/netdata-agent/resource-utilization/disk-&-retention

秦皇岛手机网站制作费用优化是什么

Mirrored String II 看到题解说是马拉车算法&#xff0c;我赛时并没想到&#xff08;好吧其实我是比赛完才知道有马拉车这个算法&#xff09; 因为字符串的长度只有1000&#xff0c;直接暴力跑其实就可以了&#xff0c;但是要注意的是&#xff1b;回文串有俩种形式&#xff0c…

arc3.2语言sort的时候报错:(sort < `(2 9 3 7 5 1)) 得写成此种:(sort > (pair (list 3 2)))

arc3.2语言sort的时候报错:(sort < `(2 9 3 7 5 1)) 得写成此种:(sort > (pair (list 3 2)))pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !i…

关于Elment-plus的el-table组件无法通过原生JS监听scroll事件

Element-ui的el-table组件能够通过原生JS监听scroll事件 Elment-plus的el-table组件无法通过原生JS监听scroll事件,貌似是由于虚拟滚动的原因?! 今天想给el-table进行无限滚动的时候才发现...

什么是网站可信认证网站内容不收录

C# WPF入门学习主线篇&#xff08;十八&#xff09;—— Border布局容器 欢迎来到C# WPF入门学习系列的第十八篇。在前几篇文章中&#xff0c;我们已经探讨了 Canvas、StackPanel、WrapPanel、DockPanel、Grid 和 UniformGrid 布局容器及其使用方法。本篇博客将介绍另一种非常…

噬菌体展示技术:从诺奖成果到疫苗研发,这一 “表型 - 基因型统一” 工具如何颠覆生物研究?

1985 年,George P. Smith 首次将外源基因插入丝状噬菌体 f1 的基因 Ⅲ,让目的多肽 “展示” 在噬菌体表面 —— 这一创举诞生了噬菌体展示技术,三十多年后,该技术因在抗体筛选、表位鉴定领域的突破性贡献,助力 Sm…

从零开始学Flink:实时流处理实战

本文以Apache Flink实时流处理为核心,通过SocketWordCount示例,系统讲解实时流处理基础概念、Flink优势、代码实现与并行处理机制,助力读者掌握Flink流处理实战技能。在大数据处理领域,实时流处理正变得越来越重要…

实用指南:解决 xmlsec.InternalError: (-1, ‘lxml xmlsec libxml2 library version mismatch‘)

实用指南:解决 xmlsec.InternalError: (-1, ‘lxml & xmlsec libxml2 library version mismatch‘)pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: b…

高质量同人动画整理回顾记录的方式

爽了,每次清空网页、收藏夹释放大脑的时候都会感觉莫名的轻松,以前从来没有过这样的记录,用了几年才学来的经验啊;;; 超高质量原创动画制作,高质量同人动画太好看了,令人激动,某种内心被充盈了的感觉,只能体…

什么响应式网站莱芜新闻民生广角

一、问题描述 1、组态王【运行配置】界面没有【服务配置】的选项&#xff0c;无法将组态王Kingview配置为OPCUA服务器&#xff1b; 2、点击组态王【运行配置界面】的【服务配置】选项弹窗警告提示【试图执行的操作不受支持】&#xff0c;如下图所示&#xff1a; 二、问题分析 …

斑马打印机基础知识

斑马标签打印机分为热转印和热敏两种,其中,热转印需要碳带,热敏不需要。 热转印打印原理 打印头加热碳带上的油墨,将油墨熔化并转印到标签纸上。 热敏打印原理 打印头直接加热热敏纸,热量使涂层显现颜色成像。 热…

网站主要应用小程序开发工具代理平台

前言 2024.3.26是我在CSDN成为创作者的第128天&#xff0c;也是我第一次真正在网上创作的第128天 当我还在日常创作时&#xff0c;突然发现我收到了一封信 我想我可以分享一下这段时间的感想以及收获 机缘 在CSDN的这段时间里&#xff0c;我学习到了很多知识&#xff0c;也…

四川互联网广告人海淀区seo多少钱

System.out.print("今天开始继续读书摘录"); //不知道官方让不让我在博客里面记录 //如果不让的话我可能得转到别的上面记录 System.out.print("现在开始看《此生未完成》"); System.out.println("今天是第三天&#xff01;");有时候常常会想到那…

班级网站素材下载扬州哪家公司做网站比较好

更多技术交流、求职机会&#xff0c;欢迎关注字节跳动数据平台微信公众号&#xff0c;回复【1】进入官方交流群 火山引擎数智平台VeDI旗下的A/B测试平台&#xff08;DataTester&#xff09;&#xff0c;旨在为企业提供科学且可信的A/B测试能力及丰富的场景实验支持。随着企业的…

网站建设与维护经营范围网站 手机版网站开发合同

对比图&#xff08;截取部分&#xff09;&#xff1a; 注&#xff1a;先看分步&#xff0c;最后会附上完整代码&#xff08;如果有用&#xff0c;可以给小编点个赞吗&#xff1f;十分感谢&#xff09; 1.首先将前端返回相同的省份只展示一次 const obj {}; let keyList []r…

详细介绍:3.1 HarmonyOS NEXT分布式数据管理实战:跨设备同步、端云协同与安全保护

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …