我的NPI项目之设备系统启动(八) -- Android14的GKI2.0开发步骤和注意事项
GKI是什么? Google为什么要推行GKI?
GKI全称General Kernel Image。GKI在framework和kernel之间提供了标准接口,使得android OS能够轻松适配/维护/兼容不同的设备和linux kernel。
Google引入GKI的目的是将Framework和Kernel进一步的解耦。因为,android一直高度依赖linux kernel, linux kernel一更新,android系统就要跟着适配更新。google发步的安全patch,也会因为kernel的版本而掣肘。
通用内核映像 (GKI) 项目通过统一核心内核并将 SoC 和板级支持从核心内核移至可加载模块中,解决了内核碎片化问题。GKI 内核为内核模块提供了稳定的内核模块接口 (KMI),因此模块和内核可以独立进行更新。
内核碎片化带来的问题:(市面上的内核版本太多,严重阻碍了Android的迭代更新),具体描述如下:
1. 安全更新需要耗费大量人力
Android 安全公告 (ASB) 中引用的安全补丁程序必须向后移植(旧的android 系统)到每个设备内核中。但是,由于存在内核碎片化问题,向正常使用的 Android 设备传播安全修复的代价非常之高。
2. 很难合并长期支持的更新
长期支持 (LTS) 版本包含安全修复和其他重大问题修复。事实证明,使用最新的 LTS 版本是提供安全修复的最有效方式。我们发现,ASB 报告的内核安全问题中有 90% 都已在保持最新状态的 Pixel 设备上得到修复。(简单一句话,打补丁不如升级OS)
不过,由于设备内核中所有的自定义修改,很难仅将 LTS 修复合并到设备内核中。
3. 妨碍 Android 平台进行版本升级
由于碎片化问题,很难向正常使用的设备添加需要更改内核的 Android 新功能。Android 框架代码必须假设支持的内核版本多达 5 个,并且没有针对新的平台版本进行任何内核更改(Android 10 支持内核版本 3.18、4.4、4.9、4.14 和 4.19;在某些情况下,这些版本自 2017 年 Android 8 发布以来还未添加新功能)。
4. 很难将内核更改贡献回上游 Linux
对内核进行完所有更改后,大多数旗舰设备附带的内核版本已经至少存在 18 个月了。例如,kernel.org 于 2017 年 11 月发布了 4.14 版内核,而首批使用 4.14 版内核的 Android 手机于 2019 年春季才发布(新特性上推linux main branch就太晚了)。
上游内核发布与产品发布之间的这种长时间延迟导致 Android 社区很难将所需的功能和驱动程序馈送到上游内核中,因此解决碎片化问题并非易事。
于是就有了GKI项目!!!!!大家还记得从Android8引入的Trible 机制吗?也是Android将framwork和linux kernel解耦的一个项目。
总而言之,无论是Android还是Apple OS 都是希望能够将自己的最新OS推送到尽可能多的设备上,从而抢占市场分额!
核心特性和目标如下:
1. 基于 ACK 来源构建而成。(ACK , Android/Aosp common kernel,Android最上游代码)
2. 是每个架构和每个 LTS 版本的单内核二进制文件以及关联的可加载模块(目前只有适用于 android11-5.4 和 android12-5.4 的 arm64)。
3.已经过关联 ACK 支持的所有 Android 平台版本的测试。在 GKI 内核版本的生命周期内不会发生功能弃用。
4. 为给定 LTS 中的驱动程序提供了稳定版 KMI。
5. 不包含 SoC 专用代码或板卡专用代码。(这个很好理解,不包含e.g specifc Qualcomm and Board code)。
Key features and goals of Android GKI include:
Stability(稳定性): The GKI aims to maintain a stable ABI(Application Binary Interface//应用程序二进制接口), ensuring that the Android framework can work with different kernel versions without requiring modifications.
Compatibility(兼容性): GKI enables Android to run on a wide range of devices with different kernel configurations, reducing fragmentation and enabling faster updates.
Portability(可移植性): By abstracting Android from the underlying kernel, GKI simplifies the process of porting Android to new devices and adapting it to different kernel versions.
Security(安全性): GKI facilitates the timely delivery of security patches(通常是Google的安全性补丁) and updates by decoupling the Android framework from the kernel, allowing for more efficient patching processes.
GKI可以更改吗?
通常在开发中我们不修改,而且其GKI镜像中的内容配置文件,我们也不可以修改,例如:
../kernel_platform/msm-kernel/arch/arm64/configs/gki_defconfig
但是Android的官网也提供了修改的方法,如下说明,分别有三个方面(再次提醒,通常作为ODM是不改的,(Android(ACK) / Qualcomm(供应商内核) / ODM(设备内核));
1. 将新功能配置为 GKI 模块。
2. 将内置内核功能配置为 GKI 模块。
3. 将受保护的 GKI 模块转换为不受保护的模块。
以上三个类型的修改,后面需要的时候可以进一步细看。有一个提醒就是,无论哪个修改,都必需需要提交更改以供审核。GKI 模块是 Android 专用内核功能,因此无需在上游提交模块转换补丁。不过,您必须按照其他准则提交 Android 通用内核 (ACK) 补丁。
什么是ACK,简称AOSP Common Kernel,应该是和LKML几乎一样的分支内容。官网的解释是
AOSP 通用内核(也称为 Android 通用内核或ACK https://android.googlesource.com/kernel/common/ )是kernel.org内核的下游,包含 Android 社区感兴趣的尚未合并到主线或长期支持 (LTS) 内核中的补丁。
官网对android-mainlin做简单介绍:
android-mainline
是 Android 功能的主要开发分支。每当 Linus Torvalds 发布版本或候选版本时,Linux 主线就会合并到android-mainline
中。 2019 年之前,Android 通用内核是通过克隆最近声明的 LTS(Long Time Support) 内核并添加 Android 特定补丁来构建的。这个过程在 2019 年发生了变化,从android-mainline
分支出新的 Android 通用内核。这种新模型通过逐步实现相同的结果,避免了转发端口和测试 Android 补丁的大量工作。 android-mainline
经过重要的持续测试,该模型从发布之日起就确保了高质量的内核。
当上游声明一个新的 LTS 时,相应的公共内核将从android-mainline
分支出来。这允许合作伙伴在声明 LTS 版本之前通过从android-mainline
合并来开始项目。创建新的通用内核分支后,合作伙伴可以无缝地将合并源更改为新分支。
其他常见的内核分支从其关联的LTS 内核接收定期合并。这些合并通常在 LTS 版本发布后立即完成。例如,当 Linux 4.19.64 发布时,它被合并到 4.19 通用内核中(例如android-4.19-q
)。强烈鼓励合作伙伴(Qualcomm ? MTK?) 定期将通用内核(GKI)合并到其产品内核中,以及时了解 LTS 和 Android 特定错误修复的最新情况(Qualcomm 会不定期的去合并Android的通用内核补丁)。
所以,想给ACK 提交补丁一定是要经过严格省查的。所以,作为ODM开发中,通常不会这么做。对处理器/个别电子器件精通的内核维护者通常能够给linux内核提交patch,那也绝对是行业大牛;通常ODM开发内核中的驱动,我们通常需要定义在自己的config文件中,并且是一=m的形式进行编译。开机过程中,需要进行动态加载的。这个是目前GKI2.0的基本要求。
官网对GKI KMI内核分支介绍
GKI 内核具有稳定的内核模块接口。 KMI (内核模块接口)由内核版本和 Android 平台版本唯一标识,因此分支被命名为<androidRelease>-<kernel version>
。例如,Android 11 的 5.4 GKI 内核名为android11-5.4.
对于 Android 12,还有两个额外的 GKI 内核: android12-5.4
和android12-5.10
。kernel_platform/msm-kernel/Makefile. 我的高通平台是从Android 12 launch的。
也就是说,Android发布时候会绑定对应的linux kernel版本,目的是提供一个固定KMI。后续开发者可以根据KMI中的接口,进行对应的内核开发。
从 Android 12 开始,功能内核将少于启动内核,以限制功能内核的数量必须支持的稳定 KMI。
简单看下KMI的时间线:
每个 ACK KMI 分支都会循环经历三个阶段: 例如android12-5.10
开发阶段:
创建后,ACK KMI (我理解这是一个kernel分支,GKI则是对应的内核镜像)分支进入开发阶段(图 2 中的dev ),并开放为下一个 Android 平台版本提供功能贡献。当 5.10 被声明为新的上游 LTS 内核时,创建了android12-5.10
。内核版本的第二个 ACK KMI 分支可能会提前创建,以允许后续版本的开发。android13-5.10
是在android12-5.10
过渡出开发阶段时创建的。
稳定阶段:
当 ACK KMI 分支声明功能完成时,它会进入稳定阶段,在图 2 中标记为稳定阶段。合作伙伴功能和错误修复仍然被接受(合作伙伴:e.g Qualcomm),但启用了 KMI 跟踪以检测影响接口的任何更改。在此阶段,会接受破坏 KMI 的更改,但必须根据需要更新 KMI 定义。有关 KMI 监控的详细信息,请参阅GKI 概述。
冷冻阶段:
在将新平台版本推送到 AOSP 之前,ACK KMI 分支会被冻结,并在分支的生命周期内保持冻结状态。这意味着,除非发现严重的安全问题,且无法在不影响稳定 KMI 的情况下缓解,否则不会接受任何破坏 KMI 的更改。为了避免 KMI 损坏,如果 Android 设备不需要修复,则可能会修改或删除从 LTS 合并的一些补丁。
GKI1.0的情况,这里就不多解释,有个核心的要求是:GKI 1.0 不要求供应商模块可卸载,可以=y。
我们看看GKI2.0的情况下,
GKI 2.0 - GKI 产品
搭载 Android S (2021) 平台版本且使用内核版本 v5.x(5.x 是 2020 年年底被选为 LTS 的内核版本)或更高版本的设备必须附带 GKI 内核(将提供已签名的启动映像,并通过 LTS 和重大问题修复定期对其进行更新。由于 KMI 将保持二进制稳定性,因此无需对供应商映像进行任何更改,即可安装这些启动映像。
GKI 2.0 的目标
1. 不为 GKI 引入明显的性能或能效降低问题。
2. 使 OEM 无需供应商参与即可提供内核安全修复和问题修复 (LTS)。(是说OEM直接从Google 获取补丁?而不用从e.g Qualcomm获取?)
3. 降低更新设备主要内核版本(例如,将 v5.x 更新为 v5.y)所需的费用。(通常我们的升级直接从Qualcomm拉代码)
4. 通过按照清晰的升级过程更新内核版本,只为每个架构(例如Qualcomm6490 Armv7 架构)维护一个 GKI 内核二进制文件。
开发有关:
GKI2.0 下的内核开发,首先要注意,需要遵循GKI2.0中要求的ABI接口检查,目的是,你不能更改KMI中的接口。这个部分,可以在编译中进行检查。
详细的说明如下ABI检查如下:
ABI 工具使用 KMI 符号列表来限制必须监控哪些接口以实现稳定性。主符号列表包含 GKI 内核模块所需的符号。供应商应提交并更新其他符号列表,以确保其依赖的接口保持 ABI 兼容性。
符号列表包含报告的特定供应商或设备所需的符号。工具使用的完整列表是所有 KMI 符号列表文件的并集。ABI 工具会确定每个符号的详细信息,包括函数签名和嵌套数据结构。
当 KMI 被冻结时,不允许对现有 KMI 接口进行任何更改;它们是稳定的。
当有补丁改动了KMI 接口或者数据结构(例如include/linux/mmxx.h),应用此补丁后再次运行 build ABI 时,该工具会退出,同时显示非零错误代码并报告ABI错误。例如:
Leaf changes summary: 1 artifact changedChanged leaf types summary: 1 leaf type changedRemoved/Changed/Added functions summary: 0 Removed, 0 Changed, 0 Added functionRemoved/Changed/Added variables summary: 0 Removed, 0 Changed, 0 Added variable'struct mm_struct at mm_types.h:372:1' changed:type size changed from 6848 to 6912 (in bits)there are data member changes:[...]
最常见的错误原因是,驱动程序使用了内核中不在符号列表中的新符号。目前,我使用的符号表是:hon4490-android14-vendor/kernel_platform/common/android/abi_gki_aarch64_qcom,当出现问题时,第一时间检查该接口是否在符号列表中。
最后,新的设备驱动是需要单独配置到kernel configure中,而且必需以=m的形式进行,这是GKI2.0的标准要求。
举个例子:
例如,需要往内核中添加一个新的设备驱动,Touch的驱动。
1. 修改上一层目录中的Kconfig/Makefile,添加驱动编译规则,例如
obj-$(CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS) += xxx.o
那么,同样需要将CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS编译选项添加到整个内核的编译配置中,才能够在编译内核的时候进行编译。
这里使用到的就是 configs/vendor/xxx_GKI.config , 添加CONFIG_TOUCHSCREEN_ATMEL_MAXTOUCH_TS=m的编译配置。其实同样可以添加到configs/vendor/xxx_consolidate.config。这里的区别是什么?原来,xxx_consolidate.config是编译userdebug时候被包含的配置文件。
那关于GKI2.0的大概历史就是这样,相关的开发注意事项需要结合开发过程进行深化理解。
实干出真知!
相关文章:

我的NPI项目之设备系统启动(八) -- Android14的GKI2.0开发步骤和注意事项
GKI是什么? Google为什么要推行GKI? GKI全称General Kernel Image。GKI在framework和kernel之间提供了标准接口,使得android OS能够轻松适配/维护/兼容不同的设备和linux kernel。 Google引入GKI的目的是将Framework和Kernel进一步的解耦。因…...

鼠标右键助手专业版 MouseBoost PRO for Mac v3.3.6中文破解
MouseBoost Pro mac版是一款简单实用的鼠标右键助手专业版,MouseBoost Pro for Mac只要轻点你的鼠标右键,就可以激活你想要的各种功能,让你的工作效率大幅度提高,非常好用。 软件下载:MouseBoost PRO for Mac v3.3.6中…...
React学习计划-react-hooks补充
React Hooks 1. 使用hooks理由 高阶组件为了复用,导致代码层级复杂生命周期的复杂 2. useState(保存组件状态) const [state, setstate] useState(initialState)3. useEffect(处理副作用)和useLayoutEffect(同步执行副作用) 使用方式: useEffect(…...

KTV点歌系统vue+springboot音乐歌曲播放器系统
目前现有的KTV点歌系统对于用户而言其在线点歌流程仍然过于繁琐,对于歌曲而言其系统安全性并不能保障。同时整套系统所使用的技术相对较为落后,界面不能动态化展示。相比较于其它同类型网站而言不能体现技术先进性。 1.2 项目目标 KTV点歌系统的后台开发…...

vue video 多个视频切换后视频不显示的解决方法
先说一下我这边的需求是视频需要轮播,一个人员有多个视频,左右轮播是轮播某个人员下的视频,上下切换是切换人员。 vue 代码 <el-carouselindicator-position"none"ref"carousel"arrow"always":interval&qu…...
多态与代码屎山
到底什么是多态呢?多态是面向未来的,比如企业采购为例: 一般分为线上合线下两种, 我们设计一个父类叫做"采购", 里面做一些共通的处理: 申请, 承认, 支付, 购买方式. 然后让各自的子类(线上,线下)实现自己的方法.实际调用过程中传入不同的对象就可以.到此为止项目开…...

Git基本操作(2)
Git基本操作(2) 上交文件之后,git文件的变化git cat-file HEAD指针里面有啥文件被修改git statusgit diff 文件名 版本回退(git reset)撤销回退git reflog 撤销的三种情况还没有addgit checkout -- [file] 已经add还没…...
编程笔记 Golang基础 023 切片
编程笔记 Golang基础 023 切片 一、切片二、定义与初始化三、基本操作四、示例 Go语言中的切片(slices)是基于数组的抽象数据类型,它提供了一种灵活的方式来处理可变长度的数据序列。切片本身不存储任何数据,而是指向底层数组的一…...

qt 软件发布(Windows)
1. 开发环境 QtCreator MSVC编译器 2. 源码编译 生成release或者debug版本的exe可执行文件(x64或x86) 3. windeployqt 打包 ①左下角开始菜单栏找到QT的命令交互对话框,如下图MSVC 2017 64-bit(根据第二步编译的类型选择64位或者32位)。 ②cd 切换到第二步可…...

《汇编语言》- 读书笔记 - 第11章-标志寄存器
《汇编语言》- 读书笔记 - 第11章-标志寄存器 标志寄存器指令与标志位关系11.1 ZF(Zero Flag,零标志位)11.2 PF(Parity Flag,奇偶标志位)11.3 SF(Sign Flag,符号标志位)处…...

1.QT简介(介绍、安装,项目创建等)
1. QT介绍 Qt(官方发音 [kju:t])是一个跨平台的C开发库,主要用来开发图形用户界面(Graphical User Interface,GUI)程序 Qt 是纯 C 开发的,正常情况下需要先学习C语言、然后在学习C然后才能使用…...

【服务器】服务器推荐
一、引言 在数字世界的浪潮中,服务器作为数据存储和处理的基石,其重要性不言而喻。而在这个繁星点点的市场中,雨云以其独特的优势和超高的性价比,逐渐成为众多企业和个人的首选。今天,就让我带你走进雨云的世界&#…...

信号系统之线性图像处理
1 卷积 图像卷积的工作原理与一维卷积相同。例如,图像可以被视为脉冲的总和,即缩放和移位的delta函数。同样,线性系统的特征在于它们如何响应脉冲。也就是说,通过它们的脉冲响应。系统的输出图像等于输入图像与系统脉冲响应的卷积…...

uniapp腾讯地图JavaScript Api,H5端和原生APP端可用
因项目需要,在uniapp中集成使用腾讯地图,为了方便维护,希望通过一套代码实现H5和APP同时可用。H5显示相对简单,APP端比较麻烦,记录下实现过程 一、集成步骤 1.使用 renderjs script标签使用renderjs,因为…...

MyBatisPlus:PG数组类型自动映射问题
引言: PostGreSQL数据库提供了丰富的数据类型,通过查看官网文档,我们也可以发现,PG也提供了对数组类型的支持。 但是在实际开发中,我们通常是使用MyBatis/MyBatisPlus这种半自动ORM映射框架来实现数据库/表数据基本的增删改查,以及其它操作。那么,问题来了,如何…...

Data-Shape制作UI节点简介
很多小伙伴对于Data-Shape制作简单的UI都是似懂非懂,群里很多小伙伴也总是询问相关的问题,那么,今天我就简单举几个例子,专门介绍下Data-Shape创建简单UI的教程。 首先,本次教程,使用的是Data-Shape 2021.…...

kubernetes负载均衡部署
目录 1.新master节点的搭建 对master02进行初始化配置(192.168.88.31) 将master01的配置移植到master02 修改master02配置文件 2.负载均衡的部署 两台负载均衡器配置nginx 部署keepalived服务 所有node节点操作 总结 实验准备: k8s…...

NestJS入门6:日志中间件
前文参考: NestJS入门1 NestJS入门2:创建模块 NestJS入门3:不同请求方式前后端写法 NestJS入门4:MySQL typeorm 增删改查 NestJS入门5:加入Swagger 1. 安装 nest g middleware logger middleware 2. lo…...
CommonJS、require、moudle实现两个文件传参
目的:实现两个文件传参 文件A给B传入一个参数,并且文件B代码执行后再传回A。 场景 拆分express项目中的app.js文件中的路由、项目越大会使app.js文件变大,复杂 如何使用 app.js文件 导入路由文件调用路由文件,调用的时候传入…...
关于php、php-fpm的解释
PHP语言是由PHP程序解释的,而不是由php-fpm程序解释的。 PHP(Hypertext Preprocessor)是一种通用开源脚本语言,最初是为创建动态Web页面而设计的,但现在也可以用于命令行脚本编写等用途。PHP程序通常由Web服务器&…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明
LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造,完美适配AGV和无人叉车。同时,集成以太网与语音合成技术,为各类高级系统(如MES、调度系统、库位管理、立库等)提供高效便捷的语音交互体验。 L…...

【机器视觉】单目测距——运动结构恢复
ps:图是随便找的,为了凑个封面 前言 在前面对光流法进行进一步改进,希望将2D光流推广至3D场景流时,发现2D转3D过程中存在尺度歧义问题,需要补全摄像头拍摄图像中缺失的深度信息,否则解空间不收敛…...
大语言模型如何处理长文本?常用文本分割技术详解
为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
数据链路层的主要功能是什么
数据链路层(OSI模型第2层)的核心功能是在相邻网络节点(如交换机、主机)间提供可靠的数据帧传输服务,主要职责包括: 🔑 核心功能详解: 帧封装与解封装 封装: 将网络层下发…...

多种风格导航菜单 HTML 实现(附源码)
下面我将为您展示 6 种不同风格的导航菜单实现,每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

莫兰迪高级灰总结计划简约商务通用PPT模版
莫兰迪高级灰总结计划简约商务通用PPT模版,莫兰迪调色板清新简约工作汇报PPT模版,莫兰迪时尚风极简设计PPT模版,大学生毕业论文答辩PPT模版,莫兰迪配色总结计划简约商务通用PPT模版,莫兰迪商务汇报PPT模版,…...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...