迅速入门Android内核编译 & 一加5 DC调光
本文最后更新于 1623 天前,其中的信息可能已经有所发展或是发生改变。

迅速入门Android内核编译 & 一加5 DC调光

前言:本篇博文只是简单介绍了利用ARM official GCC 交叉编译Git平台上提供的Android开源内核。并不涉及太多优化或是深入研究。最好提前熟练使用Git分支管理,并且知道一些基本的编译原理。(虽然你照着抄不会也能做,但是细节可能容易坑)

乱扯:这篇文章是总结前几天给我的Oneplus 5编译加DC调光的blu_spark内核的过程。其间踩了一点坑,因为自己也是零基础所以觉得自己踩的一些坑应该有一定借鉴意义?为什么要编译内核呢,还不是因为Redmi K30 Pro的费拉不堪的屏幕,第一次“头顶青天脚踏草原”,直接让我有了一加5再战3年的想法,又有dalao做出了内核层面的遮罩DC驱动,就想着动手加上DC调光了。

环境准备

工欲善其事,必先利其器。如果要编译内核,我们需要先准备好交叉编译工具链。那么什么是交叉编译?交叉编译指一个在某个系统平台下可以产生另一个系统平台的可执行文件的编译过程。 也就是我们的个人电脑基本运行在X86架构上,而手机的内核却运行在ARM架构上,因为处理器不同,实际上他们执行的机器码也不相同,直接表现就是反汇编出来的指令不同。我们系统自带的编译器都是直接Platform:x86 target:x86的存在,而如果要运行内核,就必须要以target: arm/aarch64编译。(你可以把aarch64和arm理解成amd64和x86)

首先我们需要安装基础运行编译环境(base ubuntu/debian),因为编译器运行依赖一些动态库

sudo apt update && sudo apt -y dist-upgrade
sudo apt install -y gcc g++ python make texinfo texlive bc bison build-essential ccache curl flex g++-multilib gcc-multilib git gnupg gperf imagemagick lib32ncurses5-dev lib32readline-dev lib32z1-dev liblz4-tool libncurses5-dev libsdl1.2-dev libssl-dev libwxgtk3.0-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev unzip language-pack-zh-hans

然后从Arm官网下载最新的编译器。注意这里需要根据目标平台下载,如果你是Cortex-A系列的处理器(目前绝大部分平台),则下载GNU-A版本,否则下载GNU-RM版本的编译器。根据你自己的机器平台(linux/win 32/64 bit)不同,和目标平台不同(arm/aarch64 el/le)(大小端,这个除非特意强调否则一般是小端),下载不同版本,比如我要在linux amd64上给aarch64编译,则下载gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu版本。(这也是绝大多数人的通用版本)

cd ~
wget "https://developer.arm.com/-/media/Files/downloads/gnu-a/9.2-2019.12/binrel/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz"
xz -d gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz
tar xf gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar
mv gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu .gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu

但是只是把编译器放在那里是没有用的,因为你还需要make可以找到你的编译器,这时候就需要了解PATH的基本原理。这个变量在win和linux下都存在,当你直接在command line中输入一个命令是,系统会以从前向后非递归的在指定的PATH目录中寻找以这个命令为名称的文件。所以要仔细观察PATH的设定规则。这里要注意:

  1. 从前向后:if found then break
  2. 非递归:if not found in depth=1, go to next
  3. export的效果只局限与当前会话,如果重开一个新窗口是没有用的,需要重新export
    export PATH=~/.gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin:$PATH
    export CROSS_COMPILE=aarch64-none-linux-gnu-
    

目前Google已经在Android主线分支代码中停止了对GCC 4.9的支持,并且全面转向LLVM。但是目前仍然由开源社区维护的低版本的内核代码中仍然留下了诸如-mcpu=cortex-a73.cortex-a53一类的GCC only option,因此我编译的一加5内核索性直接选择了arm官方的GCC编译器。在编译的同时会大量报Warning(但是众所周知warning不是问题)提示GCC has been deprecated(弃用),不要担心。

编译内核

