一文解决eBpf在Android上的集成和调试

news2024/11/27 9:37:28

eBPF(Extended Berkeley Packet Filter )是一种新兴的linux内核功能扩展技术,可以无需修改内核代码,在保证安全的前提下,灵活的动态加载程序,实现对内核功能的扩展。

Android平台上也引入了对eBpf技术的支持,本文以一些典型使用场景,贯穿eBpf在android上的使用流程,展示如何在手机上集成和调试eBpf程序。

如下图示,为bpf的基本部署流程,在android上也是适用的。

一、Bpf程序编写

Android的eBpf程序源码,位于system/bpfprogs,比如打开time_in_state.c可以看到程序总体上分为三个部分:

  • 使用DEFINE_BPF_MAP定义了一些Map数据结构,这些是用来实现用户程序和内核互传数据的共享缓存。
  • 使用DEFINE_BPF_PROG,定义了一个Bpf函数,这个函数编译后,可以加载进内核,实现钩子函数的功能。
  • LICENSE("GPL") 许可协议声明。

上述中,Map的类型,以及Bpf的hook类型,根据功能的不同有许多种类,可以参考https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#program-types,里面有详细的描述。

二、Bpf程序生成

当以C语言的格式编写一个Bpf程序后,通过编译,可以得到一个 “.o” 文件。此文件是以BTF(BPF Type Format) 字节码编码的元数据格式文件,并不可以直接执行,需要加载到内核中,内核进行解析执行,或者JIT转换后执行。

BTF格式文件可查看文档:

https://www.kernel.org/doc/html/latest/bpf/btf.html

三、加载Bpf程序

Bpf程序在Android上有严格的权限控制,在bpfloader.te 中有限制bpf执行的sepolicy,限定了bpfloader是唯一可以加载bpf程序的程序。

neverallow { domain -bpfloader } *:bpf { map_create prog_load };

而bpfloader只在手机启动时执行一次,保证了其它模块无法额外加载系统之外的bpf程序,防止对内核的安全性造成危害。

在system/bpf/bpfloader/BpfLoader.cpp中,bpfloader会使用loadAllElfObjects遍历/system/etc/bpf下btf格式的”.o”文件。接着使用android::bpf::loadProg解析bpf程序文件,实现创建Bpf程序和相应的Map。

Bpfloader执行加载之后,会立即退出。Bpf程序的生命周期管理为引用计数,类似文件句柄fd,当失去所有引用时,Bpf程序和map等对象就会被销毁。

为了避免bpf prog和map对象在bpfloader执行之后被销毁, 最后会通过bpf_obj_pin把这些bpf对象映射到/sys/fs/bpf文件节点。映射的文件节点,其命名有特定的规则,以便其它的程序能够通过文件路径名称来找到对应的bpf程序。

 资料直通车:Linux内核源码技术学习路线+视频教程内核源码

学习直通车:Linux内核源码内存调优文件系统进程管理设备驱动/网络协议栈

四、Attach Bpf程序

Bpf程序被加载之后,并没有附着到内核函数上,此时bpf程序不会有任何执行,还需要经过attach操作。attach指定把bpf程序hook到哪个内核监控点上,具体有tracepoint,kprobe等几十种类型。成功attach上的话,bpf程序就转换为内核代码的一个函数。

比如attach task_rename 这个tracepoint类型,可以用

cat/sys/kernel/tracing/events/task/task_rename/format来确认参数,使得定义的bpf 函数和具体的tracepoint 函数参数一致。

如果是attach raw tracepoint,则需要自行构建参数,因为raw tracepoint 访问的是事件的原始参数,未进行参数封装,相比之下有更好一点的性能。

比如task_rename 这个tracepoint中,两种类型的参数差异:

五、Update map

当Bpf附着到内核函数上,起到了一个钩子函数的作用。钩子函数在detach之前,可以一直侦测内核的执行,有时候我们需要改变侦测的范围,或者把侦测的结果上报,此时需要使用Map,Map是用户监控程序和内核间数据交换的媒介。用户态和内核态都可以使用类似的接口来访问Map。

典型操作

  • 在Map中查找记录

void *bpf_map_lookup_elem(struct bpf_map *map, const void *key)

  • 在Map中更新记录

long bpf_map_update_elem(struct bpf_map *map, const void *key, const void *value, u64 flags)

  • 在Map中删除记录

long bpf_map_delete_elem(struct bpf_map *map, const void *key)

六、Event 上报

一般的Map数据,需要我们主动去读取里面的数据。有时候,希望有数据时,能得到通知,而不是轮询去读取。此时,可以通过perf event map实现侦听数据变化的功能。内核数据能够存储到自定义的数据结构中,并且通过 perf 事件ring缓存发送和广播到用户空间进程。

perf event map的构建流程:

