LineageOS是基于原生安卓的开源第三方固件,本文将手动编译LineageOS固件并刷入小米10T(红米K30S)。

本次编译的配置为Vmware虚拟机ubuntu20.04,内存32GB,swap空间10GB,磁盘空间350GB。需要提醒的是创建虚拟机时建议将虚拟磁盘选择为“拆分为多个文件”,这样可以方便后续编译过程中磁盘空间不足时进行扩容。若设置为“存储为单个文件”,则非常不方便进行扩容(单个文件的扩容原理为创建一个更大的文件,将原始文件中的内容复制过去,若宿主机磁盘空间不足,则会扩容失败)。

配置编译环境

下载Android SDK平台工具并解压

1
unzip platform-tools-latest-linux.zip -d ~

打开 ~/.profile文件并添加以下内容,执行source ~/.profile 命令

1
2
3
4
# add Android SDK platform tools to path
if [ -d "$HOME/platform-tools" ] ; then
PATH="$HOME/platform-tools:$PATH"
fi

安装编译工具

1
sudo apt install lib32ncurses5-dev libncurses5 libncurses5-dev bc bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick lib32readline-dev lib32z1-dev libelf-dev liblz4-tool libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev python-is-python3

配置Git

配置自己的名字与邮箱,如果后续不涉及commit,仅仅是clone,可以随便设置。

1
2
git config --global user.email "sundaqing2020@gmail.com"
git config --global user.name "Big7ng"

初始化Git LFS(Large File Storage)拓展,,它可以在使用Git进行版本控制时处理大型文件。它通过将文件内容存储在外部服务器上,并在Git仓库中保留指向这些文件的引用,从而有效地管理和版本控制大型文件。

1
git lfs install

创建目录

为repo下载,LineageOS源码,LineageOS编译创建目录。

1
2
mkdir -p ~/bin
mkdir -p ~/android/lineage

安装repo

1
2
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repo
chmod a+x ~/bin/repo

repo的运行过程中会尝试访问官方的git源更新自己,如果想使用tuna的镜像源进行更新,可以将如下内容复制到你的~/.bashrc里,执行命令source ~/.bashrc.

1
export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'

为了确保终端模拟器能够找到repo的路径,需要保证以下内容在~/.profile文件中, 添加后执行命令source ~/.profile.

1
2
3
4
# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
PATH="$HOME/bin:$PATH"
fi

使用ccache开启缓存提高编译速度

ccache 是一个编译器缓存工具,可以显著加快编译过程,对于大型项目来说效果非常明显。它通过将之前编译的结果缓存下来,当下次编译相同的源文件时,如果没有变化,就可以直接读取缓存结果而不需要重新编译,大大缩短编译时间。

打开ccache功能后会在用户目录下生成一个.ccache文件夹用以产生编译时的缓存。

在命令行中输入以下命令以开启ccache功能。

1
2
export USE_CCACHE=1
export CCACHE_EXEC=/usr/bin/ccache

通过cache -M SIZE命令来调节缓存大小,SIZE为0表示没有缓存限制,编译Android时建议设置为25-50G。

1
ccache -M 50G

注意,这个功能需要充足的磁盘空间,如果磁盘空间比较紧张,建议关闭这个功能。

配置swap交换空间

ubuntu自带的swap交换空间为2G,这可能不够用,需要将swapfile增加到10G。

1
2
3
4
sudo swapoff /swapfile
sudo fallocate -l 10G /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

下载源码

国内访问谷歌不稳定,因此本文使用清华镜像源下载LineageOS源码。

1
2
cd ~/android/lineage
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/lineageOS/LineageOS/android.git -b lineage-20.0 --git-lfs

打开.repo/manifests/default.xml,将

1
2
3
<remote  name="github"
fetch=".."
review="review.lineageos.org" />

改成

1
2
3
4
5
6
<remote  name="github"
fetch="https://github.com/" />

<remote name="lineage"
fetch="https://mirrors.tuna.tsinghua.edu.cn/git/lineageOS/"
review="review.lineageos.org" />

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

改成

1
2
<remote  name="aosp"
fetch="https://mirrors.tuna.tsinghua.edu.cn/git/AOSP"

1
2
<default revision="..."
remote="github"

改成

1
2
<default revision="..."
remote="lineage"

同步源码树

1
repo sync

下载设备特定文件

breakfast <device>命令用于选择特定的设备,本文使用小米10T,因此device为apollon。

执行下列命令后会下载设备特定的配置文件与Linux内核。分别对应于device/xiaomi/kernel/xiaomi/sm8250文件夹。sm8250指骁龙865处理器。

1
2
3
cd ~/android/lineage
source build/envsetup.sh
breakfast apollon

这一步如果有报错,执行完下一步后返回重新执行一遍。

从LineageOS刷机包中提取proprietary blobs

首先需要在LineageOS官网下载LineageOS的Xiaomi10T的刷机包。

在提取前需要安装两个工具:brotli和sdat2img。

brotli是Google推出的一款无损压缩算法,需要使用brotli工具将刷机包中的.br压缩文件解压。

Android镜像主要有两种格式,分别为raw与sparse:

  • raw iamge是完整的ext4分区镜像(包含很多全零的无效填充区),可以直接使用mount进行挂载,因此比较大(一般1G左右)。
  • sparse ext4 image,是一个非常普通的dat文件。由于它将raw ext4进行稀疏描述,因此尺寸比较小(没有全零的无效填充区)。

sdat2img工具将sparse Android data镜像(.dat)转换为ext4镜像(.img),然后我们就可以挂载该文件进行提取了。

