OnePlus 7 Pro LineageOS 19.1 构建与内核 Docker 支持并在 Termux 上实现容器运行全流程指南

OnePlus 7 Pro LineageOS 19.1 构建与内核 Docker 支持并在 Termux 上实现容器运行全流程指南

OnePlus 7 Pro LineageOS 19.1 构建与内核 Docker 支持并在 Termux 上实现容器运行全流程指南

#docker,#linux,#termux,#android,#kernel,#lineageos,#oneplus,#git,


注意,获取自己的手机型号代号,这一点很重要在后续的命令中都要用到
比如我的手机 oneplus7pro 是 guacamole 也可以尝试通过命令获取获取,但是我不知道是不是所有设备都是这样获取的

adb shell getprop ro.boot.project_codename

最重要的是,一定要找好固件包,免得变成砖头,有线刷包就可以怎么折腾都不怕
最近 OP7P 设备型号是 guacamole 手机刷了 GM1910_11_H.40 即 android 12
https://gauss-componentotacostmanual-sg.allawnofs.com/remove-d74c973c240292cb011317bb07f424a2/component-ota/23/03/28/6d4604798d27450e8de05671d5effbae.zip
内核版本 4.14.180-perf+
发现 github.com/OnePlusOSS 官方有相关的开放残缺的内核源码,但缺失了很多代码配置
https://github.com/OnePlusOSS/android_kernel_oneplus_sm8150/tree/oneplus/sm8150_s_12.1_op7pro
所以我在想可不可在官方android系统的基础上编译支持docker的内核?然而我失败了,所以我直接放弃,直接使用 lineage-19.1 的源码编译刷机
android 12 源码太吃内存云服务器已经不能满足了,所以只能是买一个二手的gmk m6 mini x86_64主机,尝试编译
gmk m6 配置是 24g 12c 1T+1T Ubuntu 24.04.2 LTS 实际运行内存 20G
由于内存不足也意味着需要 swap 扩展补充 45G 以满足编译 android 12 的条件 >=64G
实际编译时常 05:56:45
临时配置swap在内存不足的时候可以借磁盘空间,磁盘因此降低写入

# 查看当前swap启用所使用的文件假设为 /swap.img
sudo swapon --show
# 查看当前内存状态
sudo free -h
# 关闭swap文件占用
sudo swapoff /swap.img
# 差不多有>=64G就行
sudo fallocate -l 45G /swap.img
sudo du -sh /swap.img 
sudo chmod 600 /swap.img
sudo mkswap /swap.img
sudo swapon /swap.img
sudo free -h

如果你想开机自动挂载 swap 则固化到 /etc/fstab(可选)

sudo nano /etc/fstab

追加以下内容

/swap.img  none  swap  sw  0  0


由于不想污染本地宿主机环境,我打算安装 docker 环境,在 docker 中编译 android 12 镜像

# 系统可以使用官方一键安装脚本 https://github.com/docker/docker-install
curl -fsSL https://test.docker.com -o test-docker.sh
sh test-docker.sh
# Manage Docker as a non-root user
## 非 root 用户需要加入到 docker 组才有权限使用
# Create the docker group
## 添加 docker 组
sudo groupadd docker
# Add your user to the docker group.
## 将当前用户加入到 docker 组权限
sudo usermod -aG docker ${USER}
# Log out and log back in so that your group membership is re-evaluated.
## 临时进入 docker 组测试,更好的方式是退出并重新登录测试
newgrp docker 
# Configure Docker to start on boot
# 启用 docker 开机自启动服务
sudo systemctl enable docker.service
sudo systemctl enable containerd.service
# satrt
# 开启 docker 服务,其实上一步就启用了
sudo systemctl start docker.service
sudo systemctl start containerd.service
# Verify that Docker Engine is installed correctly by running the hello-world image
# 测试 docker hello-world:latest 打印
docker run --rm hello-world:latest


compose 也更新一下过程如下

# GitHub 项目 URI
URI="docker/compose"

# 获取最新版本
VERSION=$(curl -sL "https://github.com/${URI}/releases" | grep -Eo '/releases/tag/[^"]+' | awk -F'/tag/' '{print $2}' | head -n 1)
echo "Latest version: ${VERSION}"

# 获取操作系统和架构信息
OS=$(uname -s)
ARCH=$(uname -m)

# 映射平台到官方命名
case "${OS}" in
  Linux)
    PLATFORM="linux"
    if [[ "${ARCH}" == "arm64" || "${ARCH}" == "aarch64" ]]; then
      ARCH="aarch64"
    elif [[ "${ARCH}" == "x86_64" ]]; then
      ARCH="x86_64"
    else
      echo "Unsupported architecture: ${ARCH}"
      echo 'should exit 1'
    fi
    ;;
  *)
    echo "Unsupported OS: ${OS}"
    echo 'should exit 1'
    ;;
esac

# 输出最终平台和架构
echo "Platform: ${PLATFORM}"
echo "Architecture: ${ARCH}"

# 拼接下载链接和校验码链接
TARGET_FILE="docker-compose-${PLATFORM}-${ARCH}"
SHA256_FILE="${TARGET_FILE}.sha256"
URI_DOWNLOAD="https://github.com/${URI}/releases/download/${VERSION}/${TARGET_FILE}"
URI_SHA256="https://github.com/${URI}/releases/download/${VERSION}/${SHA256_FILE}"
echo "Download URL: ${URI_DOWNLOAD}"
echo "SHA256 URL: ${URI_SHA256}"

