eBpf在Android上的集成和调试

news2025/2/27 21:13:04

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

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

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

78c83e859fcf97261208e44301694166.png

一、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程序。

四、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中,两种类型的参数差异:

77c47b0b3219441d0cc60a32c003cbbf.png

五、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的构建流程:

5cad61ce4903a28ef7cf2112d21e16ea.png

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

9d5767a3ffead8262bdedff4f7ab18a9.png

在内核中,则通过

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上的使用比较初步,还有很大的空间让我们在实践中进一步探索。

参考文献:

1.https://github.com/iovisor/bcc/blob/master/docs/kernel-versions.md#program-types

2.https://man7.org/linux/man-pages/man2/bpf.2.html

3.https://man7.org/linux/man-pages/man7/bpf-helpers.7.html

1db442b8d865e3637e1d0a311eab5f04.gif

长按关注内核工匠微信

Linux内核黑科技| 技术文章 | 精选教程

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

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

相关文章

Python—实现本地音乐播放器(添加/播放/暂停/下一首/上一首/音量/打开超链接)

文章目录 1.样例2.分析2.1播放器界面2.2功能2.2.1添加音乐,选择文件夹,显示文件夹里.Mp3文件2.2.2播放音乐,开始播放第一首音乐,按钮由"播放"变为"暂停",点击"暂停",变为"播放",播放显示Playing...2.2.3下一首,…

【ElasticSearch】分词器(ElasticSearchIK分词器)

1. 分词器介绍 •IKAnalyzer 是一个开源的,基于java语言开发的轻量级的中文分词工具包•是一个基于Maven构建的项目•具有60万字/秒的高速处理能力•支持用户词典扩展定义 2. ik 分词器安装 IK 分词器安装 3. 分词器的使用 IK分词器有两种分词模式:ik…

港科夜闻|香港科大与香港科大(广州)管理层联席会议顺利召开

关注并星标 每周阅读港科夜闻 建立新视野 开启新思维 1、香港科大与香港科大(广州)管理层联席会议顺利召开。这是自内地和香港全面恢复通关以来,两校的高级管理团队首次举行线下的联席会议,面对面交流、讨论有关两校协同发展的重要议题。两校持续深入推进…

【零基础学web前端】走进CSS的大门,CSS引入方式,CSS基础选择器,CSS复合选择器

前言: 大家好,我是良辰丫,前面我们已经学了html的相关知识,今天我们一起去探索前端网页的css,那么css到底是什么呢?我们慢慢往下看.💞💞 🧑个人主页:良辰针不戳 📖所属专栏:零基础学web前端 🍎…

二叉树层级遍历以及相关练习

二叉树层级遍历以及相关练习 文章目录 二叉树层级遍历以及相关练习思想步骤代码实现相关练习 力扣:102. 二叉树的层序遍历 - 力扣(Leetcode) 思想 层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。 使用队列实现二叉树广度优先遍…

算法修炼之练气篇——练气二十层