上面构建流程完成后,用户态和内核态,就存在了event fd关联。接着用户态使用epoll来持续侦听fd上的通知,而fd实际上是映射到了缓存,所以当侦听到变化时,就可以到缓存中读取具体的数据。

在内核中,则通过

bpf_perf_event_output(ctx,&events,BPF_F_CURRENT_CPU, &data, sizeof(data));

来通知数据。

BPF_F_CURRENT_CPU 参数指定了使用当前cpu的索引值来访问event map中的fd,进而往fd对应的缓存填充数据,这样可以避免多cpu同时传递数据的同步问题,也解释了上面event map初始化时,为何需要创建与cpu个数相等的大小。

七、调试

实际开发中,免不了需要反复调试的过程,遵照bpf的原理,在android上重新部署一个bpf程序可以采用如下步骤。

  1. Push 新的bpf.o 文件到/system/etc/bpf/ 中。
  2. 旧版本的bpf程序和map的映射文件仍然存在,需要进入/sys/fs/bpf,rm掉映射文件。旧bpf由于没有了引用,就会被销毁。
  3. 然后再次执行/./system/bin/bpfloader,bpfloader就能够和开机时一样,把新的bpf.o再次加载起来。

注意:bpfloader在加载时打印的log太多,会触发ratelimiting,有时候发现bpfloader不能加载新的bpf程序,也不能查到有报错的信息。可以先用"echo on > /proc/sys/kernel/printk_devkmsg" 指令关闭ratelimiting,此时就能正常发现错误了。

在成功挂载bpf程序之后,还需要确认其在内核中执行的情况,使用bpf_printk输出内核log。