# 检查文件是否存在
if [[ -f "/tmp/${TARGET_FILE}" ]]; then
  echo "File already exists: /tmp/${TARGET_FILE}"
  
  # 删除旧的 SHA256 文件(如果存在)
  if [[ -f "/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: /tmp/${SHA256_FILE}"
    rm -fv "/tmp/${SHA256_FILE}"
  fi

  # 下载新的 SHA256 文件
  echo "Downloading SHA256 file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "/tmp/${SHA256_FILE}" "${URI_SHA256}"

  # 校验文件完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for /tmp/${TARGET_FILE}..."
  cd /tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    log_warning "SHA256 checksum failed. Removing file and retrying..."
    rm -fv "/tmp/${TARGET_FILE}"
  else
    echo "File integrity verified successfully."
  fi
fi

# 如果文件不存在或之前校验失败
if [[ ! -f "/tmp/${TARGET_FILE}" ]]; then
  echo "Downloading file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "/tmp/${TARGET_FILE}" "${URI_DOWNLOAD}"

  # 删除旧的 SHA256 文件并重新下载
  if [[ -f "/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: /tmp/${SHA256_FILE}"
    rm -fv "/tmp/${SHA256_FILE}"
  fi
  echo "Downloading SHA256 file..."
  curl -L --progress-bar -o "/tmp/${SHA256_FILE}" "${URI_SHA256}"

  # 校验完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for /tmp/${TARGET_FILE}..."
  cd /tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    echo "Download failed: SHA256 checksum does not match."
    echo 'should exit 1'
  else
    echo "File integrity verified successfully."
  fi
fi

sudo mv -fv "/tmp/${TARGET_FILE}" /usr/local/bin/docker-compose
# Apply executable permissions to the binary
## 赋予执行权
sudo chmod -v +x /usr/local/bin/docker-compose
# create a symbolic link to /usr/libexec/docker/cli-plugins/
# 创建插件目录和软链接
sudo mkdir -pv /usr/libexec/docker/cli-plugins/
sudo ln -sfv /usr/local/bin/docker-compose /usr/libexec/docker/cli-plugins/docker-compose
# Test the installation.
## 测试版本打印
docker-compose version
docker compose version


buildx 也更新一下过程如下

# GitHub 项目 URI
URI="docker/buildx"

# 获取最新版本
VERSION=$(curl -sL "https://github.com/${URI}/releases" | grep -Eo '/releases/tag/[^"]+' | awk -F'/tag/' '{print $2}' | head -n 1)
echo "Latest version: ${VERSION}"

# 获取操作系统和架构信息
OS=$(uname -s)
ARCH=$(uname -m)

# 映射平台到官方命名
case "${OS}" in
  Linux)
    PLATFORM="linux"
    if [[ "${ARCH}" == "arm64" || "${ARCH}" == "aarch64" ]]; then
      ARCH="arm64"
    elif [[ "${ARCH}" == "x86_64" ]]; then
      ARCH="amd64"
    else
      echo "Unsupported architecture: ${ARCH}"
      echo 'should exit 1'
    fi
    ;;
  *)
    echo "Unsupported OS: ${OS}"
    echo 'should exit 1'
    ;;
esac

# 输出最终平台和架构
echo "Platform: ${PLATFORM}"
echo "Architecture: ${ARCH}"

# 拼接下载链接和校验码链接
TARGET_FILE="buildx-${VERSION}.${PLATFORM}-${ARCH}"
SHA256_FILE="${TARGET_FILE}.sbom.json"
URI_DOWNLOAD="https://github.com/${URI}/releases/download/${VERSION}/${TARGET_FILE}"
URI_SHA256="https://github.com/${URI}/releases/download/${VERSION}/${SHA256_FILE}"
echo "Download URL: ${URI_DOWNLOAD}"
echo "SHA256 URL: ${URI_SHA256}"

# 检查文件是否存在
if [[ -f "/tmp/${TARGET_FILE}" ]]; then
  echo "File already exists: /tmp/${TARGET_FILE}"
  
  # 删除旧的 SHA256 文件(如果存在)
  if [[ -f "/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: /tmp/${SHA256_FILE}"
    rm -fv "/tmp/${SHA256_FILE}"
  fi

  # 下载新的 SHA256 文件
  echo "Downloading SHA256 file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "/tmp/${SHA256_FILE}" "${URI_SHA256}"
  # 提取校验码
  CHECKSUM=$(cat "/tmp/${SHA256_FILE}" | jq -r --arg filename "${TARGET_FILE}" '.subject[] | select(.name == $filename) | .digest.sha256')
  # 将校验码写入源文件
  echo "${CHECKSUM} *${TARGET_FILE}" > "/tmp/${SHA256_FILE}"
  echo "校验码 ${CHECKSUM} 已写入文件: /tmp/${SHA256_FILE}"

  # 校验文件完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for /tmp/${TARGET_FILE}..."
  cd /tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    log_warning "SHA256 checksum failed. Removing file and retrying..."
    rm -fv "/tmp/${TARGET_FILE}"
  else
    echo "File integrity verified successfully."
  fi
fi

# 如果文件不存在或之前校验失败
if [[ ! -f "/tmp/${TARGET_FILE}" ]]; then
  echo "Downloading file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "/tmp/${TARGET_FILE}" "${URI_DOWNLOAD}"

  # 删除旧的 SHA256 文件并重新下载
  if [[ -f "/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: /tmp/${SHA256_FILE}"
    rm -fv "/tmp/${SHA256_FILE}"
  fi
  echo "Downloading SHA256 file..."
  curl -L --progress-bar -o "/tmp/${SHA256_FILE}" "${URI_SHA256}"
  # 提取校验码
  CHECKSUM=$(cat "/tmp/${SHA256_FILE}" | jq -r --arg filename "${TARGET_FILE}" '.subject[] | select(.name == $filename) | .digest.sha256')
  # 将校验码写入源文件
  echo "${CHECKSUM} *${TARGET_FILE}" > "/tmp/${SHA256_FILE}"
  echo "校验码 ${CHECKSUM} 已写入文件: /tmp/${SHA256_FILE}"

  # 校验完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for /tmp/${TARGET_FILE}..."
  cd /tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    echo "Download failed: SHA256 checksum does not match."
    echo 'should exit 1'
  else
    echo "File integrity verified successfully."
  fi
fi

sudo mv -fv "/tmp/${TARGET_FILE}" /usr/local/bin/docker-buildx
# Apply executable permissions to the binary
## 赋予执行权
sudo chmod -v +x /usr/local/bin/docker-buildx
# create a symbolic link to /usr/libexec/docker/cli-plugins/
# 创建插件目录和软链接
sudo mkdir -pv /usr/libexec/docker/cli-plugins/
sudo ln -sfv /usr/local/bin/docker-buildx /usr/libexec/docker/cli-plugins/docker-buildx
# Test the installation.
## 测试版本打印
docker-buildx version
docker buildx version


创建目录,创建启动容器并挂载,进入容器
其中一块磁盘已经牺牲读写性能用于 swap 了,那么就用另一块磁盘存储源码负责编译读写
当然最痛苦的就是cpu了,这么多磁盘读写cpu一定会满
另一块 1T SSD 打算用路径 /mnt/KINGSTONSSD1T/workspace/android-build

sudo mkdir -pv /mnt/KINGSTONSSD1T/workspace/android-build
docker run --restart=always --platform linux/amd64 --privileged \
           --name android-build -d -e DEBIAN_FRONTEND=noninteractive \
           -it -v /mnt/KINGSTONSSD1T/workspace:/root/workspace \
           -v /dev/bus/usb:/dev/bus/usb \
           docker.io/library/ubuntu:22.04 \
           bash
docker exec -it android-build bash


容器内编译操作

# 安装编译环境依赖
apt update && apt -y install bc bison build-essential ccache curl \
                             file flex g++-multilib gcc-multilib git \
                             git-lfs gnupg gperf htop imagemagick \
                             lib32ncurses-dev lib32readline-dev lib32z1-dev libdw-dev libelf-dev \
                             liblz4-tool libncurses-dev libncurses5 libncurses6 libsdl1.2-dev \
                             libssl-dev libtinfo5 libwxgtk3.0-gtk3-dev libxml2 libxml2-utils \
                             locales lz4 lzop nano pngcrush \
                             protobuf-compiler python2 python3-protobuf rsync schedtool \
                             squashfs-tools systemd tzdata xsltproc zip \
                             zlib1g-dev

ln -sfv $(command -v python3) /usr/bin/python

# 获取官方 platform-tools 工具
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o "/root/workspace/platform-tools-latest-linux.zip" \
     'https://dl.google.com/android/repository/platform-tools-latest-linux.zip'
unzip -o /root/workspace/platform-tools-latest-linux.zip -d /root/workspace/
# 删除压缩包节省空间
rm -frv /root/workspace/platform-tools-latest-linux.zip

# 获取镜像解包 ota extract-tools 工具
git clone https://github.com/LineageOS/android_prebuilts_extract-tools \
          /root/workspace/android_prebuilts_extract-tools

# 创建repo环境
mkdir -pv /root/workspace/bin
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o "/root/workspace/bin/repo" \
     'https://storage.googleapis.com/git-repo-downloads/repo'
chmod -v a+x /root/workspace/bin/repo
# 本地网络不行,需要修改 repo 源
#sed -i 's;https://gerrit.googlesource.com/git-repo;https://mirrors.tuna.tsinghua.edu.cn/git/git-repo;g' \
#       /root/workspace/bin/repo
# 还原
#sed -i 's;https://mirrors.tuna.tsinghua.edu.cn/git/git-repo;https://gerrit.googlesource.com/git-repo;g' \
#       /root/workspace/bin/repo

# 写入环境
cat << '469138946ba5fa' | tee /root/workspace/buildenv
# 固定使用系统中可用的 locale
export LANG=en_US.utf8
export LANGUAGE=en_US:en
export LC_ALL=en_US.utf8
echo "Generating en_US.utf8 locale..."
locale-gen en_US.utf8
update-locale LANG=en_US.utf8
echo "Environment is set:"
locale

ln -fsv /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
dpkg-reconfigure -f noninteractive tzdata

# add Android SDK platform tools to path
if [ -d "/root/workspace/platform-tools" ] ; then
    export PATH="/root/workspace/platform-tools:${PATH}"
fi

# add Android ota extract-tools tools to path
if [ -d "/root/workspace/android_prebuilts_extract-tools/linux-x86/bin" ] ; then
    export PATH="/root/workspace/android_prebuilts_extract-tools/linux-x86/bin:${PATH}"
fi

# set PATH so it includes user's private bin if it exists
if [ -d "/root/workspace/bin" ] ; then
    export PATH="/root/workspace/bin:${PATH}"
fi

# 强制 Java 使用 UTF-8 编码,防止 java 编译时读取字符产生错误
export JAVA_TOOL_OPTIONS="-Dfile.encoding=UTF-8"

# 创建临时存储链接
rm -fr ${HOME}/.cache
mkdir -pv ${HOME}/.cache
# 配置磁盘缓存相关配置增大缓存容量
export USE_CCACHE=1
export CCACHE_DIR=${HOME}/.cache
export CCACHE_EXEC=/usr/bin/ccache
ccache -M 50G
ccache -o compression=true

# 指定导出位置
#export OUT_DIR_COMMON_BASE=/root/workspace

# 配置 git 用户信息
git config --global user.email "469138946ba5fa@outlook.com"
git config --global user.name "469138946ba5fa"

# Switching the SSL backend to gnutls can resolve this issue.
#git config --global http.sslBackend gnutls
#git config --global --unset http.sslBackend

# Git 传输数据量较大,可能会导致超时或连接中断。你可以增加 Git 的缓冲区
#git config --global http.postBuffer 1048576000
#git config --global https.postBuffer 1048576000
#git config --global http.maxRequestBuffer 100M

# 网络连接不稳定,TLS 握手可能会失败。你可以增加超时时间
#git config --global http.lowSpeedLimit 1
#git config --global http.lowSpeedTime 600

# 有些服务器对 HTTP/2 兼容性较差,你可以强制 Git 使用 HTTP/1.1
#git config --global http.version HTTP/1.1
# 强制 Git 使用 HTTP/2
#git config --global http.version HTTP/2
# 跳过 ssl 证书校验
#git config --global http.sslVerify false
469138946ba5fa

# 加载自定义的 repo 和 adb 环境
source /root/workspace/buildenv

# 创建源码目录并获取
mkdir -pv /root/workspace/android-build/lineage-19.1
cd /root/workspace/android-build/lineage-19.1
repo init -u https://github.com/LineageOS/android.git -b lineage-19.1 --git-lfs --no-clone-bundle

# 本地网络不行,需要替换 AOSP 为 tsinghua 源
#sed -i 's;https://android.googlesource.com;https://mirrors.tuna.tsinghua.edu.cn/git/AOSP;g' \
#       .repo/manifests/default.xml
# 还原
#sed -i 's;https://mirrors.tuna.tsinghua.edu.cn/git/AOSP;https://android.googlesource.com;g' \
#       .repo/manifests/default.xml

# 通常情况下,你可以直接运行:首次同步代码
repo sync

# 如果过程中断,可以执行以下命令继续同步,这会清除锁定的文件
# 继续同步未完成的部分,而不会重新下载已经同步的内容。
find .repo -name "index.lock" -exec rm -f {} \;
repo sync -c --optimized-fetch --prune --force-sync

# 完成同步后加载脚本环境
source build/envsetup.sh

# 尝试下载特定设备的内核 和 配置,比如我的 OP7P 设备型号是 guacamole
breakfast guacamole

如果有vender相关的报错,比如

device/oneplus/guacamole/device.mk:56: error:  
vendor/oneplus/guacamole/guacamole-vendor.mk does not exist..

则有三种方案,任选其一,建议方案一
第一种方案 需要创建自定义配置,添加第三方 vendor 专有文件仓库
vendor blobs 必须与运行系统的 Android 版本 ABI 匹配

# 需要创建自定义配置,添加第三方 vendor 专有文件仓库 .repo/local_manifests/roomservice.xml
# 添加 vendor/oneplus 专有文件仓库也必须支持 android 16
mkdir -pv .repo/local_manifests/
nano .repo/local_manifests/roomservice.xml

添加内容如下

  <!-- 添加必要的供应商特定 vendor 文件 Android 12.1 -->
  <project name="TheMuppets/proprietary_vendor_oneplus" path="vendor/oneplus" remote="github"  revision="lineage-19.1" />

第二种方案 不用尝试了,因为 lineage 官方没有 lineage-19.1固件了
其实可以刷 crdroid v8.x android 12
就是想将 OP7P 刷机成任何一个 android 12 系统从中提取专有 vendor 文件
这里假设手机已经刷机搭载了 crdroid v8.x android 12 系统,并连接了电脑
提取出来的专有文件用于 lineage-19.1 源码编译使用

# 手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
# 进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试,启用 Rooted debugging 模式,连接电脑  
# 手机提示是否允许,就允许
# 先杀死 adb 服务
adb kill-server
# 允许授权
adb devices
# 确认 device tree 里有 extract 脚本
ls device/oneplus/guacamole/

应该能看到类似(如果 没有,那这个 device tree 是不完整的):

extract-files.sh
extract-files.py
proprietary-files.txt
setup-makefiles.sh
setup-makefiles.py
# 验证设备 root 看到 `uid=0(root)` 才算 OK。
adb root
adb shell id
# 开始提取(关键步骤)
# 重新初始化环境
source build/envsetup.sh
# 必须先 lunch / breakfast 一次
breakfast guacamole
pushd device/oneplus/guacamole 2>/dev/null
# 执行脚本等待 crdroid v8.x android 12 提取完成
# 执行提取脚本,如果没有继续往下看
./extract-files.sh
./setup-makefiles.sh
# 如果没有 sh 脚本就执行 py 脚本
./extract-files.py
./setup-makefiles.py
popd

提取成功后应该能看到以下内容

vendor/oneplus/guacamole/
├── Android.bp
├── Android.mk
├── BoardConfigVendor.mk
├── guacamole-vendor.mk
├── proprietary
├── radio
└── ...

第三种方案 这个方案我没试过,我执行方案一之后就没有报错了
这个是我臆想出来的方案
需要从已有的刷机正常的固件包提取专有文件,由于lineage-19.1官方没有固件了

mkdir -pv /root/workspace/ota
pushd /root/workspace/ota 2>/dev/null
# crdroid 8.x Android 12 镜像,刷入没问题,可以提取出来专有文件构建 Android 自身
rm -fv Android.zip
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o 'Android.zip' \
     'https://master.dl.sourceforge.net/project/crdroid/guacamole/8.x/crDroidAndroid-12.1-20221219-guacamole-v8.12.zip?viasf=1'

# 解压
unzip -o Android.zip

# 清理除 payload.bin 以外的文件
find . -mindepth 1 ! -name 'payload.bin' -exec rm -rf {} +

# clone 官方解包工具
git clone https://github.com/LineageOS/android_prebuilts_extract-tools \
          /root/workspace/ota/extract-tools

# 解压镜像
extract-tools/linux-x86/bin/ota_extractor \
    --payload payload.bin 

# 删除解压文件节省空间
rm -frv payload.bin extract-tools

# 如果 docker loop 设备不够用则可以创建loop设备并绑定镜像然后挂载
# 如果这一步失败,后面也有其他办法
mknod /dev/loop96 b 7 96
mknod /dev/loop97 b 7 97
#mknod /dev/loop98 b 7 98
#mknod /dev/loop99 b 7 99
#mknod /dev/loop100 b 7 100

# 绑定镜像到 loop 设备
losetup /dev/loop96 system.img
losetup /dev/loop97 vendor.img
#losetup /dev/loop98 odm.img
#losetup /dev/loop99 product.img
#losetup /dev/loop100 system_ext.img

# 执行挂载
mkdir -pv system
mount -o ro system.img system/
mount -o ro vendor.img system/vendor/
#mount -o ro odm.img system/odm/
#mount -o ro product.img system/product/
#mount -o ro system_ext.img system/system_ext/

mkdir -pv dump
rsync -a system/ dump/

# 用完之后解除挂载
umount -R system

# 释放 loop 设备
losetup -d /dev/loop96
losetup -d /dev/loop97
#losetup -d /dev/loop98
#losetup -d /dev/loop99
#losetup -d /dev/loop100

rm -fr system
mv -fv dump system

# 修补软链接
IFS_BAK=$IFS
IFS=$'\n'
cd system
echo "正在修补软链接 in: $PWD"
find . -maxdepth 1 -type l | while read -r link; do
    target=$(readlink "$link")
    # 只处理以 '/' 开头的链接
    if [[ "$target" == /* ]]; then
        relative_target="${target#/}"  # 去掉开头的 /
        echo "删除原链接: $link -> $target"
        rm -f "$link"
        echo "创建新链接: $link$relative_target"
        ln -sfv "$relative_target" "$link"
    fi
done

cd odm
echo "正在修补软链接 in: $PWD"
find . -maxdepth 1 -type l | while read -r link; do
    target=$(readlink "$link")
    # 只处理以 '/' 开头的链接
    if [[ "$target" == /* ]]; then
        relative_target="${target#/}"  # 去掉开头的 /
        echo "删除原链接: $link -> $target"
        rm -f "$link"
        echo "创建新链接: $link$relative_target"
        ln -sfv ../"$relative_target" "$link"
    fi
done
IFS=$IFS_BAK

# 回到 android 源码
popd

# 开始提取(关键步骤)
# 重新初始化环境
source build/envsetup.sh
# 必须先 lunch / breakfast 一次
breakfast guacamole
pushd device/oneplus/guacamole 2>/dev/null

# 如果以下命令没有则继续往下看
./extract-files.sh /root/workspace/ota/system
./setup-makefiles.sh
# 如果没有以上命令则尝试以下命令
./extract-files.py /root/workspace/ota/system
./setup-makefiles.py

# 回到 android 源码
popd

完成以上可行方案就可以继续以下步骤了

# 然后继续同步未完成的部分,而不会重新下载已经同步的内容。
find .repo -name "index.lock" -exec rm -f {} \;
repo sync -c --optimized-fetch --prune --force-sync

# 然后再次尝试下载特定设备的内核 和 配置
breakfast guacamole

# 编译镜像 croot brunch guacamole
croot

# 联合编译内核生成镜像
brunch guacamole

# 查看得到 img 镜像
echo $OUT
ls -al $OUT/*.img $OUT/*.zip $OUT/*.md5sum $OUT/*.sha256sum

# 这个步骤失败,不要尝试,我只是记录。进入内核目录备份 lineage-19.1 guacamole 的内核源码
#pushd kernel/oneplus/ 2>/dev/null
#mv -fv sm8150 sm8150.bak
# 这个步骤失败,不要尝试,我只是记录。clone 官方 OOS android 12 内核源码,鸠占鹊巢,移花接木,嘿嘿嘿
#git clone 'https://github.com/OnePlusOSS/android_kernel_oneplus_sm8150' -b oneplus/sm8150_s_12.1_op7pro sm8150
# 这个步骤失败,不要尝试,我只是记录。返回源码目录
#popd
# 这个步骤失败,不要尝试,我只是记录。再测试联合编译 官方 OOS android 12 内核源码的 boot.img 是否成功?
#make bootimage -j$(($(nproc)*2))

# 我的手机已经刷了 GM1910_11_H.40 即 android 12 最新版本,也有下载好的原始镜像
# 接下来就是刷入 lineage-19.1 guacamole 的镜像了
# 参考的 https://wiki.lineageos.org/devices/guacamole/install/ https://crdroid.net/guacamole/11/install
# 手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
# 进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试
# 连接电脑,手机提示是否允许,就允许
# 连接电脑 重启到 bootloader 模式
adb -d reboot bootloader
fastboot devices

# 单独刷入 vbmeta.img 时禁用 AVB/dm-verity ,可能会对挂载可读写系统有帮助
fastboot --disable-verity --disable-verification flash dtbo $OUT/dtbo.img
# 没有 vbmeta.img 生成
#fastboot --disable-verity --disable-verification flash vbmeta $OUT/vbmeta.img
fastboot flash --slot=all boot $OUT/boot.img

# 恢复出厂设置,备份好资料。要么别执行,别问我怎么知道,呜呜
#fastboot -w

# 然后 fastboot 模式界面音量键选择重启进入 recovery 恢复模式
# 恢复模式点击 apply update -> Apply from ADB
# 连接电脑,使用 adb sideload 将 lineage-19.1 guacamole 系统固件刷入
adb -d sideload $OUT/lineage-19.1-*-UNOFFICIAL-guacamole.zip
# 恢复模式点击返回 Advanced -> Reboot to recovery 重启进入 recovery 恢复模式完成 boot 分区切换
# 恢复模式点击 apply update -> Apply from ADB
# 连接电脑,再次使用 adb sideload 将 lineage-19.1 guacamole 系统固件刷入另一个 boot 分区
adb -d sideload $OUT/lineage-19.1-*-UNOFFICIAL-guacamole.zip


刷机完成在恢复模式界面操作点击返回并点击 Reboot system now,等待重启需要有耐心
重启看效果
如果启动卡住很久就重新进入恢复模式清除 Factory reset -> Format data/factory reset -> Format data(清除用户数据恢复出厂设置)后继续尝试重启
设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 android debugging 模式,连接电脑
手机提示是否允许,就允许
将 lineage-19.1 guacamole boot.img 传入到手机目录 /sdcard/

adb push $OUT/boot.img /sdcard/
adb shell ls -al /sdcard/

安装 magisk.apk 和 termux.apk

mkdir -pv /root/workspace/apks
# magisk.apk
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o '/root/workspace/apks/Magisk-v28.1.apk' \
     'https://github.com/topjohnwu/Magisk/releases/download/v28.1/Magisk-v28.1.apk'
adb install '/root/workspace/apks/Magisk-v28.1.apk'
# termux.apk
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o '/root/workspace/apks/termux-app_v0.118.3+github-debug_arm64-v8a.apk' \
     'https://github.com/termux/termux-app/releases/download/v0.118.3/termux-app_v0.118.3+github-debug_arm64-v8a.apk'
adb install '/root/workspace/apks/termux-app_v0.118.3+github-debug_arm64-v8a.apk'

打开 magisk app 修改 boot.img 得到 /sdcard/Download/magisk_patched-28100_BivXZ.img
重命名 magisk_patched-28100_BivXZ.img 为 boot_magisk_patched.img (我重命名了,生成的名字结尾是随机的,我觉得不好记)

adb shell "mv -fv /sdcard/Download/magisk_patched-*.img /sdcard/boot_magisk_patched.img"

检查文件是否命名成功

adb shell ls -al /sdcard/Download/ /sdcard/ 

将 boot_magisk_patched.img 文件导出到 $OUT/ 目录

adb pull /sdcard/boot_magisk_patched.img $OUT/

然后重启到 fastboot 模式,连接电脑,通过 fastboot 命令刷入 boot_magisk_patched.img

adb -d reboot bootloader
fastboot flash --slot=all boot $OUT/boot_magisk_patched.img

重启系统,再重启打开 magisk 测试 root 授权

fastboot reboot


打开 Termux app 测试 root 授权,运行脚本查看固件内核缺失哪些 docker 支持

# 更新源
pkg update
# 升级包
pkg up
# 安装依赖工具包
pkg i curl root-repo tsu

# 授权并查看编译的固件信息,会提示需要 root 直接授权 GRANT
su - root sh -c 'cat /proc/version'

固件信息如下

Linux version 4.14.180-perf+ (nobody@android-build) (Android (7485623, based on r416183b1) clang version 12.0.7 (https://android.googlesource.com/toolchain/llvm-project c935d99d7cf2016289302412d708641d52d2f7ee), GNU ld (binutils-2.27-bd24d23f) 2.27.0.20170315) #1 SMP PREEMPT Mon 28 059070:32 21T 2025

查看当前系统docker支持缺失信息,当前缺少 Docker 运行所需的关键功能
这些选项 必须启用 才能让 Docker 正常运行 容器化进程

curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o check-config.sh 'https://github.com/moby/moby/raw/refs/heads/master/contrib/check-config.sh'
chmod -v a+x check-config.sh
sed -i '1s_.*_#!/data/data/com.termux/files/usr/bin/bash_' check-config.sh
su - root sh -c './check-config.sh'

docker 缺失如下

info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: cgroupv2
  Controllers:
  - cpu: missing
  - cpuset: missing
  - io: missing
  - memory: missing
  - pids: missing
- CONFIG_PID_NS: missing
- CONFIG_IPC_NS: missing
- CONFIG_CGROUP_DEVICE: missing
- CONFIG_IP6_NF_TARGET_MASQUERADE: missing
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: missing
- CONFIG_NETFILTER_XT_MATCH_IPVS: missing
- CONFIG_IP6_NF_NAT: missing
- CONFIG_POSIX_MQUEUE: missing

Optional Features:
- CONFIG_USER_NS: missing
- CONFIG_CGROUP_PIDS: missing
- CONFIG_BLK_DEV_THROTTLING: missing
- CONFIG_CGROUP_PERF: missing
- CONFIG_CGROUP_HUGETLB: missing
- CONFIG_NET_CLS_CGROUP: missing
- CONFIG_CGROUP_NET_PRIO: missing
- CONFIG_CFS_BANDWIDTH: missing
- CONFIG_IP_VS: missing
- CONFIG_IP_VS_NFCT: missing
- CONFIG_IP_VS_PROTO_TCP: missing
- CONFIG_IP_VS_PROTO_UDP: missing
- CONFIG_IP_VS_RR: missing
- CONFIG_SECURITY_APPARMOR: missing
- Network Drivers:
  - "overlay":
    - CONFIG_VXLAN: missing
    - CONFIG_BRIDGE_VLAN_FILTERING: missing
  - "ipvlan":
    - CONFIG_IPVLAN: missing
  - "macvlan":
    - CONFIG_MACVLAN: missing
- Storage Drivers:
  - "btrfs":
    - CONFIG_BTRFS_FS: missing
    - CONFIG_BTRFS_FS_POSIX_ACL: missing
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000


容器内回到源码路径启用参数编译内核

cd /root/workspace/android-build/lineage-19.1

# 获取当时整体编译固件时所用的 kernel 配置文件名
grep -r "defconfig" device

获取到信息如下

device/oneplus/sm8150-common/BoardConfigCommon.mk:TARGET_KERNEL_CONFIG := vendor/sm8150-perf_defconfig

进入内核路径,根据上述信息,查找内核配置文件路径

pushd kernel/oneplus/sm8150 2>/dev/null
find . -iname 'sm8150-perf_defconfig'

获取到信息如下

./arch/arm64/configs/vendor/sm8150-perf_defconfig

备份内核配置文件,防止改错无法恢复

cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig arch/arm64/configs/vendor/sm8150-perf_defconfig.bak

# 复制内核配置文件到当前目录
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig.bak .config

# 微调内核配置,输入 / 进入搜索 missing 项,会找到详细位置,是有规律的,找完就关闭
# 请不要做任何操作,仅仅用做找位置参考
# 因为这是 x86_64 架构平台,会不会污染 arm64 架构的配置?非我族类其心必异啊。。。这句话用的对吗?
# 如果你和我一样都是 oneplus 7 pro guacamole OOS10.0.0 Android 12 系统
# 并且成功刷入自编译的 lineage-19.1 那你为什么还要折腾一遍呢?可以跳过这个步骤,往后看看,直接执行我的命令不好吗?
make menuconfig

尝试找到以下内核具体位置,不要勾选,后面总结了命令可以一键开启

info: reading kernel config from /proc/config.gz ...

Generally Necessary:
- cgroup hierarchy: cgroupv2
  Controllers:
  - cpu: missing
  - cpuset: missing
    - CONFIG_CPUSETS [=y]
      - Depends on: CGROUPS [=y] && SMP [=y]
        -> General setup
          -> Control Group support (CGROUPS [=y])
            -> Cpuset controller
  - io: missing
  - memory: missing
  - pids: missing

- CONFIG_PID_NS [=y]
  - Depends on: NAMESPACES [=y]
    -> General setup
      -> Namespaces support (NAMESPACES [=y])
        -> PID Namespaces

- CONFIG_SYSVIPC [=y]
    -> General setup
      -> System V IPC

- CONFIG_IPC_NS [=y]
  - Depends on: NAMESPACES [=y] && (SYSVIPC [=y] || POSIX_MQUEUE [=y])
    -> General setup
      -> Namespaces support (NAMESPACES [=y])
        -> IPC namespace

- CONFIG_CGROUP_DEVICE [=y]
  - Depends on: CGROUPS [=y]
    -> General setup
      -> Control Group support (CGROUPS [=y])
        -> Device controller

- CONFIG_IP6_NF_NAT [=y]
  - Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && NF_CONNTRACK_IPV6 [=y] && NETFILTER_ADVANCED [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IPv6: Netfilter Configuration
            -> IP6 tables support (required for filtering) (IP6_NF_IPTABLES [=y])
              -> ip6tables NAT support

- CONFIG_IP6_NF_TARGET_MASQUERADE [=y]
  - Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && IP6_NF_NAT [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IPv6: Netfilter Configuration
            -> IP6 tables support (required for filtering) (IP6_NF_IPTABLES [=y])
              -> ip6tables NAT support (IP6_NF_NAT [=y])
                -> MASQUERADE target support

- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE [=y]
  - Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> Core Netfilter Configuration
            -> Netfilter Xtables support (required for ip_tables) (NETFILTER_XTABLES [=y])
              -> "addrtype" address type match support

- CONFIG_IP_VS [=y]
  - Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n)
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IP virtual server support

- CONFIG_NETFILTER_XT_MATCH_IPVS [=y]
  - Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=y] && IP_VS [=y] && NETFILTER_ADVANCED [=y] && NF_CONNTRACK [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> Core Netfilter Configuration
            -> Netfilter Xtables support (required for ip_tables) (NETFILTER_XTABLES [=y])
              -> "ipvs" match support

- CONFIG_IP6_NF_NAT [=y]
  - Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && NF_CONNTRACK_IPV6 [=y] && NETFILTER_ADVANCED [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IPv6: Netfilter Configuration
            -> IP6 tables support (required for filtering) (IP6_NF_IPTABLES [=y])
              -> ip6tables NAT support

- CONFIG_POSIX_MQUEUE [=y]
  - Depends on: NET [=y]
    -> General setup
      -> POSIX Message Queues

Optional Features:
- CONFIG_USER_NS [=y]
  - Depends on: NAMESPACES [=y]
    -> General setup
      -> Namespaces support (NAMESPACES [=y])
        -> User namespace

- CONFIG_CGROUP_PIDS [=y]
  - Depends on: CGROUPS [=y]
    -> General setup
      -> Control Group support (CGROUPS [=y])
        -> PIDs controller

- CONFIG_BLK_DEV_THROTTLING [=y]
  - Depends on: BLOCK [=y] && BLK_CGROUP [=y]
    -> Enable the block layer (BLOCK [=y])
      -> Block layer bio throttling support

- CONFIG_BLK_DEV_THROTTLING_LOW [=y]
  - Depends on: BLOCK [=y] && BLK_DEV_THROTTLING [=y]
    -> Enable the block layer (BLOCK [=y])
      -> Block layer bio throttling support (BLK_DEV_THROTTLING [=y])
        -> Block throttling .low limit interface support (EXPERIMENTAL)

- CONFIG_CGROUP_PERF [=y]
  - Depends on: CGROUPS [=y] && PERF_EVENTS [=y] 
    -> General setup
      -> Control Group support (CGROUPS [=y])
        -> Perf controller

- CONFIG_HUGETLB_PAGE [=y]

- CONFIG_HUGETLBFS [=y]
  - Depends on: X86 [=y] || IA64 || SPARC64 || S390 && 64BIT [=y] || SYS_SUPPORTS_HUGETLBFS || BROKEN [=n]
    -> File systems
      -> Pseudo filesystems
        -> HugeTLB file system support

- CONFIG_CGROUP_HUGETLB [=y]
  - Depends on: CGROUPS [=y] && HUGETLB_PAGE [=y]
    -> General setup
      -> Control Group support (CGROUPS [=y])
        -> HugeTLB controller

- CONFIG_NET_CLS_CGROUP [=y]
  - Depends on: NET [=y] && NET_SCHED [=y] && CGROUPS [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> QoS and/or fair queueing (NET_SCHED [=y])
          -> Control Group Classifier

- CONFIG_CGROUP_NET_PRIO [=y]
  - Depends on: NET [=y] && CGROUPS [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network priority cgroup

- CONFIG_SMP [=y]
  -> Processor type and features
    -> Symmetric multi-processing support

- CONFIG_SCHED_WALT [=n]
  - Depends on: SMP [=y]
    -> General setup
      -> CPU/Task time and stats accounting
        -> Support window based load tracking

- CONFIG_CFS_BANDWIDTH [=y]
  - Depends on: CGROUPS [=y] && CGROUP_SCHED [=y] && FAIR_GROUP_SCHED [=y] && !SCHED_WALT [=n]
    -> General setup
      -> Control Group support (CGROUPS [=y])
        -> CPU controller (CGROUP_SCHED [=y])
          -> Group scheduling for SCHED_OTHER (FAIR_GROUP_SCHED [=y])
            -> CPU bandwidth provisioning for FAIR_GROUP_SCHED

- CONFIG_IP_VS [=y]
  - Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n)
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IP virtual server support

- CONFIG_IP_VS_NFCT [=y]
  - Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y] && NF_CONNTRACK [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IP virtual server support (IP_VS [=y])
            -> Netfilter connection tracking

- CONFIG_IP_VS_PROTO_TCP [=y]
  - Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IP virtual server support (IP_VS [=y])
            -> TCP load balancing support

- CONFIG_IP_VS_PROTO_UDP [=y]
  - Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IP virtual server support (IP_VS [=y])
            -> UDP load balancing support

- CONFIG_IP_VS_RR [=y]
  - Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y]
    -> Networking support (NET [=y])
      -> Networking options
        -> Network packet filtering framework (Netfilter) (NETFILTER [=y])
          -> IP virtual server support (IP_VS [=y])
            -> round-robin scheduling

- CONFIG_SECURITY_APPARMOR [=y]
  - Depends on: SECURITY [=y] && NET [=y]
    -> Security options
      -> AppArmor support

- Network Drivers:
  - "overlay":
    - CONFIG_VXLAN [=y]
      - Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y]
        -> Device Drivers
          -> Network device support (NETDEVICES [=y])
            -> Network core driver support (NET_CORE [=y])
              -> Virtual eXtensible Local Area Network (VXLAN)

    - CONFIG_VLAN_8021Q [=y]  
      - Depends on: NET [=y]
        -> Networking support (NET [=y])
          -> Networking options
            -> 802.1Q/802.1ad VLAN Support

    - CONFIG_BRIDGE_VLAN_FILTERING [=y]
      - Depends on: NET [=y] && BRIDGE [=y] && VLAN_8021Q [=y]
        -> Networking support (NET [=y])
          -> Networking options
            -> 802.1d Ethernet Bridging (BRIDGE [=y])
              -> VLAN filtering

  - "ipvlan":
    - CONFIG_NET_L3_MASTER_DEV [=y]
      - Depends on: NET [=y] && (INET [=y] || IPV6 [=y])
        -> Networking support (NET [=y])
          -> Networking options
            -> L3 Master device support

    - CONFIG_IPVLAN [=y]
      - Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NET_L3_MASTER_DEV [=y]
        -> Device Drivers
          -> Network device support (NETDEVICES [=y])
            -> Network core driver support (NET_CORE [=y])
              -> IP-VLAN support

  - "macvlan":
    - CONFIG_MACVLAN [=y]
      - Depends on: NETDEVICES [=y] && NET_CORE [=y]
        -> Device Drivers
          -> Network device support (NETDEVICES [=y])
            -> Network core driver support (NET_CORE [=y])
              -> MAC-VLAN support

- Storage Drivers:
  - "btrfs":
    - CONFIG_BTRFS_FS [=y]
      - Depends on: BLOCK [=y]
        -> File systems
          -> Btrfs filesystem support

    - CONFIG_BTRFS_FS_POSIX_ACL [=y]
      - Depends on: BLOCK [=y] && BTRFS_FS [=y]
        -> File systems
          -> Btrfs filesystem support (BTRFS_FS [=y])
            -> Btrfs POSIX Access Control Lists

  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000

总结命令

# 防止污染,重新覆盖
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig.bak .config

# 开启功能项
# android 12 启用这些没啥问题
# android 15 启用这些会让 wifi 失效

scripts/config --enable CONFIG_CPUSETS
scripts/config --enable CONFIG_PID_NS
scripts/config --enable CONFIG_SYSVIPC
scripts/config --enable CONFIG_IPC_NS
scripts/config --enable CONFIG_CGROUP_DEVICE
scripts/config --enable CONFIG_IP6_NF_NAT
scripts/config --enable CONFIG_IP6_NF_TARGET_MASQUERADE
scripts/config --enable CONFIG_NETFILTER_XT_MATCH_ADDRTYPE
scripts/config --enable CONFIG_IP_VS
scripts/config --enable CONFIG_NETFILTER_XT_MATCH_IPVS
scripts/config --enable CONFIG_POSIX_MQUEUE
scripts/config --enable CONFIG_USER_NS
scripts/config --enable CONFIG_CGROUP_PIDS
scripts/config --enable CONFIG_BLK_DEV_THROTTLING
scripts/config --enable CONFIG_BLK_DEV_THROTTLING_LOW
scripts/config --enable CONFIG_CGROUP_PERF
scripts/config --enable CONFIG_HUGETLB_PAGE
scripts/config --enable CONFIG_HUGETLBFS
scripts/config --enable CONFIG_CGROUP_HUGETLB
scripts/config --enable CONFIG_NET_CLS_CGROUP
scripts/config --enable CONFIG_CGROUP_NET_PRIO
scripts/config --enable CONFIG_SMP
# CONFIG_SCHED_WALT 和 CONFIG_CFS_BANDWIDTH 互为冲突
# CONFIG_SCHED_WALT  WALT 调度(Window Assisted Load Tracking,Pixel/Qualcomm 特有的调度器),默认启用就会屏蔽掉 CONFIG_CFS_BANDWIDTH。
# 很显然我不无法启用 CONFIG_CFS_BANDWIDTH 启用就意味着不断的修内核代码,成本太高了
scripts/config --enable CONFIG_SCHED_WALT
scripts/config --disable CONFIG_CFS_BANDWIDTH
scripts/config --enable CONFIG_IP_VS_NFCT
scripts/config --enable CONFIG_IP_VS_PROTO_TCP
scripts/config --enable CONFIG_IP_VS_PROTO_UDP
scripts/config --enable CONFIG_IP_VS_RR
scripts/config --enable CONFIG_SECURITY_APPARMOR
scripts/config --enable CONFIG_VXLAN
scripts/config --enable CONFIG_VLAN_8021Q
scripts/config --enable CONFIG_BRIDGE_VLAN_FILTERING
scripts/config --enable CONFIG_NET_L3_MASTER_DEV
scripts/config --enable CONFIG_IPVLAN
scripts/config --enable CONFIG_MACVLAN
scripts/config --enable CONFIG_BTRFS_FS
scripts/config --enable CONFIG_BTRFS_FS_POSIX_ACL

# 最后检查一遍
EXP_INFO='
CONFIG_CPUSETS=
CONFIG_PID_NS=
CONFIG_SYSVIPC=
CONFIG_IPC_NS=
CONFIG_CGROUP_DEVICE=
CONFIG_IP6_NF_NAT=
CONFIG_IP6_NF_TARGET_MASQUERADE=
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=
CONFIG_IP_VS=
CONFIG_NETFILTER_XT_MATCH_IPVS=
CONFIG_POSIX_MQUEUE=
CONFIG_USER_NS=
CONFIG_CGROUP_PIDS=
CONFIG_BLK_DEV_THROTTLING=
CONFIG_BLK_DEV_THROTTLING_LOW=
CONFIG_CGROUP_PERF=
CONFIG_HUGETLB_PAGE=
CONFIG_HUGETLBFS=
CONFIG_CGROUP_HUGETLB=
CONFIG_NET_CLS_CGROUP=
CONFIG_CGROUP_NET_PRIO=
CONFIG_SMP=
CONFIG_SCHED_WALT=
CONFIG_CFS_BANDWIDTH=
CONFIG_IP_VS_NFCT=
CONFIG_IP_VS_PROTO_TCP=
CONFIG_IP_VS_PROTO_UDP=
CONFIG_IP_VS_RR=
CONFIG_SECURITY_APPARMOR=
CONFIG_VXLAN=
CONFIG_VLAN_8021Q=
CONFIG_BRIDGE_VLAN_FILTERING=
CONFIG_NET_L3_MASTER_DEV=
CONFIG_IPVLAN=
CONFIG_MACVLAN=
CONFIG_BTRFS_FS=
CONFIG_BTRFS_FS_POSIX_ACL=
'

for config in $EXP_INFO; do
    grep -Ei "$config" .config || echo "$config 未找到"
done

# 解除环境,用不上了
unset EXP_INFO

然后再给它放回去

# 执行会报错,唉
cp -fv .config arch/arm64/configs/vendor/sm8150-perf_defconfig
make clean
rm -fv .config .config.old

备份原始 boot.img 文件

# 回到源码目录
popd
# 备份 boot.img 方便还原
mv -fv $OUT/boot.img $OUT/boot.img.bak

将编译内核的工作交给 lineage-19.1 联合编译工具,省心

# 清理 kernel obj 目录,避免历史构建污染
rm -fr $OUT/obj/KERNEL_OBJ
# 生成支持 docker 的 boot.img
make bootimage -j$(($(nproc)*2))
# 构建成功后进入目录,你就能看到 boot.img docker支持版文件
echo $OUT
ls -al $OUT/*.img
# 更改 boot.img 为 boot-docker-1.img 方便区分
mv -fv $OUT/boot.img $OUT/boot-docker-1.img

通过 magisk app 修改 boot-docker-1.img

# 将 $OUT 的 boot-docker-1.img 传入手机 /sdcard/
adb push $OUT/boot-docker-1.img /sdcard/
# 通过 magisk app 修改 boot-docker-1.img 得到 /sdcard/Download/magisk_patched-29000_i2Elj.img
adb shell ls -al /sdcard/
# 重命名 magisk_patched-28100_AivWF.img 为 boot-docker-1_magisk_patched.img (我重命名了,生成的名字结尾是随机的,我觉得不好记)
adb shell "mv -fv /sdcard/Download/magisk_patched-*.img /sdcard/boot-docker-1_magisk_patched.img"
# 检查文件是否命名成功
adb shell ls -al /sdcard/Download/ /sdcard/ 
# 将 boot-docker-1_magisk_patched.img 文件导出到 android 镜像存放目录
adb pull /sdcard/boot-docker-1_magisk_patched.img $OUT/

# 然后重启到 fastboot 模式,连接电脑,通过 fastboot 命令刷入 boot-docker-1_magisk_patched.img
adb -d reboot bootloader
fastboot flash --slot=all boot $OUT/boot-docker-1_magisk_patched.img
fastboot reboot

手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 Rooted debugging 模式,连接电脑
手机提示是否允许,就允许
运行 Termux 执行脚本查看固件内核还有哪些缺失 docker 支持功能

su - root sh -c './check-config.sh'

未开启内容如下,其他不会开

info: reading kernel config from /proc/config.gz ...    
Generally Necessary:
- cgroup hierarchy: cgroupv2
  Controllers:
  - cpu: missing
  - cpuset: missing
  - io: missing
  - memory: missing

Optional Features:
- CONFIG_CFS_BANDWIDTH: missing
- Storage Drivers:
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

Limits:
- /proc/sys/kernel/keys/root_maxkeys: 1000000

再次进入内核路径,根据上述信息,查找内核配置文件路径

pushd kernel/oneplus/sm8150 2>/dev/null

# 复制内核配置文件到当前目录
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig .config

# 微调内核配置,输入 / 进入搜索 missing 项,会找到详细位置,是有规律的,找完就关闭
# 仅用于第二次编译 kernel 请不要做任何操作,仅仅用做找位置参考
make menuconfig

尝试找到以下内核具体位置,寻找跨平台兼容相关项位置

# 对杂项二进制文件格式的支持,可以让系统识别并运行非标准格式的可执行文件(例如通过 binfmt_misc 可直接运行脚本或虚拟格式的二进制)。
- CONFIG_BINFMT_MISC [=y]
  -> Executable file formats / Emulations 
    -> Kernel support for MISC binaries
# 不确定需不需要的跨平台兼容项位置
# 为 64 位内核添加对 32 位 (IA-32) 应用的兼容支持,使得旧的 32 位软件可以在 64 位系统上正常运行。
- CONFIG_IA32_EMULATION [=y]
  - Depends on: X86_64 [=y]
    -> Executable file formats / Emulations
      -> IA32 Emulation

再覆盖一遍,万一 make menuconfig 操作不小心污染了 .config 就不好了

rm -frv .config.old
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig .config

启用对杂项二进制文件格式的支持,可以让系统识别并运行非标准格式的可执行文件(例如通过 binfmt_misc 可直接运行脚本或虚拟格式的二进制)。

scripts/config --enable CONFIG_BINFMT_MISC
# 为 64 位内核添加对 32 位 (IA-32) 应用的兼容支持,使得旧的 32 位软件可以在 64 位系统上正常运行。
scripts/config --enable CONFIG_IA32_EMULATION

# 最后检查一遍
EXP_INFO='
CONFIG_BINFMT_MISC=
CONFIG_IA32_EMULATION=
'

for config in $EXP_INFO; do
    grep -Ei "$config" .config || echo "$config 未找到"
done


# 解除环境,用不上了
unset EXP_INFO

# 然后再给它放回去
cp -fv .config arch/arm64/configs/vendor/sm8150-perf_defconfig
make clean
rm -fv .config .config.old
# 回到源码目录
popd

# 将编译内核的工作交给 lineage-19.1 编译工具,省心
# 生成支持 docker 的 boot.img
make bootimage -j$(($(nproc)*2))

# 构建成功后进入目录,你就能看到 boot.img docker支持版文件
echo $OUT
ls -al $OUT/*.img

# 存储 boot.img 到本地为了保证不会覆盖原始 boot-docker.img 你可能需要更名文件为 boot-docker-2.img
mv -fv $OUT/boot.img $OUT/boot-docker-2.img

通过 magisk app 修改 boot-docker-2.img

# 将 $OUT 的 boot-docker-2.img 传入手机 /sdcard/
adb push $OUT/boot-docker-2.img /sdcard/
# 通过 magisk app 修改 boot-docker-2.img 得到 /sdcard/Download/magisk_patched-29000_i2Elj.img
adb shell ls -al /sdcard/
# 重命名 magisk_patched-28100_AivWF.img 为 boot-docker-2_magisk_patched.img (我重命名了,生成的名字结尾是随机的,我觉得不好记)
adb shell "mv -fv /sdcard/Download/magisk_patched-*.img /sdcard/boot-docker-2_magisk_patched.img"
# 检查文件是否命名成功
adb shell ls -al /sdcard/Download/ /sdcard/ 
# 将 boot-docker-2_magisk_patched.img 文件导出到 android 镜像存放目录
adb pull /sdcard/boot-docker-2_magisk_patched.img $OUT/

# 然后重启到 fastboot 模式,连接电脑,通过 fastboot 命令刷入 boot-docker-1_magisk_patched.img
adb -d reboot bootloader
fastboot flash --slot=all boot $OUT/boot-docker-2_magisk_patched.img
fastboot reboot

连接电脑,adb 获取 root 允许系统挂载为可读写
进入系统设置里的开发者模式 system setting - enable in Settings -> System -> Developer options
开启 Root access 或者 Rooted debugging

adb root
adb disable-verity
adb remount
adb shell mount -o remount,rw /


测试运行 termux docker

# 启动 termux app 直接运行 docker
pkg i docker tmux

# 下载 tini-static -> docker-init
ARCH="" ; case $(uname -m) in aarch64) echo arm64;export ARCH=arm64;; x86_64) echo amd64;export ARCH=amd64;; esac
echo 'https://github.com/krallin/tini/releases/latest/download/tini-static-'${ARCH}
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o ${PREFIX}/bin/docker-init 'https://github.com/krallin/tini/releases/latest/download/tini-static-'${ARCH}
chmod -v a+x ${PREFIX}/bin/docker-init

# 挂载 cgroup
sudo mount -t tmpfs -o mode=755 tmpfs /sys/fs/cgroup
sudo mkdir -p /sys/fs/cgroup/devices
sudo mount -t cgroup -o devices cgroup /sys/fs/cgroup/devices
sudo df -h | grep /sys/fs/cgroup

# 挂载 net_cls
sudo mkdir -p /sys/fs/cgroup/net_cls
sudo mount -t cgroup -o net_cls none /sys/fs/cgroup/net_cls
sudo ls -al /sys/fs/cgroup/net_cls

# 挂载跨平台 binfmt_misc 支持
sudo mkdir -p /proc/sys/fs/binfmt_misc
sudo mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
sudo ls -al /proc/sys/fs/binfmt_misc

# 修改 dockerd 配置文件支持 overlay2 创建目录
sed -i "s;${PREFIX}/lib;/data/lib;g" ${PREFIX}/etc/docker/daemon.json

运行 dockerd 服务

# 在 tmux 会话内启动 dockerd 守护进程并不去修改或管理主机的 iptables 规则
# --exec-opt list (最重要)
# 建议: native.cgroupdriver=cgroupfs
# 用途: 设置运行时执行选项。核心关键参数(解决报错与启动问题)
# 如果有 Device or resource busy 错误是因为 Android 系统已经挂载了 cgroup,或者挂载方式与 Docker 预期的不一致。
# 
# --dns list (解决解析慢/失败)
# 建议: dockerd --dns 8.8.8.8 --dns 1.1.1.1
# 用途: Termux 环境下的 /etc/resolv.conf 往往指向 Android 内部的 DNS 代理(如 127.0.0.1),容器内部无法直接使用。
# 强制指定公共 DNS 可以解决容器内 curl 无法解析域名的问题。
# 
# --mtu int (解决包丢失/卡顿)
# 建议: dockerd --mtu 1350 (或其他较小值)
# 用途: 某些移动网络或 VPN 环境下,标准 MTU 1500 会导致大数据包被丢弃(表现为 ping 得通但网页打不开)。降低 MTU 可以提高通过性。
# 
# --data-root string
# 默认值: /data/data/com.termux/files/usr/var/lib/docker
# 用途: 如果手机内部存储空间不足,想把 Docker 镜像存到 SD 卡或者挂载的硬盘上,可以用这个参数修改路径。
# 存储与路径参数(根据设备情况调整,目前已经通过以上步骤修改为 $PREFIX/var/lib/docker 了)
# 注意: 目标路径的文件系统必须支持 overlay2 (如 ext4/f2fs),不要指向 FAT32/exFAT 格式的 SD 卡分区。
# 
# --config-file string
# 默认值: /data/data/com.termux/files/usr/etc/docker/daemon.json
# 用途: 推荐使用这个文件来管理配置,而不是每次都在命令行敲一长串参数。(目前已经通过以上步骤修改为 $PREFIX/etc/docker/daemon.json 了)
# 
# --http-proxy string
# --https-proxy string
# --no-proxy string
# 用途: 代理与连接参数(科学上网环境)直接让 Docker 守护进程走代理去拉取镜像。
# 如果你需要拉取 Docker Hub 的镜像(通常被墙),可以使用这些
# 注意: 这里的代理地址通常要是局域网 IP(如 192.168.x.x),填 127.0.0.1 在容器启动阶段可能会有问题。
# 
# --dns 8.8.8.8 --dns 1.1.1.1
# 用途: 强行指定容器 DNS。
# 彻底解决容器内 curl 无法解析域名、apt update 报错的问题。不再依赖 Android 本地那个不稳定的 DNS 代理。
# 
# --mtu 1350
# 用途: 调小数据包大小。
# 解决了“能 ping 通但网页打不开/卡死”的问题。特别是在移动网络或经过层层 NAT 的 WiFi 下,这个设置能显著提高传输成功率。
# 
# --exec-opt native.cgroupdriver=cgroupfs
# 用途: 强制使用文件系统管理资源。
# 解决了启动时的 mount busy 报错,让 Docker 适配没有 systemd 的 Termux 环境。
# 
# --iptables=true (关键稳定项)
# 用途: 允许 Docker 插入 Android 的防火墙规则。
# 解决了“网络端口映射”的问题。
# 注意: Android 的网络管理非常霸道,Docker 自动写入的规则经常会被 Android 系统覆盖或冲突,可能会导致docker容器内网断流。
# 有一个解决方案: 
# 配置网络网关
# 如果是切换网络或者网络设备,就不一定固定的网关或wlan0了,唯有这个需要手动修改配置
# 比如换成了sim流量则需要 ifconfig 查看流量设备比如 rmnet_data0
# 并通过 su 模式下获取网关 ip route show table 0 | grep default | awk '{print $3}' 比如 192.168.255.253
# 则有 ip route replace default via 192.168.255.253 dev rmnet_data0
# 
# 强制所有流量去查找 main 路由表(解决 Android 策略路由导致的断网)
# 这非常重要,建议每隔一段时间重新运行确保它存在
# 检查路由规则锁定路由表
# ip rule del from all lookup main pref 30000 2>/dev/null
# ip rule add from all lookup main pref 30000
# 
# 手动补齐 NAT 规则
# 即使设置了 iptables=true,如果断网了,手动运行这行通常能“接通”
# 尝试删除旧规则(防止堆叠),然后插入新规则
# iptables -t nat -D POSTROUTING -s 172.17.0.0/16 -j MASQUERADE 2>/dev/null
# iptables -t nat -I POSTROUTING -s 172.17.0.0/16 -j MASQUERADE
# 
# 如果配置为 false 也行
# --iptables=false (关键稳定项)
# 用途: 禁止 Docker 去乱动 Android 的防火墙规则。
# 解决了“网络不稳定”的核心问题。Android 的网络管理非常霸道,Docker 自动写入的规则经常会被 Android 系统覆盖或冲突,导致断流。关掉它,让大家互不干扰。
# 注意: 唯一的副作用(必读)
# 因为设置了 --iptables=false,Docker 不再自动配置 NAT 转发规则。这意味着: 
# 默认的 Bridge 模式容器(即直接 docker run 出来的容器)可能无法上网!
# 有两个解决方案: 
# 
# 方案 A: 
# 总是使用 Host 模式,但是需要考虑端口占用问题,由于没有端口映射,同样端口的容器无法同时运行
# 这是在 Android 上最稳的方案。以后运行任何容器,都尽量加上 --net=host。
# Docker CLI: docker run --net=host ...
# Docker Compose: network_mode: "host"
# 
# 方案 B: 手动补一条 NAT 规则(如果你必须用 Bridge 模式),但是好像没什么效果
# 如果你有些容器必须用 Bridge 模式(比如为了端口映射),你需要手动帮 Docker 开启上网通道。
# 可以在自定义 dockerd 启动命令之前,加一行 iptables 规则: 
# 手动开启 NAT,让 docker0 网桥 (172.17.0.0/16) 的流量可以通过 wlan0 上网
# 注意: 如果你切换到移动数据,可能需要把 wlan0 改成 rmnet_data0
# #iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -o wlan0 -j MASQUERADE
# iptables -t nat -A POSTROUTING -s 172.17.0.0/16 -j MASQUERADE

# 综上所述我打算选择 --iptables=true 参数方式启动命令
# 比如换成了wifi网则需要 ifconfig 查看流量设备比如 wlan0
# 并通过 su 模式下获取网关 ip route show table 0 | grep default | awk '{print $3}' 比如 192.168.255.253
# 则有如下命令
ip route replace default via 192.168.255.253 dev wlan0

# 强制所有流量去查找 main 路由表(解决 Android 策略路由导致的断网)
# 这非常重要,建议每隔一段时间重新运行确保它存在
# 检查路由规则锁定路由表
ip rule del from all lookup main pref 30000 2>/dev/null
ip rule add from all lookup main pref 30000

# --iptables=true 参数方式启动命令
nohup dockerd \
  --iptables=true \
  --mtu 1300 \
  --dns 8.8.8.8 --dns 223.5.5.5 \
  --exec-opt native.cgroupdriver=cgroupfs \
  > $PREFIX/tmp/dockerd.log 2>&1 &

或者你也可以编辑配置文件后配置代理然后再运行 dockerd 服务

nano $PREFIX/etc/docker/daemon.json

添加内容如下,根据你本地的网络环境举一反三的修改代理配置好吗?

{
    "proxies": {
        "http-proxy": "http://192.168.255.253:40000",
        "https-proxy": "http://192.168.255.253:40000",
        "no-proxy": "127.0.0.1,localhost"
    },
    ... 其他配置 ...
}

开启 dockerd 守护进程使用代理(和以上功能重复,二选一,可选)

# 当前终端代理,可以用于 docker pull build push 操作
export http_proxy='http://192.168.255.253:40000' \
https_proxy='http://192.168.255.253:40000' \
no_proxy='localhost,127.0.0.1,192.168.255.0/24'
nohup dockerd \
  --http-proxy "${http_proxy}" \
  --https-proxy "${https_proxy}" \
  --no-proxy "${no_proxy}" \
  --iptables=true \
  --mtu 1300 \
  --dns 8.8.8.8 --dns 223.5.5.5 \
  --exec-opt native.cgroupdriver=cgroupfs \
  > $PREFIX/tmp/dockerd.log 2>&1 &

保持后台运行,以及如何重新返回后台

# 按 Ctrl+B 然后按 D 键退出 tmux 会话(正在运行的进程仍在后台运行)
# 可以使用 tmux attach -t dockerd 重新进入该会话
tmux attach -t dockerd

运行测试容器 运行 hello-world 跨平台测试

# All emulators:
sudo docker run --privileged --rm docker.io/tonistiigi/binfmt:master --install all
# Show currently supported architectures and installed emulators
sudo docker run --privileged --rm docker.io/tonistiigi/binfmt:master

效果如下

{
  "supported": [
    "linux/arm64",
    "linux/amd64",
    "linux/amd64/v2",
    "linux/riscv64",
    "linux/ppc64le",
    "linux/s390x",
    "linux/386",
    "linux/mips64le",
    "linux/mips64",
    "linux/loong64",
    "linux/arm/v7",
    "linux/arm/v6"
  ],
  "emulators": [
    "qemu-i386",
    "qemu-loongarch64",
    "qemu-mips64",
    "qemu-mips64el",
    "qemu-ppc64le",
    "qemu-riscv64",
    "qemu-s390x",
    "qemu-x86_64"
  ]
}
# arm64/v8
sudo docker run --platform linux/arm64/v8 --privileged --rm --name test docker.io/library/hello-world:latest

效果如下

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
# amd64
sudo docker run --platform linux/amd64 --privileged --rm --name test docker.io/library/hello-world:latest

效果如下

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

测试网络 http/https 协议 google.com 还是 baidu.com ?

sudo docker run --platform linux/amd64 --rm --name test docker.io/appropriate/curl:latest curl -I https://www.google.com

效果如下

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0HTTP/1.1 200 OK
Content-Type: text/html; charset=ISO-8859-1
Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-aHs4o--blspAZfFj-iHZLA' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
Accept-CH: Sec-CH-Prefers-Color-Scheme
P3P: CP="This is not a P3P policy! See g.co/p3phelp for more info."
Date: Sat, 28 Jun 2025 12:45:41 GMT
Server: gws
X-XSS-Protection: 0
X-Frame-Options: SAMEORIGIN
Transfer-Encoding: chunked
Expires: Sat, 28 Jun 2025 12:45:41 GMT
Cache-Control: private
Set-Cookie: AEC=AVh_V2iAy5AyTtimMsaWTSwCeM5NPrDsa1948qacpMpKwPIZc7qlTLFMsw; expires=Thu, 25-Dec-2025 12:45:41 GMT; path=/; domain=.google.com; Secure; HttpOnly; SameSite=lax
Set-Cookie: NID=525=QjT6uWvN6hAcwD5kl_xwJEQnO4PBOw1AknMdv0Z3y775HB0ZiYRedul10FL2zlzJAPMB3sgrTVZ4iqk30LRjHSpufq1Gx3j9WOY1MXpK5k12aDsFcQ3QU_tjRobpXforNDg0683g6sxQnxl2CY9CvAevrAhYHmQfe3UBPUZ5fPnsH59MS8uBJf9KbDfP2gDlzBPxuGZztLrFAA; expires=Sun, 28-Dec-2025 12:45:41 GMT; path=/; domain=.google.com; HttpOnly
  0     0    0     0    0     0      0      0 --:--:--  0:00:02 --:--:--     0
Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000

测试网络 icmp 协议 google.com 还是 baidu.com ?

sudo docker run --platform linux/arm64/v8 --rm --name test docker.io/library/busybox:latest ping -c 4 baidu.com

效果如下

PING baidu.com (182.61.201.211): 56 data bytes
64 bytes from 182.61.201.211: seq=0 ttl=48 time=48.950 ms
64 bytes from 182.61.201.211: seq=1 ttl=48 time=44.501 ms
64 bytes from 182.61.201.211: seq=2 ttl=48 time=63.809 ms
64 bytes from 182.61.201.211: seq=3 ttl=48 time=69.941 ms

--- baidu.com ping statistics ---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max = 44.501/56.800/69.941 ms

运行 alpine

# arm64
sudo docker run --platform linux/arm64/v8 --privileged --rm --name test docker.io/library/alpine:latest uname -a

效果如下

Linux 6ff038160e35 4.14.180-perf+ #2 SMP PREEMPT Sat Jun 28 20:27:09 CST 2025 aarch64 Linux
# amd64
sudo docker run --platform linux/amd64 --privileged --rm --name test docker.io/library/alpine:latest uname -a

效果如下

Linux 1a1296964cab 4.14.180-perf+ #2 SMP PREEMPT Sat Jun 28 20:27:09 CST 2025 x86_64 Linux

也可以选择启动容器时使用 --net=host --dns=8.8.8.8 移除容器与 Docker 主机之间的网络隔离,并直接使用主机的网络,可能会不安全?总之随意吧

sudo docker run --privileged --rm --net=host --dns=8.8.8.8 -it ubuntu:latest bash

至此测试完成,这下配套的系统、内核、支持docker的内核弄好了,不怕折腾了
0

其它关于termux的docker-compose和docker-buildx更新

安装用于校验的工具

pkg i jq perl git

compose 部署更新过程如下

# GitHub 项目 URI
URI="docker/compose"

# 获取最新版本 compose
VERSION=$(curl -sL "https://github.com/${URI}/releases" | grep -Eo '/releases/tag/[^"]+' | awk -F'/tag/' '{print $2}' | head -n 1)
echo "Latest version: ${VERSION}"

# 获取操作系统和架构信息
OS=$(uname -s)
ARCH=$(uname -m)

# 映射平台到官方命名
case "${OS}" in
  Linux)
    PLATFORM="linux"
    if [[ "${ARCH}" == "arm64" || "${ARCH}" == "aarch64" ]]; then
      ARCH="aarch64"
    elif [[ "${ARCH}" == "x86_64" ]]; then
      ARCH="x86_64"
    else
      echo "Unsupported architecture: ${ARCH}"
      echo 'should exit 1'
    fi
    ;;
  *)
    echo "Unsupported OS: ${OS}"
    echo 'should exit 1'
    ;;
esac

# 输出最终平台和架构
echo "Platform: ${PLATFORM}"
echo "Architecture: ${ARCH}"

# 拼接下载链接和校验码链接
TARGET_FILE="docker-compose-${PLATFORM}-${ARCH}"
SHA256_FILE="${TARGET_FILE}.sha256"
URI_DOWNLOAD="https://github.com/${URI}/releases/download/${VERSION}/${TARGET_FILE}"
URI_SHA256="https://github.com/${URI}/releases/download/${VERSION}/${SHA256_FILE}"
echo "Download URL: ${URI_DOWNLOAD}"
echo "SHA256 URL: ${URI_SHA256}"

# 检查文件是否存在
if [[ -f "${PREFIX}/tmp/${TARGET_FILE}" ]]; then
  echo "File already exists: ${PREFIX}/tmp/${TARGET_FILE}"
  
  # 删除旧的 SHA256 文件(如果存在)
  if [[ -f "${PREFIX}/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: ${PREFIX}/tmp/${SHA256_FILE}"
    rm -fv "${PREFIX}/tmp/${SHA256_FILE}"
  fi

  # 下载新的 SHA256 文件
  echo "Downloading SHA256 file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "${PREFIX}/tmp/${SHA256_FILE}" "${URI_SHA256}"

  # 校验文件完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for ${PREFIX}/tmp/${TARGET_FILE}..."
  cd ${PREFIX}/tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    log_warning "SHA256 checksum failed. Removing file and retrying..."
    rm -fv "${PREFIX}/tmp/${TARGET_FILE}"
  else
    echo "File integrity verified successfully."
  fi
fi

# 如果文件不存在或之前校验失败
if [[ ! -f "${PREFIX}/tmp/${TARGET_FILE}" ]]; then
  echo "Downloading file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "${PREFIX}/tmp/${TARGET_FILE}" "${URI_DOWNLOAD}"

  # 删除旧的 SHA256 文件并重新下载
  if [[ -f "${PREFIX}/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: ${PREFIX}/tmp/${SHA256_FILE}"
    rm -fv "${PREFIX}/tmp/${SHA256_FILE}"
  fi
  echo "Downloading SHA256 file..."
  curl -L --progress-bar -o "${PREFIX}/tmp/${SHA256_FILE}" "${URI_SHA256}"

  # 校验完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for ${PREFIX}/tmp/${TARGET_FILE}..."
  cd ${PREFIX}/tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    echo "Download failed: SHA256 checksum does not match."
    echo 'should exit 1'
  else
    echo "File integrity verified successfully."
  fi
fi

sudo mv -fv "${PREFIX}/tmp/${TARGET_FILE}" ${PREFIX}/bin/docker-compose
# Apply executable permissions to the binary
## 赋予执行权
sudo chmod -v +x ${PREFIX}/bin/docker-compose
# create a symbolic link to ${PREFIX}/libexec/docker/cli-plugins/
# 创建插件目录和软链接
sudo mkdir -pv ${PREFIX}/libexec/docker/cli-plugins/
sudo ln -sfv ${PREFIX}/bin/docker-compose ${PREFIX}/libexec/docker/cli-plugins/docker-compose
# Test the installation.
## 导入 docker daemon socket 测试版本打印
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock
sudo -E docker-compose version
sudo -E docker compose version

buildx 部署更新过程如下

# GitHub 项目 URI
URI="docker/buildx"

# 获取最新版本
VERSION=$(curl -sL "https://github.com/${URI}/releases" | grep -Eo '/releases/tag/[^"]+' | awk -F'/tag/' '{print $2}' | head -n 1)
echo "Latest version: ${VERSION}"

# 获取操作系统和架构信息
OS=$(uname -s)
ARCH=$(uname -m)

# 映射平台到官方命名
case "${OS}" in
  Linux)
    PLATFORM="linux"
    if [[ "${ARCH}" == "arm64" || "${ARCH}" == "aarch64" ]]; then
      ARCH="arm64"
    elif [[ "${ARCH}" == "x86_64" ]]; then
      ARCH="amd64"
    else
      echo "Unsupported architecture: ${ARCH}"
      echo 'should exit 1'
    fi
    ;;
  *)
    echo "Unsupported OS: ${OS}"
    echo 'should exit 1'
    ;;
esac

# 输出最终平台和架构
echo "Platform: ${PLATFORM}"
echo "Architecture: ${ARCH}"

# 拼接下载链接和校验码链接
TARGET_FILE="buildx-${VERSION}.${PLATFORM}-${ARCH}"
SHA256_FILE="${TARGET_FILE}.sbom.json"
URI_DOWNLOAD="https://github.com/${URI}/releases/download/${VERSION}/${TARGET_FILE}"
URI_SHA256="https://github.com/${URI}/releases/download/${VERSION}/${SHA256_FILE}"
echo "Download URL: ${URI_DOWNLOAD}"
echo "SHA256 URL: ${URI_SHA256}"

# 检查文件是否存在
if [[ -f "${PREFIX}/tmp/${TARGET_FILE}" ]]; then
  echo "File already exists: ${PREFIX}/tmp/${TARGET_FILE}"
  
  # 删除旧的 SHA256 文件(如果存在)
  if [[ -f "${PREFIX}/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: ${PREFIX}/tmp/${SHA256_FILE}"
    rm -fv "${PREFIX}/tmp/${SHA256_FILE}"
  fi

  # 下载新的 SHA256 文件
  echo "Downloading SHA256 file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "${PREFIX}/tmp/${SHA256_FILE}" "${URI_SHA256}"
  # 提取校验码
  CHECKSUM=$(cat "${PREFIX}/tmp/${SHA256_FILE}" | jq -r --arg filename "${TARGET_FILE}" '.subject[] | select(.name == $filename) | .digest.sha256')
  # 将校验码写入源文件
  echo "${CHECKSUM} *${TARGET_FILE}" > "${PREFIX}/tmp/${SHA256_FILE}"
  echo "校验码 ${CHECKSUM} 已写入文件: ${PREFIX}/tmp/${SHA256_FILE}"

  # 校验文件完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for ${PREFIX}/tmp/${TARGET_FILE}..."
  cd ${PREFIX}/tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    log_warning "SHA256 checksum failed. Removing file and retrying..."
    rm -fv "${PREFIX}/tmp/${TARGET_FILE}"
  else
    echo "File integrity verified successfully."
  fi
fi

# 如果文件不存在或之前校验失败
if [[ ! -f "${PREFIX}/tmp/${TARGET_FILE}" ]]; then
  echo "Downloading file..."
  curl -L -C - --retry 3 --retry-delay 5 --progress-bar -o "${PREFIX}/tmp/${TARGET_FILE}" "${URI_DOWNLOAD}"

  # 删除旧的 SHA256 文件并重新下载
  if [[ -f "${PREFIX}/tmp/${SHA256_FILE}" ]]; then
    echo "Removing old SHA256 file: ${PREFIX}/tmp/${SHA256_FILE}"
    rm -fv "${PREFIX}/tmp/${SHA256_FILE}"
  fi
  echo "Downloading SHA256 file..."
  curl -L --progress-bar -o "${PREFIX}/tmp/${SHA256_FILE}" "${URI_SHA256}"
  # 提取校验码
  CHECKSUM=$(cat "${PREFIX}/tmp/${SHA256_FILE}" | jq -r --arg filename "${TARGET_FILE}" '.subject[] | select(.name == $filename) | .digest.sha256')
  # 将校验码写入源文件
  echo "${CHECKSUM} *${TARGET_FILE}" > "${PREFIX}/tmp/${SHA256_FILE}"
  echo "校验码 ${CHECKSUM} 已写入文件: ${PREFIX}/tmp/${SHA256_FILE}"

  # 校验完整性
  # shasum 校验依赖 perl 可能 linux 系统需要手动安装
  echo "Verifying file integrity for ${PREFIX}/tmp/${TARGET_FILE}..."
  cd ${PREFIX}/tmp
  if ! shasum -a 256 -c "${SHA256_FILE}"; then
    echo "Download failed: SHA256 checksum does not match."
    echo 'should exit 1'
  else
    echo "File integrity verified successfully."
  fi
fi

sudo mv -fv "${PREFIX}/tmp/${TARGET_FILE}" ${PREFIX}/bin/docker-buildx
# Apply executable permissions to the binary
## 赋予执行权
sudo chmod -v +x ${PREFIX}/bin/docker-buildx
# create a symbolic link to ${PREFIX}/libexec/docker/cli-plugins/
# 创建插件目录和软链接
sudo mkdir -pv ${PREFIX}/libexec/docker/cli-plugins/
sudo ln -sfv ${PREFIX}/bin/docker-buildx ${PREFIX}/libexec/docker/cli-plugins/docker-buildx
# Test the installation.
## 导入 docker daemon socket 测试版本打印
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock
sudo -E docker-buildx version
sudo -E docker buildx version

此后使用docker-compose还是docker-buildx都需要提前加载 DOCKER_HOST 环境变量,这个需要注意一下。

export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock
sudo -E docker-compose version
sudo -E docker-buildx version

参考&感谢

Mamba User Guide — documentation
[Root] Termux:以原生效能在Android手機上跑Docker (紅米Note 5)
docker-on-android
Community – LineageOS
Build for guacamole | LineageOS Wiki
Extracting proprietary blobs from LineageOS zip files | LineageOS Wiki
Repo command reference | Android Open Source Project
tsinghua git-repo 源
lineage os
tsinghua AOSP 源
crdroid guacamole 固件镜像
github LineageOS/android_prebuilts_extract-tools
github TheMuppets/proprietary_vendor_oneplus
github moby/moby check-config.sh
docker use
github termux/termux-packages
github docker/cli
github moby/moby
github krallin/tini
github containerd/containerd
crdroid 固件刷机脚本
docker/buildx/issues/1834
docker/buildx/issues/136
moby/buildkit/blob/master/docs/buildkitd.toml.md
daxiaamu OP7P

Comments