(封面图源 小米商城 )
前情提要 在去年1月25号的时候,我尝试给非官方支持的设备编译LineageOS 20,但却以失败告终。这次,重新尝试一台官方支持的设备,且系统为Lineage 22.1。⚠️万字长文预警
环境配置部分,同上期文章。
硬件和软件环境 我用的是平时拿来干活的笔记本。硬件方面:i5-10300H
的处理器,32GB 2933MHz
的主存,开启了16GB SWAP
智慧运存 ,编译环境用的硬盘是Samsung Evo 870 1TB
;软件方面:采用Debian 12
系统。主要是Ubuntu太臃肿了
是的我今年加了一根16GB的内存条,去年编译的时候物理内存和融合内存 SWAP都吃满了,今年除了在ninja
初次启动的时候两个都吃满,平时编译基本上只吃了80%的物理内存。
⚠️本次编译的初次编译耗时一天一夜,CPU平均频率为3.5GHz,请合理评估和安排您的编译时间。后续增量编译平均耗时十分钟,主要耗时部分为打包系统镜像写回硬盘。
装依赖 Part 1: 下载和解压 第一个要装的就是adb
和fastboot
。
⚠️ 注意!不要去apt
源里下载,那里的版本太老了。前往谷歌官方下载:https://dl.google.com/android/repository/platform-tools-latest-linux.zip
按照Lineage
官方的说法 ,把他解压到~
下吧:
1 unzip platform-tools-latest-linux.zip -d ~
现在你确定一下~
目录下是否存在platform-tools
文件夹,如果存在则继续。 打开你的~/.profile
或者~/.zshrc
(本文全文将以.zshrc
进行举例说明),在source $ZSH/oh-my-zsh.sh
前添加以下代码:
1 2 3 4 if [ -d "$HOME /platform-tools" ] ; then export PATH="$HOME /platform-tools:$PATH " fi
然后,source
它,再echo $PATH
一下看看环境变量里是否存在~/platform-tools
,存在就可以进行下一步。
Part 2: 从apt源安装 使用apt把这些都装进去: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
对于我使用的Debian 12
系统,再安装这些:lib32ncurses-dev libncurses5 libncurses5-dev
对于Ubuntu
用户,请按照Lineage
官网说法进行操作:
1 2 3 4 5 6 7 8 9 10 11 12 # For Ubuntu 23.10 (mantic), install libncurses5 from 23.04 (lunar) as follows: wget http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libtinfo5_6.4-2_amd64.deb && sudo dpkg -i libtinfo5_6.4-2_amd64.deb && rm -f libtinfo5_6.4-2_amd64.deb wget http://archive.ubuntu.com/ubuntu/pool/universe/n/ncurses/libncurses5_6.4-2_amd64.deb && sudo dpkg -i libncurses5_6.4-2_amd64.deb && rm -f libncurses5_6.4-2_amd64.deb# While for Ubuntu versions older than 23.10 (mantic), simply install: lib32ncurses5-dev libncurses5 libncurses5-dev# Additionally, for Ubuntu versions older than 20.04 (focal), install also: libwxgtk3.0-dev# While for Ubuntu versions older than 16.04 (xenial), install: libwxgtk2.8-dev
Part 3: OpenJDK的安装 OpenJDK
的版本取决于你想要编译的Lineage OS
版本。根据官方的提示,我们需要安装Java 11。 下面的信息来自于上面提到的Lineage
官网教程。LineageOS
18.1及更高版本: openjdk-11 openjdk-11-source
LineageOS
16.0-17.1: openjdk-9 openjdk-9-source
LineageOS
14.1-15.1: openjdk-8-jdk
⚠️注意: 构建这些版本时你需要在/etc/java-8-openjdk/security/java.security
中从jdk.tls.disabledAlgorithms
中移除TLSv1
和TLSv1.1
相关的东西。
LineageOS
11.0-13.0: openjdk-7-jdk
Ubuntu 16.04
及更新版本的软件源中已将OpenJDK 1.7
移除了。解决方案参考Ask Ubuntu
上的问题“How do I install openjdk 7 on Ubuntu 16.04 or higher?” 。注意热评里那个叫你添加ppa
源的老登,因为ppa
源缺乏安全性维护,所以别看他的回答,看后面一个叫你去Debian官网下载的回答。笔者评:截止写稿时,Debian 12
源上的openjdk
只有17
版本了。所以只能去网站上下载.deb
包然后安装。这里提供两个下载站:OpenJDK Archive(无需登陆但没有deb) ;Java SE Archive(概率登陆但有deb) 。
但是!我们是不是可以整点活?比如直接去隔壁Ubuntu
的镜像源网站上下载?比如清华源: Ubuntu系统前往这里下载:下载jdk11-universe 下载jdk11-main ;下载jdk9-universe ;下载jdk8-universe 下载jdk8-main ;下载jdk7-main Debian系统前往这里下载:下载jdk11-main 下载jdk8-main 使用此方法时如提示缺失依赖则需要补全依赖然后再安装,否则apt
会报错:ca-certificates-java java-common libc6
需要把openjdk-xx-jdk
及其headless
版本、openjdk-xx-jre
及其headless
版本和openjdk-xx-source
都安装上再继续。
Part 4: Python的安装 啥?这都什么年代了还教咋装Python? 要不是因为不同Lineage
版本要求的Python版本不一样,我也懒得写了LineageOS
17.1及更高版本: python3
LineageOS
11.0-16.0: python2
如果你电脑上有多个蟒蛇Python
互相冲突,Lineage
官网推荐的解决方案是用venv
。相关的东西这里不再赘述。
⚠️ 值得一提的是现在Debian源里python的包名改了,如果你要装Python3则需要安装python-is-python3
,如果是Python2的话需要安装python-is-python2
。
进入准备工作! 建立工作目录
⚠️ Lineage和清华源上的教程写的不一样,这里冲突部分采用的是Lineage官网教程。
1 2 mkdir -p ~/binmkdir -p ~/android/lineage
其中~/bin
存放git-repo
工具,~/android/lineage
存放LineageOS
的源码。
安装repo工具
这是个啥?repo
是个由Google开发的git
的增强工具,和git
配合食用。参考Google官方文档。
1 2 3 4 mkdir ~/bin PATH=~/bin:$PATH curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > ~/bin/repochmod a+x ~/bin/repo
更新repo使用这个命令:export REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo'
然后再使用上面添加adb
的方法将~/bin
目录添加到环境变量中,编辑.zshrc
…:
1 2 3 4 if [ -d "$HOME /bin" ] ; then PATH="$HOME /bin:$PATH " fi
别忘了再次source
它一下!
配置Git 没啥好说的,设置一下用户名和邮箱,这步没做的话下一步初始化仓库的时候命令行里也会叫你提供这两个信息。
⚠️ 注意: 这里的操作是对整个电脑全局的设置。如果你只想在编译系统的源码仓库文件夹内设置这两个信息,则请跳过设置信息这一步,直接进行lfs
初始化。
1 2 git config --global user.email "you@example.com" git config --global user.name "Your Name"
为了能让git
存放大文件,需要初始化一下Large File Storage
:
设置Git
的Change-Id
:Lineage
官方说为了防止重复的Change-Id
,就要这么操作一下。但是我没有进行这一步设置。
To avoid duplicated Change-Id: trailers in commit messages, especially when cherry-picking changes, make Change-Id: a known trailer to git:
1 git config --global trailer.changeid.key "Change-Id"
配置编译缓存 这是用ccache
来加快编译的。将这些内容放入.zshrc
中然后再source
一下:
1 2 export USE_CCACHE=1export CCACHE_EXEC=/usr/bin/ccache
然后回到命令行终端,设置ccache
大小:
ccache
大小影响你的编译速度。如果只编译一个设备,那么给20-50GB
就够了;如果编译多个设备(不共享内核源码),则建议配置75-100GB
。 当然,你也可以启用压缩:
1 2 3 4 5 6 7 8 9 10 ccache -o compression=true ```` > 启用压缩后,一台设备大概给`20G`就够了。 > ⚠️先进入`~/android/lineage`目录,再初始化仓库。 ``` shell repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/lineageOS/LineageOS/android.git -b lineage-22.1 --git-lfs --no-clone-bundle
确保网络通畅,待同步完成后,打开~/android/lineage/.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 3 <remote name ="aosp" fetch ="https://android.googlesource.com" xxx ="..." />
改成
1 2 3 <remote name ="aosp" fetch ="https://mirrors.tuna.tsinghua.edu.cn/git/AOSP" xxx ="..." />
将
1 2 3 <default revision ="..." remote ="github" xxx ="..." />
改成
1 2 3 <default revision ="..." remote ="lineage" xxx ="..." />
随后,同步源码树:
在我家这边,同步源码树的平均网速为10MB/s,整个过程大约耗时一小时左右。
准备设备专属代码 需要下载的内容 进入~/android/lineage
目录,执行以下代码:
1 2 souce build/envsetup.sh breakfest gemini
⚠️此处需要保证网络通畅,能正常连接到GitHub,否则会同步失败。
不需要下载的内容 掏出你的小米5,插上数据线,给shell
进程赋予root权限,再打开开发者选项中的使用Root身份进行ADB调试
。 进入~/android/lineage/device/xiaomi/gemini
再运行:
等待其文件提取完成,这一步提取的是闭源驱动,比如摄像头驱动.so。
开始构建! 可以通过croot
命令回到~/android/lineage
,或手动回去都行。然后运行:
就可以开始构建系统了。当构建完成后,系统包会存放在out/target/product/gemini/lineage-22.1-YYYYMMDD-UNOFFICIAL-gemini.zip
,使用out/target/product/gemini/recovery.img
将其通过adb sideload
刷入。
好了,享受自编译的系统吧!
一些可能要用到的细节信息 内核编译使用的defconfig
是kernel/xiaomi/msm8996/arch/arm64/configs/vendor/xiaomi/mi8996_defconfig
,和kernel/xiaomi/msm8996/arch/arm64/configs/vendor/xiaomi/gemini.config
。 相关配置文件可参考device/xiaomi/msm8996-common/BoardConfigCommon.mk
。 LineageOS的关于页面的彩蛋源码位于packages/apps/LineageParts/src/org/lineageos/lineageparts/logo/PlatLogoActivity.java
, 我们可以根据需求进行定制。
番外:不受支持的Lindroid
开源项目地址是这个 ,主要依据vendor_lindroid仓库的readme 进行操作。1. 向内核的defconfig(此处是kernel/xiaomi/msm8996/arch/arm64/configs/vendor/xiaomi/gemini.config
)添加以下内容:
1 2 3 4 5 6 7 8 CONFIG_SYSVIPC=y CONFIG_UTS_NS=y CONFIG_PID_NS=y CONFIG_IPC_NS=y CONFIG_USER_NS=y CONFIG_NET_NS=y CONFIG_CGROUP_DEVICE=y CONFIG_KERNEL_CGROUP_FREEZER=y
2. 将以下仓库clone到源码树:
1 2 3 git clone --depth=1 https://github.com/example/vendor_lindroid vendor/lindroid git clone --depth=1 https://github.com/example/external_lxc external/lxc git clone --depth=1 https://github.com/example/libhybris external/libhybris
3. 修改设备配置信息: 向device/xiaomi/gemini/device.mk
添加一行:
1 $ (call inherit-product, vendor/lindroid/lindroid.mk)
4. 将SELinux设置为Permissive: 打开device/xiaomi/msm8996-common/BoardConfigCommon.mk
,在Kernel
部分的添加一行启动参数:
1 BOARD_KERNEL_CMDLINE += androidboot.selinux=permissive
⚠️注意:关闭SELinux会令设备处于安全风险之中,请自行处理好该设备上的信息安全。
5. 修改Lineage源码以修复一些作者提到的问题 应用这个Patch ,或手动修改: 打开frameworks/native/services/inputflinger/reader/EventHub.cpp
: 将
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 ALOGV(" name: \"%s\"\n" , identifier.name.c_str()); ALOGV(" location: \"%s\"\n" , identifier.location.c_str()); ALOGV(" unique id: \"%s\"\n" , identifier.uniqueId.c_str()); ALOGV(" descriptor: \"%s\"\n" , identifier.descriptor.c_str()); ALOGV(" driver: v%d.%d.%d\n" , driverVersion >> 16 , (driverVersion >> 8 ) & 0xff , driverVersion & 0xff ); device->loadConfigurationLocked(); device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0 ), device->keyBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0 ), device->absBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_REL, 0 ), device->relBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0 ), device->swBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0 ), device->ledBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0 ), device->ffBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_MSC, 0 ), device->mscBitmask); device->readDeviceBitMask(EVIOCGPROP(0 ), device->propBitmask);
修改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 ALOGV(" name: \"%s\"\n" , identifier.name.c_str()); ALOGV(" location: \"%s\"\n" , identifier.location.c_str()); ALOGV(" unique id: \"%s\"\n" , identifier.uniqueId.c_str()); ALOGV(" descriptor: \"%s\"\n" , identifier.descriptor.c_str()); ALOGV(" driver: v%d.%d.%d\n" , driverVersion >> 16 , (driverVersion >> 8 ) & 0xff , driverVersion & 0xff ); device->loadConfigurationLocked();if (device->configuration && device->configuration->getBool("device.disabled" )) { device->disable(); ALOGV("Disabling device with id %d\n" , device->id); } device->readDeviceBitMask(EVIOCGBIT(EV_KEY, 0 ), device->keyBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_ABS, 0 ), device->absBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_REL, 0 ), device->relBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_SW, 0 ), device->swBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_LED, 0 ), device->ledBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_FF, 0 ), device->ffBitmask); device->readDeviceBitMask(EVIOCGBIT(EV_MSC, 0 ), device->mscBitmask); device->readDeviceBitMask(EVIOCGPROP(0 ), device->propBitmask);
其中修改的部分是:新增了这一段代码:
1 2 3 4 5 6 if (device->configuration && device->configuration->getBool("device.disabled" )) { device->disable(); ALOGV("Disabling device with id %d\n" , device->id); }
接下来,就是重新增量编译系统! 如果你遇到了CONFIG_SYSVIPC
和FCM
相关的报错:
1 2 3 For kernel requirements at matrix level 5, Kernel config errors: For config CONFIG_SYSVIPC, value = y but required n : Success
那就去kernel/configs/*/*/android-base.config
里删掉# CONFIG_SYSVIPC is not set
。是的没错,是kernel/configs
下每个子文件夹里的所有子文件夹里的android-base.config
再重新编译。
如果在开机后遇到了overlayfs
无法挂载的错误,应用这个补丁 ,或手动修改: 打开fs/overlayfs/util.c
: 找到这段代码,将这段代码:
1 2 3 4 5 6 7 8 9 10 bool ovl_dentry_weird (struct dentry *dentry) { return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | DCACHE_MANAGE_TRANSIT | DCACHE_OP_HASH | DCACHE_OP_COMPARE); DCACHE_MANAGE_TRANSIT); }enum ovl_path_type ovl_path_type (struct dentry *dentry)
修改为:
1 2 3 4 5 6 7 bool ovl_dentry_weird (struct dentry *dentry) { return dentry->d_flags & (DCACHE_NEED_AUTOMOUNT | DCACHE_MANAGE_TRANSIT); }enum ovl_path_type ovl_path_type (struct dentry *dentry)
但是很可惜,我的小米5遇到了这段overlayfs
的报错:
1 2 3 4 02-10 21:18:16.334 3495 3494 I perspectived_lxc: test: overlay - external/lxc/src/lxc/storage/overlay.c:ovl_mount:483 - Invalid argument - Failed to mount "/data/lindroid/lxc/rootfs_ro" on "/data/lindroid/lxc/rootfs" with options "upperdir=/data/lindroid/lxc/container/test/rootfs,lowerdir=/data/lindroid/lxc/rootfs_ro,workdir=/data/lindroid/lxc/container/test/work". Retrying without workdir 02-10 21:18:16.334 0 0 E overlayfs: filesystem on '/data/lindroid/lxc/container/test/rootfs' not supported as upperdir 02-10 21:18:16.336 3495 3494 E perspectived_lxc: test: overlay - external/lxc/src/lxc/storage/overlay.c:ovl_mount:491 - Invalid argument - Failed to mount "/data/lindroid/lxc/rootfs_ro" on "/data/lindroid/lxc/rootfs" with options "upperdir=/data/lindroid/lxc/container/test/rootfs,lowerdir=/data/lindroid/lxc/rootfs_ro" 02-10 21:18:16.336 3495 3494 E perspectived_lxc: test: conf - external/lxc/src/lxc/conf.c:lxc_mount_rootfs:1238 - Failed to mount rootfs "/data/lindroid/lxc/rootfs_ro:/data/lindroid/lxc/container/test/rootfs" onto "/data/lindroid/lxc/rootfs" with options "(null)"
但我的内核里并不存在util.c
。Lindroid作者的回复是,4.4内核太老了,就算修了这个问题,后面会遇到的问题也会很多。后面的路,以后再来探索吧!