1
2
3
4
mkdir ~/android/system_dump/
cd ~/android/system_dump/
sudo apt-get install brotli
git clone https://github.com/xpirt/sdat2img

安装完成后,可以开始进行提取了,刷机包中需要提取的内容为Android系统的不同分区内容,将不同分区内的设备特定文件提取出来:

system 分区是安卓系统的核心部分,包含了操作系统的基本文件和程序。它是安卓设备启动和运行的基础,确保设备能够正常启动和运行。

1
2
3
4
5
unzip ~/Downloads/lineage-*.zip system.transfer.list system.new.dat*
brotli --decompress --output=system.new.dat system.new.dat.br
python sdat2img/sdat2img.py system.transfer.list system.new.dat system.img
mkdir system/
sudo mount system.img system/

vendor 分区包含了设备制造商特有的驱动程序和配置文件。这些文件确保设备的硬件能够与安卓操作系统正常集成和工作。

此分区包含所有无法分发给 AOSP 的二进制文件。如果设备不包含专有信息,则可以忽略此分区。

1
2
3
4
5
6
unzip ~/Downloads/lineage-*.zip vendor.transfer.list vendor.new.dat*
brotli --decompress --output=vendor.new.dat vendor.new.dat.br
python sdat2img/sdat2img.py vendor.transfer.list vendor.new.dat vendor.img
sudo rm -r system/vendor
sudo mkdir system/vendor
sudo mount vendor.img system/vendor/

system_ext分区

1
2
3
4
5
6
unzip ~/Downloads/lineage-*.zip system_ext.transfer.list system_ext.new.dat*
brotli --decompress --output=system_ext.new.dat system_ext.new.dat.br
python sdat2img/sdat2img.py system_ext.transfer.list system_ext.new.dat system_ext.img
sudo rm system/system_ext -r
sudo mkdir system/system_ext
sudo mount system_ext.img system/system_ext/

product分区是特定于设备的定制区域,用于存储与设备相关的应用程序、配置文件和资源。这个分区主要用于制造商和运营商来添加或修改设备上特定的应用程序和服务,而不影响Android系统的核心功能。

1
2
3
4
5
6
unzip ~/Downloads/lineage-*.zip product.transfer.list product.new.dat*
brotli --decompress --output=product.new.dat product.new.dat.br
python sdat2img/sdat2img.py product.transfer.list product.new.dat product.img
sudo rm system/product -r
sudo mkdir system/product
sudo mount product.img system/product/

ODM分区是设备制造商(Original Design Manufacturer)提供的一个专有分区。它包含了设备特有的驱动程序、配置文件和其他定制化的软件组件。

ODM 分区与 vendor 分区的作用类似,都是提供设备制造商特有的软件组件。不同的是,vendor 分区是由操作系统供应商(如谷歌、小米、OPPO等)维护,而 ODM 分区是由设备制造商维护。

1
2
3
4
5
6
unzip ~/Downloads/lineage-*.zip odm.transfer.list odm.new.dat*
brotli --decompress --output=odm.new.dat odm.new.dat.br
python sdat2img/sdat2img.py odm.transfer.list odm.new.dat odm.img
sudo rm system/odm -r
sudo mkdir system/odm
sudo mount odm.img system/odm/

完成以上操作后,可以开始提取proprietary blobs了

1
2
cd ~/android/lineage/device/xiaomi/apollon
./extract-files.sh ~/android/system_dump/

提取后, 挂载的镜像都不需要了,可以进行清理以节省磁盘空间。

1
2
3
4
5
6
sudo umount ~/android/system_dump/system/system_ext
sudo umount ~/android/system_dump/system/product
sudo umount ~/android/system_dump/system/vendor
sudo umount ~/android/system_dump/system/odm
sudo umount ~/android/system_dump/system
rm -rf ~/android/system_dump

编译源码

1
2
3
cd ~/android/lineage
croot
brunch apollon

博主编译过程中出现的错误主要有如下:

  • 出现了如下错误,需要检查提取proprietary blobs步骤中,是否把OTA升级包中所有的镜像文件都提取了。
1
2
3
 FAILED: ninja: 'vendor/xiaomi/sm8250-common/proprietary/odm/etc/media_profiles_V
1_0.xml', needed by 'out/target/product/apollon/odm/etc/media_profiles_V1_0.xml'
, missing and no known rule to make it
  • 出现了如下错误,repo sync命令未下载完全,把报错中相应的目录删除后重新执行repo sync命令。
1
2
ninja: 'external/chromium-webview/prebuilt/arm64/webview.apk', needed by
'out/target/product/apollon/obj/APPS/webview_intermediates/package.apk', missing and no known rule to make it
  • 如果没有出现error错误,但是编译停止了,此时大概率是内存不足了,可以增加swap空间大小。

刷机

1
cd $OUT

该目录下两个文件在后续刷机过程需要使用:

  1. recovery.img, which is the LineageOS recovery image.
  2. lineage-20.0-20240713-UNOFFICIAL-apollon.zip, which is the LineageOS installer package.

后续的刷机过程与官方提供的刷机包一致,可以参考官方文档,简要概括一下就是先刷入recovery固件,再通过该recovery模式刷入LineageOS固件。

参考

Build LineageOS for Xiaomi Redmi K30S Ultra

Extracting proprietary blobs from LineageOS zip files

从CM刷机过程和原理分析Android系统结构

Git Repo 镜像使用帮助

lineageOS 源代码镜像使用帮助