Google在android11-5.4分支上开始要求所有下游厂商使用Generic Kernel Image(GKI),需要将SoC和device相关的代码从核心内核剥离到可加载模块中(下文称之为GKI改造),从而解决内核碎片化问题。GKI为内核模块提供了稳定的内核模块接口(KMI),模块和内核可以独立更新。本文主要介绍了在GKI改造过程中需遵循的原则、遇到的问题和解决方法。

一、不能破坏KMI

冻结KMI后,分支在其整个生命周期中都保持冻结状态,原则上不会接受破坏KMI的修改(除非发现严重的安全问题,且不能在不影响KMI稳定的情况下得到缓解)。在冻结的分支中,只有不破坏KMI的bug修复和partner features才能被接收。在不影响现有KMI接口的前提下,可以使用新导出的符号扩展KMI,新接口被接收添加到KMI后,必须保持稳定,不能被将来的修改破坏。

1. 问题现象:

替换google boot.img后,开机串口有如下打印错误,

[    1.669135] init: Loading module /lib/modules/foo.ko with args ""

[    1.676281] foo: disagrees about version of symbol xxx

2. 原因分析:

出现这种错误可能的原因是ko中调用的符号与vmlinux中的符号crc值不匹配,如在KMI接口使用的结构体中增加了新字段,间接地修改了接口定义:

3. 推荐方法:

(1) 扩展内核原生结构体和接口

(2) 向google申请,在内核原生结构体中加入一些padding

Google在android11-5.4分支中新增了两个宏

ANDROID_VENDOR_DATA,在结构体中保留一些padding以备将来可能的使用,这些padding正常的都是位于结构体尾部,padding变量标识n从1开始递增。

ANDROID_VENDOR_DATA_ARRAY同ANDROID_VENDOR_DATA,分配一个数组,数组大小是s,元素是u64类型。

下面是使用ANDROID_VENDOR_DATA和ANDROID_VENDOR_DATA_ARRAY在内核结构体中增加新字段的示例:

4. 措施:

在编译脚本中增加检测,编译GKI kernel后,比较生成的Module.symvers和原生android/abi_gki_aarch64.xml文件中符号的crc值,如果crc值不匹配,编译报错,表示使用了非规则的方法修改原生接口或结构体。

二、内核模块只能使用已export并添加到白名单中的接口

android11-5.4分支build.config.gki.aarch64文件中有如下配置

表示模块只能使用abi_gki_aarch64文件中的符号。

1. 问题现象:

替换google boot.img后,串口有如下打印错误:

[    1.735506] foo: Unknown symbol xxx(err -2)

2. 原因分析:

原生内核没有用EXPORT_SYMBOL_GPL把接口xxx export,或已经export的接口没有添加到白名单(该接口abi可能不稳定)

3. 推荐方法:

(1)  Google建议向上游linux社区申请将要使用的内核接口export,并向Google申请,将接口添加到白名单android/abi_gki_aarch64_xxx

(2)使用其他已在白名单中的接口替代。

三、vendor hook机制

考虑到SoC和OEM厂商可能要对原生内核做一些客制化修改和优化,Google提供了一套vendor hook机制,下游厂商在需要修改内核源码的地方添加hook,并向Google申请,将patch upstream到AOSP。

1. vendor hook实现步骤如下:

(1) 在include/trace/hooks/目录下创建一个新的头文件xxx.h,定义一组hook接口register_trace_android_vh_xxx、trace_android_vh_xxx和全局变量__tracepoint_android_vh_xxx

(2) 在drivers/android/vendor_hooks.c文件中包含hook头文件xxx.h,export hook变量__tracepoint_android_vh_xxx给模块使用

(3)在内核模块中增加register代码将回调函数绑定到hook变量__tracepoint_android_vh_xxx

(4) 在内核xxx.c文件中包含hook头文件xxx.h,调用hook接口trace_android_vh_xxx(即hook变量__tracepoint_android_vh_xxx绑定的callback函数)

2. 问题现象:

测试偶现dump “BUG: scheduling while atomic:”

3. 原因分析:

vendor hook变量有两种,都是基于tracepoints的:

正常的:使用DECLARE_HOOK宏创建tracepoint函数trace_<name>,要求name在trace中是独一无二的,callback函数的调用是在关抢占的场景中使用的

受限制的:受限制的hook在scheduler hook类的场景中使用,绑定的callback函数可以在cpu offline或非原子上下文中调用(调用前没有关抢占),受限制的vendor hook不能被解绑定,所以绑定的模块不能卸载,只允许有一个绑定(任何其他绑定将会返回-EBUSY错误)。

4. 推荐方法:

根据使用场景选择适合的vendor hook变量,在可能会调度的场景需要使用受限制的vendor hook

四、vendor hook延伸

SoC和OEM feature都要从内核剥离出来编译成内核模块,内核源码中相互调用export接口是没有问题的,那么模块之间相互调用export接口呢?

1. 问题现象:

编译报错 depmod: ERROR: Found 2 modules in dependency cycles!

2. 原因分析:

模块之间相互调用export接口,导致编译时报错。

3. 推荐方法:

借鉴Google的vendor hook机制,在A模块中定义并export全局变量,B模块初始化函数中将callback函数注册绑定到该全局变量,这样只有B模块调用A模块中的变量和接口,A模块通过hook变量回调B模块中接口,解决编译调用问题。

五、通过内核已有的事件注册接口替代vendor hook

是不是只能通过vendor hook实现修改内核呢?

android11-5.4分支log中有这么一笔关于vendor hook的提交:

为按键组合增加vendor hook