准备好了环境我们现在就可以开始了。因为准备好了环境这里就非常简单了,分为如下几步

  1. 清理之前的编译中间文件和旧的配置信息,防止出现奇怪问题。
    make mrproper  
    #这个mrproper非常有意思,是英国的一个清洁剂品牌 Mr.Proper,美国是Mr.Clean
    #Linus Torvalds 生于波兰,现居于美国
    #可以理解这句命令是更彻底的make clean
    
  2. 设置编译选项及目标
    export ARCH=arm64
    export SUBARCH=arm64
    export PATH=~/.gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin:$PATH
    export CROSS_COMPILE=aarch64-none-linux-gnu-
    make -j$(nproc --all) O=out blu_spark_defconfig # your config name here
    
    这里的编译选项一般在你要构建的架构的config目录里面有,例如我针对msm8998构建是./arch/arm64/configs/blu_spark_defconfig。因为我的msm8998(骁龙835)是arm64架构的cpu,如果你是mips架构的cpu就要去./arch/mips/configs里面找。(虽然mips for android好像还没出来?)
  3. 开始编译
    make -j$(nproc --all) O=out ARCH=arm64\
    	SUBARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- \
    	CONFIG_DEBUG_SECTION_MISMATCH=y
    
    理论上如果在前面已经导入了环境变量,这里是不需要手动指定的。但是我编译的时候遇到了手动指定无效的问题,所以为了保险我个人还是建议两个都用上 XD。 -j$(nproc --all)的含义是使用cpu的全部线程。你也可以手动用-j4限制4线程 -O=out是为了将编译中间文件与源代码分开,避免写gitignore到头大
  4. 获取内核文件 以msm8998为例内核文件在./out/arch/arm64/boot/Image.gz-dtb中,其他架构规则同上。但是要注意后缀有-dtb,别直接把.gz文件拿走了。

刷入内核

刷入内核有两种手段,一种是直接在fastboot下操作boot镜像的手段之类。这个过于硬核,学艺不精的我不太敢讲,以免砖了别人的手机。 这里说的是利用Anykernel 3来刷入内核,因为Anykerenl3自带了Magisk Patch也省去了重刷入Magisk的问题。如果你想自己定制刷入脚本的话可以去仓库看看,但是我这里是迅速入门,所以当然选择最省事的:

  1. 找一个已经做好的内核下下来(比如 Blu_spark官方内核)
  2. 替换压缩目录下的Image.gz-dtb之类的文件为你刷好的内核镜像。

一些坑坑

  1. 刷入的时候报Error:1: 这个一般是因为你的编译器选择有问题,可能是交叉编译没选对。注意,交叉编译不是你的编译器和交叉编译器共同工作,而是交叉编译器接手全部工作。

  2. 编译的时候报类似unknown option: -mcpu=: 这个一般是因为Makefile中有一些GCC only的选项,如果你指定了编译器为clang会出问题。

  3. 为什么我看到有的教程中有CC=CLANG,CLANG_TRIPLE=aarch64-linux-gnu-? 编译器有 “预处理,编译,汇编,链接”四个过程,而这四个过程由不同模块组成。CC则是将编译环节指定成了Clang,如果你的代码中有使用了 std=gnu89/99/11而不是c89/99/11的代码,那么clang编译可能会出错(clang是llvm toolchains中的一环) 请先看Makefile
    image.png
    但是因为GCCGPL v2传染病协议,许多大厂并不愿意支持GCC的发展。随着苹果带领发起LLVM及各大厂家的推进,目前LLVM已经在一些领域取代GCC,例如google前一段时间在Android主分支中取消了对GCC 4.9的支持就是一个信号。同时Pixel系列的内核也均靠Clang编译。但是Clang目前仍然存在一些问题,比如交叉编译的连接操作有可能会出现问题,目前还需要GCC在一定程度上予以支持。在不可见的将来GCC可能会从开源的Android中销声匿迹

  4. Linux下的NTFS-3G 驱动 如果你试图在Linux下挂载NTFS磁盘进行编译,那你得做好心理准备。我是4C8T的R7 2700U处理器,而编译的时候这个驱动足足吃了我1个线程(100%)。所以哪怕多烧点磁盘读写(大概10G),也请挪到ext4分区下编译。

白嫖资本主义羊毛

因为疫情原因,我在家里并没有拿到台式机,笔记本电脑又是R7 2700U这个处理器,虽然已经能一定程度上打平I7 4770,但是性能仍然费拉不堪,还需要我启动到Linux分区下进行操作,影响我上(da)网(you)课(xi)的大业。所以我就打算直接利用GitHub Actions来进行编译。

Github Actions:是Github推出的一个新的功能,可以为我们的项目自动化地构建工作流,例如代码检查,自动化打包,测试,发布版本等等。大概和Gitlab CI/CDJenkins一个性质。

image.png