/* Helper macro to print out debug messages */
#define bpf_printk(fmt, ...)                \
({                            \
char ____fmt[] = fmt;                \
bpf_trace_printk(____fmt, sizeof(____fmt),    \
##__VA_ARGS__);        \
})

查看内核日志可用:

$ echo 1 > /sys/kernel/tracing/tracing_on

$ cat /sys/kernel/tracing/trace_pipe

注意:bpf程序虽然用C 代码格式书写,但其最终为内核验证执行,会有许多安全和能力方面的限制,典型的如bpf_printk,只支持3个参数输出,超过则会报错。

八、结语

Bpf 可以hook 系统调用、tracepoint和内核函数等,其应用场景相当广泛,目前在Android上的使用比较初步,还有很大的空间让我们在实践中进一步探索。

 

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

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

相关文章

NC 人力薪酬管理薪资发放流程粗略整理

NC 人力薪酬管理薪资发放流程: 1、【公共薪资项目-集团/组织】节点新增公共新增项目 2、【薪资期间-集团/组织】节点设置薪资期间 3、根据公司实际情况,如果需要,则在【薪资标准设置-集团/组织】、【薪资规则-集团/组织】两个节点设置薪资标准和薪资规则 4、在【税率表-集…

【类和对象(下)】

文章目录 🍕前言一、🍕再谈构造函数1.1构造函数体赋值1.2初始化列表1.3explicit关键字 二、🍕static成员三、🍕友元四、🍕内部类五、🍕匿名对象六、🍕拷贝对象时编译器的一些优化七、&#x1f3…

香港Web3,已走至黎明前夜 能否抓住机遇,是外界始终关注的话题?

香港对Web3的全面开放,既是挑战,又是一个不容错过的发展机遇。香港相关行业是否有足够的基础和能力抓住金融大变局的历史性契机,面向未来,完善金融生态,提升香港金融中心的国际竞争力,是外界始终关注的话题…

mongodb geohash

地理位置索引支持是MongoDB的一大亮点,这也是全球最流行的LBS服务foursquare 选择MongoDB的原因之一。我们知道,通常的数据库索引结构是B Tree,如何将地理位置转化为可建立BTree的形式,下文将为你描述。 首先假设我们将需要索引的…

Apache Doris简单易用、高性能和统一的分析数据库

Doris 介绍 https://github.com/apache/doris Apache Doris 是一个基于 MPP 架构的高性能、实时的分析型数据库,以极速易用的特点被人们所熟知,仅需亚秒级响应时间即可返回海量数据下的查询结果,不仅可以支持高并发的点查询场景,…

认识BACnet协议

一、什么是BACnet? BACnet,Building Automation and Control networks的简称,即楼宇自动化与控制网络。是用于智能建筑的通信协议。 一般楼宇自控设备从功能上讲分为两部分:一部分专门处理设备的控制功能;另一部分专…

设计模式之【代理模式】,有事找我“经纪人”

文章目录 一、什么是代理模式1、代理模式三大角色2、代理、桥接、装饰器、适配器 4 种设计模式的区别3、代理模式使用场景4、代理模式优缺点 二、静态代理1、静态代理的一般写法2、火车站售票案例3、静态代理优缺点 三、动态代理1、静态代理和动态代理的本质区别2、JDK动态代理…

ArcSWAT报错:Error Number :-2147467259; 对 COM 组件的调用返回了错误 HRESULT E_FAIL

文章目录 1 报错内容2 报错解决3 并行处理的设置补充说明 1 报错内容 通常为连续两段报错: Error Number :-2147467259 Error Message :对 COM 组件的调用返回了错误 HRESULT E_FAIL 。 Module name : mSWFlow Function name : createStream Procedure ( error li…

星辰天合参加首届数字驱动创新峰会 强调以 SDS 加速数据基础设施建设

5 月 11 日,2023 数字驱动创新峰会在北京新世纪日航饭店隆重举办。作为赛迪网、《数字经济》杂志社首次主办的数字驱动峰会,本届峰会以“新要素、新生产、新经济”为主题,下设数字金融创新论坛、数字制造创新论坛和数字服务创新论坛三个分论坛…

4 月 NFT 月报:在动荡的 NFT 市场中寻求生存

作者:lesleyfootprint.network 数据来源:Footprint NFT Research 上个月,NFT市场在 4 月 5 日出现了交易量高峰,随后交易量又在月底大幅下降了 50%。近期,NFT 卖家的数量持续超过买家的数量,这表明市场可…

4面华为测试开发,居然挂在这个地方....

说一下我面试别人时候的思路 反过来理解,就是面试时候应该注意哪些东西;用加粗部分标注了 一般面试分为这么几个部分: 一、自我介绍 这部分一般人喜欢讲很多,其实没必要。大约5分钟内说清楚自己的职业经历,自己的核…

基于Docker的深度学习环境NVIDIA和CUDA部署以及WSL和linux镜像问题

基于Docker的深度学习环境部署 1. 什么是Docker?2. 深度学习环境的基本要求3. Docker的基本操作3.1 在Windows上安装Docker3.2 在Ubuntu上安装Docker3.3 拉取一个pytorch的镜像3.4 部署自己的项目3.5 导出配置好项目的新镜像 4. 分享新镜像4.1 将镜像导出为tar分享给…

安卓源码下apk进行platform签名的方法

目录 一 任意目录下创建一个文件夹 二 该目录下需要准备的5个文件 三 执行命令 四 生成结果 一 任意目录下创建一个文件夹 二 该目录下需要准备的5个文件 上述五个文件, 前四个可以从编译好的安卓源码工程目录下复制, 第五个是自己需要签名的apk文件 …

抖音谋局本地生活“大蛋糕”|成都待慕电商

打开抖音APP,“同城”里囊括的美食、休闲娱乐、丽人美发、酒店民宿、周边旅游等让消费者们眼花缭乱,似乎正在打造另一个短视频版本的同城服务商。 4月25日,2023抖音生活服务生态伙伴大会在成都举行。《每日经济新闻》记者看到,活…

基于WiFi的CSI数据做呼吸频率检测-python版(含代码和数据)

一、概述 本Demo无需机器学习模型,Demo功能涉及的理论主要参考了硕士学位论文《基于WiFi的人体行为感知技术研究》,作者是南京邮电大学的朱XX,本人用python复现了论文中呼吸频率检测的功能。Demo实现呼吸速率检测的主要过程为: …

Java面试知识点(全)-设计模式三

Java面试知识点(全) 导航: https://nanxiang.blog.csdn.net/article/details/130640392 注:随时更新 18、责任链模式(Chain of Responsibility) 接下来我们将要谈谈责任链模式,有多个对象,每个对象持有对…

基于stm32mp157 linux开发板ARM裸机开发教程6:ARM 汇编语言程序设计(连载中)

前言: 目前针对ARM Cortex-A7裸机开发文档及视频进行了二次升级持续更新中,使其内容更加丰富,讲解更加细致,全文所使用的开发平台均为华清远见FS-MP1A开发板(STM32MP157开发板) 针对对FS-MP1A开发板&…

Scrapy 框架介绍

一、Scrapy是什么 Scrapy 是一个基于 Twisted 的异步处理框架,是纯 Python 实现的爬虫框架,其架构清晰,模块之间的耦合程度低,可扩展性极强,可以灵活完成各种需求。我们只需要定制开发几个模块就可以轻松实现一个爬虫。…

索引有哪些优缺点?索引有哪几种类型?

目录 一、什么是索引? 二、索引的优点 三、索引的缺点 四、索引有哪几种数据类型? 一、什么是索引? 索引是一种能够帮组Mysql高效的从磁盘上检索数据的一种数据结构。在MySQL中的InnoDB引擎中,采取了B树的结构来实现索引和数据…

matlabR2021b启动很慢和初始化时间很长解决

工具:MatlabR2021b。 问题记录,在网上下载安装包后,安装后,发现软件启动时间很长。进入界面后软件需要较长时间的初始化。才能就绪。 查询原因为软件需要在启动是查询licence。 首先在安装文件夹中启动Activate MATLAB R2021b。…