0%

给 Xiaomi 6 编译 LineageOS 过程小记

2023年9月1日: 更新了大伙儿常遇到的 breakfast 命令失败的问题处理办法, 可以参考一下.

最近给手头的 Xiaomi 6 刷了 LneageOS, 体验了一把 Android 15, 挺香的! 但是这个系统有那么一丢丢水土不服, 于是决定自己来改改然后编译一个出来玩玩.

主机描述

  • CPU >= 4C
  • MEM >= 16G
  • DISK >= 200G
  • NET >= 100M
  • OS >= Debian 11/12/13
  • Docker >= Debian 13 Image

环境准备

基础环境镜像

构建镜像

docker build -t build-base - <<\EOF
FROM debian:13

RUN <<EOT
    sed -i -e 's|deb.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list.d/debian.sources
    apt update
    # install base tool
    apt install -y sudo bash-completion command-not-found procps vim wget curl net-tools
    # install version control
    apt install git subversion python3
    wget https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -O /usr/local/bin/repo
    chmod +x /usr/local/bin/repo
    # build command not found data
    apt update
    apt clean && rm -rf /var/lib/apt/lists/*
EOT

ENV TZ=Asia/Shanghai
RUN <<EOT
    useradd --create-home --uid 1000 --groups users,sudo --shell /bin/bash user
    echo "user:1111" | chpasswd
    ln -snf /usr/share/zoneinfo/${TZ} /etc/localtime
    echo "${TZ}" > /etc/timezone
EOT

COPY <<EOT /etc/profile.d/aliases.sh
alias ll='ls -lh -F --color=auto --time-style=long-iso'
alias la='ls -lhA -F --color=auto --time-style=long-iso'
alias lt='ls -lht -F --color=auto --time-style=long-iso'
alias lat='ls -lhAt -F --color=auto --time-style=long-iso'
EOT

USER user
WORKDIR /home/user/
EOF
  1. 使用管道输入 Dockerfile 内容,自定义镜像标签为 build-base
    https://docs.docker.com/build/building/context/#how-to-build-without-a-context
  2. 使用 Here-Documents 运行 RUNCOPY 指令,注意如果是在 Dockerfile 中使用需要保证文件换行符是 LF
    https://docs.docker.com/reference/dockerfile/#here-documents
  3. 备用镜像站:
    - mirrors.aliyun.com
    - mirrors.cernet.edu.cn
    - mirrors.tuna.tsinghua.edu.cn

使用镜像

docker run -ti --rm build-base bash -l
  1. 默认为 non-loginshell,需要使用 ‘-l’ 参数登录以生效 /etc/profile 配置。
    https://github.com/gliderlabs/docker-alpine/issues/443

编译环境镜像

构建镜像

docker build -t build-lineage - <<\EOF
FROM build-base
USER root

RUN <<EOT
    apt update
    # toolchain
    apt install -y bc bison build-essential ccache curl flex g++-multilib gcc-multilib git git-lfs gnupg gperf imagemagick protobuf-compiler python3-protobuf lib32readline-dev lib32z1-dev libdw-dev libelf-dev libgnutls28-dev lz4 libsdl1.2-dev libssl-dev libxml2 libxml2-utils lzop pngcrush rsync schedtool squashfs-tools xsltproc zip zlib1g-dev
    apt clean &&  rm -rf /var/lib/apt/lists/*
EOT

USER user
EOF

软件列表请参考: https://wiki.lineageos.org/devices/sagit/build#install-the-build-packages

使用镜像

docker run -ti --rm --privileged -v ~/projects/:/projects/ build-lineage bash -l

拉取代码

配置 git 用户信息

配置基本信息:

git config --global user.email "you@example.com"
git config --global user.name "Your Name"

指定 LineageOS 仓库镜像(清华大学镜像源):

cat >> ~/.gitconfig <<EOF
#[http "https://gerrit.googlesource.com/"]
#    proxy = socks5://192.168.8.12:10808
#[http "https://android.googlesource.com/"]
#    proxy = socks5://192.168.8.12:10808
#[http "https://review.lineageos.org/"]
#    proxy = socks5://192.168.8.12:10808
#[http "https://github.com/LineageOS/"]
#    proxy = socks5://192.168.8.12:10808

[url "https://mirrors.tuna.tsinghua.edu.cn/git/git-repo"]
    insteadof = https://gerrit.googlesource.com/git-repo
[url "https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/"]
    insteadof = https://android.googlesource.com/
[url "https://mirrors.tuna.tsinghua.edu.cn/git/lineageOS/"]
    insteadof = https://review.lineageos.org/
[url "https://mirrors.tuna.tsinghua.edu.cn/git/lineageOS/LineageOS/"]
    insteadof = https://github.com/LineageOS/
EOF

有时候镜像源可能出现代码尚未完成同步的情况, 这个时候建议屏蔽镜像开启代理尝试直接同步.

同步代码

mkdir -p ~/projects/android/android_lineage_22
cd ~/projects/android/android_lineage_22
repo init -u https://github.com/LineageOS/android.git -b lineage-22.2 --git-lfs --depth=1
repo sync -c -d

--depth=1 表示浅克隆, 只拉取一层代码.

启动容器

docker run -ti --rm --privileged -v ~/projects/:/projects/ build-lineage bash -l

编译

配置 ccache 加速(可选)

cat >> ~/.bashrc <<EOF
export USE_CCACHE=1
export CCACHE_EXEC=/usr/bin/ccache
export CCACHE_DIR=~/.cache/ccache
EOF

ccache -M 50G
ccache -o compression=true
mkdir -p ~/.cache/ccache/

初始化编译环境

cd /projects/android/android_lineage_22/

source build/envsetup.sh
breakfast sagit

这个环节会根据设备型号拉取对应的产品构建组件仓库, 建议使用镜像仓库加速.
对于 Xiaomi 6, 这个环节第一次执行会因为没有导入二进制文件而失败, 请参考踩坑记录.
如果碰到 Can not locate config makefile for product "lineage_sagit". 的问题也请参考踩坑记录.

导入厂商二进制文件

厂商代码是不开源的, 需要引用现有的二进制; 可以从设备提取, 也可以从现有的 ROM 包里面提取, 二选一即可.

  • 从现有 ROM 包里面提取(推荐)

    sudo apt update
    sudo apt install -y python3 e2fsprogs
    sudo ln -s /usr/bin/python3 /usr/bin/python
    cd /projects/android/android_lineage_22/device/xiaomi/sagit/
    
    ./extract-files.py path/to/lineage-*.zip
    

    所需要的工具可以在 tools/extract-utils/extract_utils/extract.py 文件中看到.

  • 从设备提取

    cd /projects/android/android_lineage_22/device/xiaomi/sagit/
    
    ./extract-files.py
    

    这个环节需要开启 Xiaomi 6 设备的 开发者选项的调试模式 , 并连接至编译主机. 然后执行上述命令.

正常导入完成之后, 能够在 vendor 下面看到编译依赖:

user@5e613a9deb71:/projects/android/android_lineage_22$ ls -lh vendor/xiaomi/sagit/
total 104K
-rw-r--r-- 1 user user  77K Dec 24 20:11 Android.bp
-rw-r--r-- 1 user user   80 Dec 24 20:11 Android.mk
-rw-r--r-- 1 user user   50 Dec 24 20:11 BoardConfigVendor.mk
drwxr-xr-x 3 user user 4.0K Dec 24 20:11 proprietary
-rw-r--r-- 1 user user 9.2K Dec 24 20:11 sagit-vendor.mk

之后重新执行 breakfast sagit 初始化环境.

启动编译

cd /projects/android/android_lineage_22/

brunch sagit

踩坑记录

git lfs 同步失败

  • 错误示例
    Downloading webview.apk (91 MB)
    Error downloading object: webview.apk (e35a2a1): Smudge error: Error downloading webview.apk (e35a2a15f6dd1055ba3320f280849474eafc73d56ee26cecb7a3273ffbaa24c2): batch response: Repository or object not found: https://mirrors.tuna.tsinghua.edu.cn/git/lineageOS/LineageOS/android_external_chromium-webview_prebuilt_arm.git/info/lfs/objects/batch
    Check that it exists and that you have proper access to it
    
    Errors logged to /home/liux/projects/android_lineage/.repo/projects/external/chromium-webview/prebuilt/arm.git/lfs/logs/20230510T215212.15094947.log
    Use `git lfs logs last` to view the log.
    error: 外部过滤器 'git-lfs filter-process' 失败
    fatal: webview.apk:smudge 过滤器 lfs 失败
    error.GitError: Cannot checkout LineageOS/android_external_chromium-webview_prebuilt_arm: Cannot initialize work tree for LineageOS/android_external_chromium-webview_prebuilt_arm
    error: Cannot checkout LineageOS/android_external_chromium-webview_prebuilt_arm
    正在更新文件: 100% (2237/2237), 完成.
    正在更新文件: 100% (3547/3547), 完成.
    
    error: 工作区中下列未跟踪的文件将会因为检出操作而被覆盖:
    	.gitattributes
    	.lfsconfig
    请在切换分支前移动或删除。
    正在终止
    error: external/chromium-webview/prebuilt/arm64/: LineageOS/android_external_chromium-webview_prebuilt_arm64 checkout ed88096ab28a21d2fb785899532194b3a67438f1
    error: Cannot checkout LineageOS/android_external_chromium-webview_prebuilt_arm64
    
    error: Unable to fully sync the tree.
    error: Checking out local projects failed.
    Failing repos:
    external/chromium-webview/prebuilt/arm
    external/chromium-webview/prebuilt/arm64
    external/chromium-webview/prebuilt/x86
    external/chromium-webview/prebuilt/x86_64
    Try re-running with "-j1 --fail-fast" to exit at the first error.
    

    由于上面拉取代码是配置了镜像仓库的, 但是镜像仓库中 git lfs 的部分文件不全, 导致同步失败.

拉取代码偶现无法解析主机名

  • 错误示例

  • 解决办法
    避免使用过多的线程, 宽带带宽不够的情况下某些线程抢不到资源, 导致连接失败;
    检查网络连接质量, 必要时可以考虑科学上网;

    # http
    git config --global http.proxy 'http://192.168.8.12:10808'
    git config --global https.proxy 'http://192.168.8.12:10808'
    # socks
    git config --global http.proxy 'socks5://192.168.8.12:10808'
    git config --global https.proxy 'socks5://192.168.8.12:10808'
    # cancel
    git config --global --unset http.proxy
    git config --global --unset https.proxy
    

运行 breakfast 找不到产品

  • 错误示例

    In file included from build/make/core/config.mk:406:
    In file included from build/make/core/envsetup.mk:351:
    build/make/core/product_config.mk:226: error: Cannot locate config makefile for product "lineage_sagit".
    15:20:28 dumpvars failed with: exit status 1
    Device sagit not found. Attempting to retrieve device repository from LineageOS Github (http://github.com/LineageOS).
    Failed to fetch data from GitHub
    In file included from build/make/core/config.mk:406:
    In file included from build/make/core/envsetup.mk:351:
    build/make/core/product_config.mk:226: error: Cannot locate config makefile for product "lineage_sagit".
    15:20:41 dumpvars failed with: exit status 1
    In file included from build/make/core/config.mk:406:
    In file included from build/make/core/envsetup.mk:351:
    build/make/core/product_config.mk:226: error: Cannot locate config makefile for product "lineage_sagit".
    15:20:44 dumpvars failed with: exit status 1
    
    ** Don't have a product spec for: 'lineage_sagit'
    ** Do you have the right repo manifest?
    

    这是我新硬盘重新拉取代码后出现的问题, 第一次搭建环境的时候并没有出现, 折腾了很久. 最终通过看源码的方式定位原来是访问不到 Github 的文件服务器(刚好我上次同步代码的时候可以访问, 这个问题出现的频次挺高的, 我发了博客之后好几个人找我说了这个问题, 当时是不知所云, 现在明白了~).
    LineageOS 源码在第一次初始化某个产品到时候, 会去 Github 上检索对应的配置便于拉取对于的代码仓库, 这个过程是通过访问 Github 的接口来实现的, 出现这个错误就是访问不到 Github 的文件服务器了.

  • 解决办法
    在文件 vendor/lineage/build/tools/roomservice.py 中作如下修改:

    diff --git a/build/tools/roomservice.py b/build/tools/roomservice.py
    index 8c55c51..d59dc00 100755
    --- a/build/tools/roomservice.py
    +++ b/build/tools/roomservice.py
    @@ -51,6 +51,9 @@ repositories = []
    
     if not depsonly:
         githubreq = urllib.request.Request("https://raw.githubusercontent.com/LineageOS/mirror/main/default.xml")
    +    proxy = urllib.request.ProxyHandler({'http': '192.168.8.12:10808', 'https': '192.168.8.12:10808'})
    +    opener = urllib.request.build_opener(proxy, urllib.request.HTTPHandler)
    +    urllib.request.install_opener(opener)
         try:
             result = ElementTree.fromstring(urllib.request.urlopen(githubreq, timeout=10).read().decode())
         except urllib.error.URLError:
    

    就是给访问 Github 的请求加上代理服务器即可. 也可以尝试给 shell 环境加代理试试, 我这不想污染环境就没尝试了.

运行 breakfast 报错没有找到文件

  • 错误示例

    In file included from build/make/core/config.mk:353:
    In file included from build/make/core/envsetup.mk:352:
    In file included from build/make/target/product/telephony_vendor.mk:21:
    device/xiaomi/sagit/device.mk:54: error:  vendor/xiaomi/sagit/sagit-vendor.mk does not exist..
    09:32:24 dumpvars failed with: exit status 1
    Device sagit not found. Attempting to retrieve device repository from LineageOS Github (http://github.com/LineageOS).
    Found repository: android_device_xiaomi_sagit
    Default revision: lineage-20.0
    Checking branch info
    Using fallback branch: lineage-20
    Checking if device/xiaomi/sagit is fetched from android_device_xiaomi_sagit
    LineageOS/android_device_xiaomi_sagit already fetched to device/xiaomi/sagit
    Syncing repository to retrieve project.
    Fetching: 100% (1/1), done in 1.015s
    repo sync has finished successfully.
    Repository synced!
    Looking for dependencies in device/xiaomi/sagit
    Looking for dependencies in device/xiaomi/msm8998-common
    Looking for dependencies in hardware/xiaomi
    hardware/xiaomi has no additional dependencies.
    Looking for dependencies in kernel/xiaomi/msm8998
    kernel/xiaomi/msm8998 has no additional dependencies.
    Done
    In file included from build/make/core/config.mk:353:
    In file included from build/make/core/envsetup.mk:352:
    In file included from build/make/target/product/telephony_vendor.mk:21:
    device/xiaomi/sagit/device.mk:54: error:  vendor/xiaomi/sagit/sagit-vendor.mk does not exist..
    09:32:29 dumpvars failed with: exit status 1
    In file included from build/make/core/config.mk:353:
    In file included from build/make/core/envsetup.mk:352:
    In file included from build/make/target/product/telephony_vendor.mk:21:
    device/xiaomi/sagit/device.mk:54: error:  vendor/xiaomi/sagit/sagit-vendor.mk does not exist..
    09:32:30 dumpvars failed with: exit status 1
    
    ** Don't have a product spec for: 'lineage_sagit'
    ** Do you have the right repo manifest?
    
  • 解决办法

    IMPORTANT: Some devices require a vendor directory to be populated before breakfast will succeed. If you receive an error here about vendor makefiles, jump down to Extract proprietary blobs. The first portion of breakfast should have succeeded, and after completing you can rerun breakfast
    

    某些设备需要填充供应商目录,然后才能成功 breakfast。需要先执行 导入厂商二进制文件 步骤然后再 breakfast

参考

  • 本文作者: 6x
  • 本文链接: https://6xyun.cn/article/169
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-ND 许可协议。转载请注明出处!