我们注意到内核中有一个接口input_register_handle,它的注释是注册一个新的input handle,添加到设备和handle列表中,只要使用input_open_device()接口打开设备,输入事件触发后会轮询到该handle,input_register_handle接口应该在handler的connect方法中调用,因此我们可以使用input_register_handler、input_register_handle来实现上述的按键组合功能,不需要在内核中增加vendor hook。

通过这个改造示例,启发我们思考是否只能使用vendor hook机制,是否可以使用其他内核已有的机制、事件注册接口将原先嵌入在内核中的feature剥离出来。

参考文章

[1]  https://source.android.com/devices/architecture/kernel/generic-kernel-image

[2]  https://blog.csdn.net/geshifei/article/details/94360470

[3]  https://blog.csdn.net/qq_39937242/article/details/82631165

长按关注

内核工匠微信

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

GKI改造原则、机制和方法相关推荐

  1. jdbc mysql 自动重连_JDBC实现Mysql自动重连机制的方法详解

    JDBC是Java程序连接和访问各种数据库的API,它可以提供Java程序和各种数据库之间的连接服务,下面是爱站技术频道小编为大家带来的JDBC实现Mysql自动重连机制的方法详解. 日志:using ...

  2. 我的世界服务器刷怪笼怎么修改,我的世界改造刷怪笼的方法,有三种方法介绍...

    原标题:我的世界改造刷怪笼的方法,有三种方法介绍 大家好,我是海底蛟龙解说,今天向大家分享一下我的世界改造刷怪笼的方法.下面是我的改造方法,你可以参照其他更多人的改造办法来建造修建 方案一:手动杀怪类 ...

  3. KDD 2021 | Neural Auction: 电商广告中的端到端机制优化方法

    ▐  导读 拍卖机制设计一直是计算广告领域的核心问题,在本文中我们将机器学习和机制设计方法深度融合,提出一种基于深度神经网络建模的电商广告拍卖机制,并在满足 Value 最大化广告主激励兼容的机制解空 ...

  4. java 心跳程序_Java实现心跳机制的方法

    一.心跳机制简介 在分布式系统中,分布在不同主机上的节点需要检测其他节点的状态,如服务器节点需要检测从节点是否失效.为了检测对方节点的有效性,每隔固定时间就发送一个固定信息给对方,对方回复一个固定信息 ...

  5. php网页事件处理方法,PHP实现事件机制的方法

    本文实例讲述了PHP实现事件机制的方法.分享给大家供大家参考.具体如下: /** * 事件 */ class Event { private $callbacks = array(); private ...

  6. php ci hooks,CodeIgniter框架钩子机制实现方法【hooks类】

    本文实例讲述了CodeIgniter框架钩子机制实现方法.分享给大家供大家参考,具体如下: 记得上一次去到喜啦面试,面试官问我一个问题:codeigniter是如何实现钩子机制的? 当时答不上来,后来 ...

  7. OC语言基础一:OC方法调用机制,new方法实现原理

    文章目录 OC方法调用机制 new方法实现原理 野指针 内存溢出 内存泄漏 alloc和init OC方法调用机制 OC有两种方法 Person *person=[Person new]; [pers ...

  8. 计算机维修应遵循先硬件后软件的原则,计算机硬件维护的原则和及方法

    计算机硬件维护的原则和及方法 伴随着社会经济的迅速发展以及网络信息时代的快速到来,计算机的普及运用越来越广泛,已成为人们日常生活中不可缺少的工具,随之而来的是人们对计算机硬件方面的维护要求也逐渐提升. ...

  9. java tcp 心跳机制_Java实现心跳机制的方法

    一.心跳机制简介 在分布式系统中,分布在不同主机上的节点需要检测其他节点的状态,如服务器节点需要检测从节点是否失效.为了检测对方节点的有效性,每隔固定时间就发送一个固定信息给对方,对方回复一个固定信息 ...

最新文章

  1. 人群分析综述--Crowd Scene Understanding from Video: A Survey
  2. Swift学习——Swift解释特定的基础(七)
  3. MacOS系统下简单安装以及配置MongoDB数据库(一)
  4. open session and Hibernate事务处理机制
  5. JSON是什么,为什么这么流行?
  6. maya python 弹出窗口_maya python打印状态复选框?
  7. 怎么使用ar打包静态库
  8. java c s是什么_Java在C/S
  9. 力扣225-用队列实现栈(C++,附思路及优化思路,代码)
  10. 高性价比手持机有哪些
  11. 吾爱破解crackme 023 024
  12. 注册Google的步骤
  13. DOTween的常用方法
  14. 所有人望向黑洞那一刻,我们短暂地共享了 5500 万光年外的世界
  15. GBA火焰纹章改版-智慧的结晶2.0更新(发布)
  16. 期货反跟单-侃侃人工反跟单那些事儿
  17. 沉痛悼念张孝祥老师逝世
  18. 在GATE中用ICTCLAS处理多个文档
  19. 酒店行业如何借助无线认证提高营销能力
  20. 小鸡手柄android,简便易懂的连接方式_小鸡 Gamesir-G3_DIY攒机手柄-中关村在线

热门文章

  1. c++ WinAPI 获取文件被占用的进程信息
  2. 细数在阿里巴巴工作的N种幸福
  3. 爬虫:获取某著名旅游城市的楼盘信息
  4. easyexcel分页导出多个excel
  5. RubyConf China 2021 Hotwire 讲师征集
  6. 摩尔斯 (Morse )编码
  7. python调用子函数时参数传递问题
  8. 《嵌入式系统》知识总结2:Cortex-M3处理器和STM32
  9. LiveGBS中接入的设备一键分享GB28181查看设备端录像
  10. linux下编译snmp++报crypt冲突