Post

从0开始编译android类原生系统

写在文章开头的废话

为什么我要写这篇文章

给自己留下笔记,给大家一起进步。

为什么原生安卓?

原生,通常指的是AOSP,是不包括厂商或运营商定制程序以及任何第三方修改的Android系统,主要由谷歌维护。所以说原生安卓会很干净。不会有系统应用偷偷联网,偷偷窃取用户信息。而且还少了很多应用,内存也大了起来。

为什么这么多的原生安卓系统,还有不同日期版本?

在各类美化和修改团队下,产生了各种类型的系统,例如著名的CM(LineageOS),Crdroid,havoc,dotos.每个月,因为谷歌都会定期给AOSP进行安全更新,因此开发者也在不停编译新的系统。

我应该选择哪一个?

你应该跟上你所选的系统,跟上自己喜欢的开发者脚步,刷上最新的系统。


配置开发环境

环境准备

在 Ubuntu 20.10 下编译 LineageOS/CM 等 AOSP Ubuntu 20.10 LTS 请选择 64 位的。

硬件最低要求:

HDD: HDD 100GB 及以上剩余存储空间(最好用固态硬盘)。 CPU 性能差点没事,只不过是浪费时间与电费而已。(本人是AMD Ryzen 2500u) 安卓源码所在目录最低剩余空间不要小于 150GB。

本人建议:

在学校多媒体室找台性能好的电脑编译,安装虚拟机,特别是做视频剪辑的那种。

1.配置环境

配置SDK(fastboot和adb)

1
wget https://dl.google.com/android/repository/platform-tools-latest-linux.zip
1
unzip platform-tools-latest-linux.zip -d ~
1
gedit ~/.profile

安装依赖组件

1
sudo apt-get install 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
  1. 如果显示libcurses5-dev.deb 找不到/
  2. 依赖因为gcc++不被安装,无法直接安装。

解决方法:

  1. 直接google搜索 libcurses5-dev.deb,下载对应的deb文件。
  2. sudo aptitude install gcc++

安装 JDK

1
sudo apt install -y openjdk-8-jdk

设置repo工具

安装repo
1
2
3
4
5
mkdir -p ~/bin
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
chmod a+x ~/bin/repo
gedit ~/.profile
source ~/.profile
设置git身份
1
2
git config --global user.email "g0d3ph@gmail.com"
git config --global user.name "Gah0"
新建aosp存放目录
1
2
mkdir -p ~/dotos
cd ~/dotos

我们这里编译dotos系统,所以命名dotos

初始化repo

1
   	repo init -u git://github.com/DotOS/manifest.git -b dot-q

如果提示无法连接到 gerrit.googlesource.com,可以编辑 ~/bin/repo,把 REPO_URL 一行替换成下面的:

` REPO_URL = ‘https://gerrit-googlesource.proxy.ustclug.org/git-repo`

如果你之前已经通过某种途径获得了AOSP的源码,但是你希望以后通过中科大同步,只需要将.repo/manifest.xml(隐藏文件夹)中的

1
2
3
    	<remote  name="aosp"
     	 fetch=".."
     	 review="https://android-review.googlesource.com/" />

改为下面的code即可:

1
2
3
   		<remote  name="aosp"
    	 fetch="git://mirrors.ustc.edu.cn/aosp/"
     	 review="https://android-review.googlesource.com/" />

下载AOSP仓库

1
	`repo sync -c -j8 --force-sync --no-clone-bundle --no-tags`

-j8指的是你的下载线程,太多会卡,太少会慢

源码下载完成后,看到下面的信息可以说明下载成功。整个源码的大小为46+g


重要:内核开发者的工作

  • 构建手机内核(这里以小米9se为例)

手机内核有新有旧,当然,这里为了方便开发者,我决定挑选小米初始的内核,并且自己重做(重新打caf等操作) 手机内核是决定硬件是否能正常工作的部分,很重要。

要在内核上工作的内容差不多,就是打commit,保持上游更新,如果你需要做成offical,不能乱来,请看教程打上游 Git是一个 “分布式版本管理工具”,我们这里需要学习git工具的知识:git-tips

打开终端,我喜欢在主页面下载内核/home/gah0,所以,你也可以选择你喜欢的位置克隆

1
`git clone -b grus-p-oss --single-branch git@github.com:Gah0/android_xiaomi_kernel_grus.git`

克隆后,进入内核文件夹内,在本地新建一个分支,自己重做内核

1
2
	cd android_xiaomi_kernel_grus
	git checkout -b lineage-17.1

成功的消息是:

切换到一个新分支 ‘lineage-17.1’

  • 注意:

通常,我们得到的内核可能是不完整的,厂商只是遵循gpl-2.0规定释放内核快照(遵守规则),例如wifi驱动,指纹驱动,这些是其他厂商的工作(手机厂商是没有义务公布出来的)。通常不会集成在内核里面,一些屏幕指纹,环境光传感器,都需要自己导入…

大家可以参考我这个源的grus-p-caf分支的提交。android_xiaomi_kernel_grus