使用Actions,我们可以节省自己的计算资源和电费。同时Actions的性能也十分不错(2C7G 14g虽然相比R9 3950X仍然蔡的像个弟弟,白嫖的要什么飞机)。但是在实测的过程中,除了因为apt dist-upgrade的包太多导致更新需要20分钟(其实非必须),编译只花了10分钟就完成了。相比Vultr 4C8G则花了足足20多分钟,可见Vultr超售严重,MS爸爸财大气粗。 将服务推送上去后会自动开始运行。不过这里我就不讲使用教程了,直接贴yml。

name: Build Kernel H2OS
on:
  push:
    branches:
	  - makiras
jobs:
  build:
	runs-on: ubuntu-18.04
	steps:
	  - name: Init Repo
		run: |
		  cd ~
		  git clone https://github.com/Makiras/op5.git -b makiras --depth=1
	  - name: Build With Shell
	    run: |
		  cd ~/op5
		  bash build_full.sh
	  - name: Package With AnyKernel
		run: |
		  cd ~
		  cp op5/AnyKernel ./ -r
		  cd AnyKernel/
		  cp ../op5/out/arch/arm64/boot/Image.gz-dtb ./
	  - name : Upload artifact
	    uses: actions/upload-artifact@master
	    with:
		  name: blu_spark_makiras_modified.zip
		  path: /home/runner/AnyKernel/

这里我为了增加泛用性,直接把编译步骤写成了脚本,大概就是我上面的步骤加起来。如果有兴趣可以直接去repo里面翻一下,编译完成后在页面可以下载。

如何给内核打补丁加功能(以DC调光为例)

当然是雇人完成这项工作啊,我干活超便宜的
当 然 是 舒 服 的 Cherry-Pick 啊

DC调光由 aa889788 编写(内核层面遮罩式软DC)

我这里说一个最水的方法

  1. Git Remote Add && Git Fetch 找到你想添加的仓库(有你想要的补丁的仓库),然后把这个仓库添加为远程分支
    git remote add news https://github.com/lyq1996/android_kernel_oneplus_msm8998.git
    git fetch news
    
  2. Git cherry-pick 找到你想添加的补丁修改,比如这个就是DC调光的补丁ID。(懒得截图了)
    git cherry-pick 95b06a9bc12fddf28b9bae32e3c6f86ab406ccb8
    
  3. 如果出现问题,请自己merge后commit。
  4. 如果要找我改的内核,下载地址:http://suo.im/6cdBeX 文件密码:114514 modified.zip就是稳定版,然后还要Magisk刷入dctuner来控制开启关闭DC

评论

  1. Windows Chrome 83.0.4103.61
    4 年前
    2020-6-04 15:19:37

    来膜云龙聚聚

  2. 匿名
    Linux Chrome 80.0.3987.162
    4 年前
    2020-7-01 18:31:21

    deepin20.4报道[手动滑稽]酷安来的

  3. 秋幻雪涙
    Windows Chrome 83.0.4103.116
    4 年前
    2020-7-17 14:52:08

    谢谢博主! 用网上英文文档的方法报错地我都崩溃了

  4. 匿名
    Chrome OS Chrome 55.0.2883.105
    4 年前
    2020-11-03 23:14:53

    无意间摸到这里,曾经陌生的ID突然变得十分眼熟!

    • Makiras
      博主
      匿名
      Android Chrome 86.0.4240.110
      4 年前
      2020-11-03 23:42:04

      还行,互联网真小.jpg

  5. lala
    Windows Edge 121.0.0.0
    8 月前
    2024-2-17 22:12:52

    大佬你好,我下载的是pixel3的官方的内核代码,如何依赖内核代码来编译驱动,是单独编译驱动,不是把驱动丢到内核源码中编译。搜索了很对资料都没有找到如何单独编译驱动

    • Makiras
      博主
      lala
      Android Chrome 121.0.0.0
      8 月前
      2024-2-17 22:21:41

      驱动一般是内核模块,内核模块编译时都会依赖编译内核。类似ubuntu的dkms设计上提供了单独编译内核模块的可能(仍然依赖编译好的内核),但是在我的知识范围内安卓这边没做这种设计,所以据我所知应该是不行的。

      • 匿名
        Makiras
        Macintosh Chrome 122.0.0.0
        7 月前
        2024-2-29 15:08:35

        一定要把驱动代码丢到内核源码中编译吗,我看一些rk的板子的驱动编译,他们设置编译的内核源码目录,依赖这个本地的源码,但是驱动代码不在内核目录中也能编译。

        • Makiras
          博主
          匿名
          Android Chrome 122.0.0.0
          7 月前
          2024-2-29 15:14:23

          设置好编译器的include path和library path可以不在

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