博主:命运之光 专栏:算法修炼之练气篇 前言:每天练习五道题,炼气篇大概会练习200道题左右,题目有C语言网上的题,也有洛谷上面的题,题目简单适合新手入门。(代码都是命运之光自己写的…

实例演示如何结合Selenium和Requests进行自动化测试

下方查看历史精选文章 重磅发布 - 自动化框架基础指南pdfv1.1大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 Selenium和Requests是两个常用的自动化测试…

Meme和BRC-20的暴跌洗盘

* * * 原创:刘教链 * * * 5月以来的Meme(模因币,发音类似“谜姆”)狂欢,有ERC-20版本的Meme比如Pepe(青蛙佩佩),也有BRC-20版本的Meme比如ordi(序数协议本身的名字&…

IM即时通讯系统[SpringBoot+Netty]——梳理(二)

文章目录 五、IM开发核心之构建TCP网关(上)1、编写LimServer2、编写LimWebSocketServer3、使用snakeyaml动态配置文件4、大白话讲通信协议—详解主流通讯协议4.1、文本协议4.2、二进制协议4.3、xml协议4.4、可以落地使用的协议 5、私有协议编解码—设计篇…

ArcGIS栅格重采样与算法选择

本文介绍在ArcMap软件中,实现栅格图像重采样的具体操作,以及不同重采样方法的选择依据。 首先,如下图所示,是我们待重采样的栅格图像的属性界面。其中,可以看到此时栅格像元的边长为0.4867左右(由于图层是地…

“技术开发最应该做什么?”,聊聊我在服务端开发5年的理解和收获

我们新推出大淘宝技术年度特刊《长期主义,往往从一些小事开始——工程师成长总结专题》,专题收录多位工程师真诚的心路历程与经验思考,覆盖终端、服务端、数据算法、技术质量等7大技术领域,欢迎一起沟通交流。 本文为此系列第二篇…

我的.net视频课程

https://edu.csdn.net/lecturer/222?spm1002.2001.3001.4144

9.并发基础与CAS基本原理

线程的状态/线程的生命周期 初始化 Thread thread new Thread();运行 thread.start(); 运行中状态 ——> 调用yeild进入就绪状态就绪状态 ——> 通过系统调度(获取到cpu时间片),又会进入到运行中状态 等待 调用如下方法就从运行进入到等待状态: Object.wait()、Object.…

2360. 图中的最长环

方法一&#xff1a;拓扑排序加搜索 class Solution { public:bool vis[100005];vector<int>v[100005];int dfs(vector<int> &dist,int st,int step){vis[st]true; // cout<<st<<endl;int res0;for(int i0;i<v[st].size();i){int xv[st][i];if(…

Angular开发之——Angular项目介绍(03)

一 概述 Angular项目目录介绍Angular程序如何启动 二 Angular项目目录介绍 2.1 项目目录 2.2 目录结构说明 工作区配置文件 node_modules &#xff1a;第三方依赖包存放的目录src&#xff1a;应用源代码目录angular-cli.json&#xff1a; Angular命令行工具的配置文件&…

设计模式之桥接模式释义与举例剖析

文章目录 一、前言二、模式定义三、模式结构四、案例具体实现五、 模式优缺点六、 模式使用场景七、 模式总结 一、前言 开始学Java讲继承的时候&#xff0c;总喜欢用一个例子来讲解&#xff0c;那就是画图形。这里有一个画笔&#xff0c;可以画正方形、长方形、圆形。除了画出…

OpenCV-答题卡识别-四点透视变换

目录 答题卡识别图片读取四点透视变换 划出区域处理选择题区域处理准考证号区域处理科目区域得分导出结果 封装成品 答题卡识别 使用opencv技术&#xff0c;实现对答题卡的自动识别&#xff0c;并进行答题结果的统计 技术目的&#xff1a; 能够捕获答题卡中的每个填涂选项;将…

【新星计划-2023】TCP三次握手和四次挥手讲解

关于TCP三次握手和四次挥手&#xff0c;各位想必在读大学的时候或者是在面试的时候一定遇到过&#xff0c;三次握手和四次挥手本身是不是太难的&#xff0c;但它容易忘&#x1f61e;&#xff0c;今天我就在这里给大家讲解一下三次握手与四次挥手。 一、三次挥手 TCP三次握手建…

我,大厂P9,找不到工作

作者| 老W 编辑| Emma 来源| 技术领导力(ID&#xff1a;jishulingdaoli) K哥写在前面的话&#xff1a;这是一位读者投稿&#xff0c;读者老W讲述了自己从大厂P9失业后、再就业的故事&#xff0c;并总结了自己的心路历程&#xff0c;很真实的记录与思考&#xff0c;值得大家借…

SensorX2car:在道路场景下的完成传感器到车体坐标系标定

文章&#xff1a;SensorX2car: Sensors-to-car calibration for autonomous driving in road scenarios 作者&#xff1a;Guohang Yan, Zhaotong Luo, Zhuochun Liu and Yikang Li 编辑&#xff1a;点云PCL 代码&#xff1a;https://github.com/OpenCalib/SensorX2car 作者单位…