那么,小米9se,高通提供了四个驱动在QAEP上,从高通源获得以下驱动:qcacld-3.0fw-apiqca-wifi-host-cmntechpack/audio,这四个都是非常重要的。

部分老手机是用primaqcacld-2.0

看清楚自己手机设备是使用什么平台的处理器,例如我的小米9se为高通712,就需要获取qcacld-3.0的驱动,那么就在源码branch或tag页面使用

1
2
3
`git fetch https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/wlan/qcacld-3.0/ LA.UM.7.8.r1-06500-SDM710.0`

`git merge FETCH_HEAD`

如何查看当前最新CAF驱动,内核标签?请点击在这里

LA.UM.7.8.r1-06500-SDM710.0在2019.08.07为当前日期最新android P标签

  • 当你像我一样完成了合并驱动和内核标签之后..

此时内核或者驱动会有一点小小的编译错误,在编译期间会停下来报错,需要自行修复。 这次我捕捉到多个错误,就像这样,漏个某个function漏了个bool类型枚举类型没有使用这样的错误

这些一般都是小米自己对caf的基础上做了一些关于自己充电协议的修改。合并caf要多注意,以上这些代码是被小米删去的。对于小米手机来说可能是没有用处的,又或者他把这个功能写在了另一个驱动文件中。

如果用clang编译器编译内核可以参考这里修复

  • 别人的做法

我看过一个开发者的做法,我感觉很妥当,能保持内核代码纯洁和性能,减少底层无用代码,把caf的tag先克隆下来,然后再cherry-pick小米的提交,改上设备树,充电驱动,光传感器,扬声器驱动等。将有关驱动逐个合并到caf tag上。类似于我对小米4c的变基操作。然后再盖上当前linux-stable…其他手机同理!


如何写device tree

这里分为两个部分,一个是重写device tree,一个是偷窃别人的device tree

如果手机比较新,通常就是没有device tree,需要自己补上

首先先建立一个device tree骨架,填上相应的手机硬件信息,需要自己从手机build.prop获取。

这里应该是最复杂的部分。

grus: Add initial device tree files

Android.mk 这个makefile存在于很多文件夹中。目的是在用户调用正确的build命令时,building脚本可以正确检测到device-tree
BoardConfig.mk 这个makefile是最重要的文件之一,包含了board的定义(分区大小,include路径、overlay路径、CPU、Soc等等)
Lineage.mk 这个文件是首先被building脚本读取的,仅包含了产品名称、代号、制造商还有是平板还是手机,并且链接 device.mk
device.mk 这个文件包含了所有的需要使用或者需要复制的包、应用、权限和库,也包含了设备编译apps的时候需要的大小(例:xhdpi)
extract-files.sh+setup-makefiles.sh 这些shell脚本被调用来创建vendor(通过ADB从proprietary-files.txt拉取需要的文件到vendor文件夹)
proprietary-files.txt 这个文本文件一行一个文件,决定了AOSP需要的来自原生固件的文件(audio库、图形库(例如OpenGL、MALI驱动等),等等)
system.prop 这个文件包含了一些需要被复制到build.prop的属性,包含了一些设置,比如RIL类、库、支持,要使用的WLAN接口,显示大小等等

通常写完device tree后,大家可以通过extract-files.sh+setup-makefiles.sh 拉取自己手机中的二进制blob,然后查看LineageOS源上自己手机相对应架构处理器的device tree common,里面会有很多的通用库和你需要添加到设备的功能文件,通过git合并到自己的device tree common上。不建议把太多库写到一个device tree上,把dt common和你的设备dt分开。

然而还有另外一些内容,高通一般会提供给开发者,按照自己实际请添加

部分开发者提交了很多有用的功能到相对应的device tree common中 例如让第三方系统支持微信,支付宝指纹支付


  • 偷窃开源成果

手机比较老,那么通常就会有开发者写出device tree或device tree common 正常情况下,如果获取到device tree,可是要编译与开发者不同的第三方系统,需要修改很多地方。

例如在device tree文件夹下的某.mk文件,以达到编译期间能正常链接该文件进行编译。

以下展示mokee的源进行lineage化,mokee->lineage-ify。

1
2
3
4
5
PRODUCT_MAKEFILES := \
    		$(LOCAL_DIR)/mk_libra.mk
更换为
PRODUCT_MAKEFILES := \
		$(LOCAL_DIR)/lineage_libra.mk

又例如在AndroidManifest.xml,设置控件

1
2
3
package="org.mokee.settings.device"
改为:
package="org.lineageos.settings.device"

最好能获取lineageOS device tree自己修改,这个项目一般是比较标准的。


最后

小白第一次编译建议使用别人编译成功的源,自己操作一遍,会减少不少麻烦。

修成正果:编译成功!

但是却无法开机。

需要在手机中提早在init进程中加载adb,以方便卡米时logcat。卡米就是小米手机卡在启动动画。

若是内核有问题,大概会无限卡MI或者进入了Bootloader。

最后建议和开发者多交流。


This post is licensed under CC BY 4.0 by the author.