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

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

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

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


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

adb shell getprop ro.boot.project_codename

最重要的是,一定要找好固件包,免得变成砖头,有线刷包就可以怎么折腾都不怕
听我说,编译内核是一件很枯燥的核对过程,这个过程需要考虑到各项之间的互相依赖和冲突并以此作出取舍
这不是个简单的过程,这里只展示具有逻辑的依赖项,需要耐心和不断的试错总结
不得不说设计的内核是一件件精美的艺术品,从某种意义上来讲,万事万物皆为艺术,而探索艺术本身是反人类的枯燥,因为艺术是用来欣赏的。
最近浏览 XDA 论坛,发现竟然有人成功的为Android16编译支持docker的内核链接在此,我忽然就想试试自己的 OP7P 设备型号是 guacamole 手机能不能也在进步进步?还是用那个二手的gmk m6 mini x86_64主机,尝试编译
gmk m6 配置是 24g 12c 1T+1T Ubuntu 24.04.2 LTS 实际运行内存 20G
由于内存不足也意味着需要 swap 扩展补充 45G 以满足编译 android 12 的条件 >=64G
实际编译时常 09:30:10
临时配置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 16 镜像

# 系统可以使用官方一键安装脚本 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 打算用路径 /media/gmktecm6/KINGSTONSSD1T/oneplus7pro/android-build

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


容器内编译操作

# 安装编译环境依赖
DEBIAN_FRONTEND=noninteractive
apt update
apt -y install apt-utils autoconf automake axel bc \
  bison build-essential ccache clang cmake \
  curl expat file flex g++ \
  g++-multilib gawk gcc gcc-multilib git \
  git-lfs gnupg gperf htop imagemagick \
  lib32ncurses-dev lib32readline-dev lib32z1-dev libc6-dev libcap-dev \
  libdw-dev libelf-dev libexpat1-dev libgmp-dev '^liblz4-.*' \
  '^liblzma.*' libmpc-dev libmpfr-dev libncurses-dev libncurses5 \
  libncurses6 libsdl1.2-dev libssl-dev libswitch-perl libtinfo5 \
  libtool libwxgtk3.0-gtk3-dev libxml-simple-perl libxml2 libxml2-utils \
  locales lz4 lzip '^lzma.*' lzop \
  maven nano ncftp patch patchelf \
  pkg-config pngcrush pngquant protobuf-compiler python-is-python3 \
  python2 python3 python3-dev python3-pip python3-protobuf \
  re2c rsync schedtool squashfs-tools subversion \
  systemd texinfo tzdata unzip w3m \
  wget 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
# ===== Android build dedicated HOME =====
export ANDROID_BUILD_HOME=/root/workspace/.home
mkdir -p "${ANDROID_BUILD_HOME}"
export HOME="${ANDROID_BUILD_HOME}"
# 固定使用系统中可用的 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

# 创建源码目录并获取(预计消耗 6h45m59.129s)
mkdir -pv /root/workspace/android-build/lineage-23.0
cd /root/workspace/android-build/lineage-23.0
repo init -u https://github.com/LineageOS/android.git -b lineage-23.0 --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

# 可能会有如下警告,意味着这两个 git 仓库里有很多“松散对象(loose objects)”,git 还没来得及整理成 pack 文件,占用磁盘空间变大
# warning: Project "platform/prebuilts/clang/host/linux-x86" is accumulating unoptimized data.
# warning: Project "platform/prebuilts/misc" is accumulating unoptimized data.
# 跑一次官方推荐的垃圾回收命令即可
repo sync --auto-gc

# 完成同步后加载脚本环境
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..

则有三个方案,任选其一,建议方案一。没报错请跳过
第一个方案 就是将 OP7P 刷机成 lineage 23.0 从中提取专有 vendor 文件
这里假设手机已经刷机搭载了 lineage 23.0 系统,并连接了电脑

# 手机点击 设置 -> 关于手机 -> 点击 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
# 验证设备 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
# 执行脚本等待 lineage 23.0 提取完成
# 执行提取脚本,如果没有继续往下看
./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官方有23.0的固件了

mkdir -pv /root/workspace/ota
pushd /root/workspace/ota 2>/dev/null
# lineage-23.0 Android 16 镜像,刷入没问题,可以提取出来专有文件构建 Android 自身
rm -fv Android.zip
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o 'Android.zip' \
     'https://mirrorbits.lineageos.org/full/guacamole/20251222/lineage-23.0-20251222-nightly-guacamole-signed.zip'

# 解压
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

第三个方案 可以不用尝试了,因为文件 vendor 文件支持的版本太低了
vendor blobs 必须与运行系统的 Android 版本 ABI 匹配

# 需要创建自定义配置,添加第三方 vendor 专有文件仓库 .repo/local_manifests/roomservice.xml
# 添加 vendor/oneplus 专有文件仓库也必须支持 android 12
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" />

完成以上可行方案就可以解决报错了,可以继续以下步骤了

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

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

# 编译镜像 croot brunch guacamole
croot

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

# 查看得到 img 镜像
echo $OUT
ls -al $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip*

# 创建备份目录
# 防止后续配套系统镜像覆盖最初配套系统
# 防止后续修改内核导致系统无法开机可以随时通过fastboot和recovery刷机还原
rm -frv /root/workspace/custom_build
mkdir -pv /root/workspace/custom_build
mv -fv $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip* /root/workspace/custom_build

# 我的手机已经刷了官方 lineage-23.0 guacamole 即 android 16 最新版本
# 接下来就是刷入自定义编译的 lineage-23.0 guacamole 的镜像了
# 参考教程如下
# https://wiki.lineageos.org/devices/guacamole/install/
# https://crdroid.net/guacamole/11/install
# 手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
# 进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试,启用 Rooted debugging 模式,连接电脑  
# 连接电脑,手机提示是否允许,就允许
# 连接电脑 重启到 bootloader 模式
adb -d reboot bootloader
fastboot devices

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

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

# 然后 fastboot 模式界面音量键选择重启进入 recovery 恢复模式
# 恢复模式点击 apply update -> Apply from ADB
# 连接电脑,使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入
adb -d sideload /root/workspace/custom_build/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,选择 Yes 切换 boot 分区

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 No 或者没有提示也别怕别哭,可以手动切换
注意观察 recovery 界面上的 Ativate slot 值,假设是 a
然后在 recovery 模式点击 Advanced -> Enter fastboot 进入 fastboot 模式
回到容器中,使用命令手动完成切换 boot 分区为 b 如下

# fastboot模式下连接的设备
fastboot devices
# 获取当前分区
fastboot getvar current-slot
# 设置b分区
fastboot set_active b
# 获取检查当前分区
fastboot getvar current-slot

然后再回到手机 fastboot 界面,点击 Enter recovery 回到 recovery 模式
然后在 recovery 模式点击 Advanced -> Reboot to recovery 重启 recovery 模式
注意观察 recovery 界面上的 Ativate slot 值,此时此刻应该是 b 了
重复刷机流程

# recovery 模式点击 apply update -> Apply from ADB
# 连接电脑,再次使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入另一个 boot 分区
adb -d sideload /root/workspace/custom_build/lineage-23.0-*-UNOFFICIAL-guacamole.zip


应该会有提示,这次选择 No 并在 recovery 模式点击 Advanced -> Reboot System now 重启系统

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 Yes 或者没有提示也别怕别哭,只是会切换 boot 分区重启到 recovery 模式
这时只要重新在 recovery 模式点击 Advanced -> Reboot System now 重启系统就可以了,等待重启需要有耐心
重启看效果
如果启动卡住很久就重新进入恢复模式清除 Factory reset -> Format data/factory reset -> Format data(清除用户数据恢复出厂设置)后继续尝试重启
设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试,启用 Rooted debugging 模式,连接电脑
手机提示是否允许,就允许
将 lineage-23.0 guacamole boot.img 传入到手机目录 /sdcard/

adb push /root/workspace/custom_build/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-v30.6.apk' \
     'https://github.com/topjohnwu/Magisk/releases/download/v30.6/Magisk-v30.6.apk'
adb install '/root/workspace/apks/Magisk-v30.6.apk'
# termux.apk
curl -L -C - --retry 3 --retry-delay 5 --progress-bar \
     -o '/root/workspace/apks/termux-app_v0.119.0-beta.3+apt-android-7-github-debug_arm64-v8a.apk' \
     'https://github.com/termux/termux-app/releases/download/v0.119.0-beta.3/termux-app_v0.119.0-beta.3+apt-android-7-github-debug_arm64-v8a.apk'
adb install '/root/workspace/apks/termux-app_v0.119.0-beta.3+apt-android-7-github-debug_arm64-v8a.apk'

打开 magisk app 修改 boot.img 得到 /sdcard/Download/magisk_patched-28100_BivXZ.img
检查文件是否命名成功

adb shell ls -al /sdcard/Download/ 

重命名 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 /root/workspace/custom_build/

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

adb -d reboot bootloader
fastboot flash --slot=all boot /root/workspace/custom_build/boot_magisk_patched.img

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

fastboot reboot


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

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

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

固件信息如下

Linux version 4.14.356-openela-rc1-perf-g519973973269 (nobody@android-build) (Android (13290119, +pgo, +bolt, +lto, +mlgo, based on r547379) clang version 20.0.0 (https://android.googlesource.com/toolchain/llvm-project b718bcaf8c198c82f3021447d943401e3ab5bd54), LLD 20.0.0 (/mnt/disks/build-disk/src/android/llvm-r547379-release/out/llvm-project/llvm b718bcaf8c198c82f3021447d943401e3ab5bd54)) #1 SMP PREEMPT Sun Jan 25 07:33:31 CST 2026

查看当前系统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
  - pids: missing
- CONFIG_PID_NS: missing
- CONFIG_IPC_NS: missing
- CONFIG_CGROUP_DEVICE: missing
- CONFIG_BRIDGE_NETFILTER: 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
- CONFIG_NFT_CT: missing
- CONFIG_NFT_FIB_IPV4: missing
- CONFIG_NFT_FIB_IPV6: missing
- CONFIG_NFT_FIB: missing
- CONFIG_NFT_MASQ: missing
- CONFIG_NFT_NAT: missing
- CONFIG_NF_TABLES: 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-23.0

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

获取到信息如下

device/oneplus/sm8150-common/BoardConfigCommon.mk:    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-23.0 那你为什么还要折腾一遍呢?可以跳过这个往后看,直接执行我的命令不好吗?
make menuconfig

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

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

Generally Necessary:
- cgroup hierarchy: cgroupv2
  Controllers:
  - cpu: missing
    - CGROUPS [=y]
      - General setup
        - Control Group support [=y]
    # 开启 CGROUP_SCHED 无效(需要联合编译配套系统规避)
    # 运行容器时必须加上 --exec-opt native.cgroupdriver=cgroupfs
    - CGROUP_SCHED [=y]
      - General setup
        - Control Group support
          - CPU controller [=y]
  - cpuset: missing
    - CGROUPS [=y]
      - General setup
        - Control Group support [=y]
    - SMP [=y]
      - Processor type and features
        - Symmetric multi-processing support [=y]
    # Depends on: CGROUPS [=y] && SMP [=y]
    - CPUSETS [=y]
      - General setup
        - Control Group support
          - Cpuset controller [=y]
  - io: missing
    - CGROUPS [=y]
      - General setup
        - Control Group support [=y]
    - BLOCK [=y]
      - Enable the block layer [=y]
    # Depends on: CGROUPS [=y] && BLOCK [=y]
    - BLK_CGROUP [=y]
      - General setup
        - Control Group support
          - IO controller [=y]
  - memory: available
    - CGROUPS [=y]
      - General setup
        - Control Group support [=y]
    - MEMCG [=y]
      - General setup
        - Control Group support [=y]
          - Memory controller [=y]
  - pids: missing
    - CGROUPS [=y]
      - General setup
        - Control Group support [=y]
    # 开启 CGROUP_PIDS 会导致 wifi 无法使用(需要联合编译配套系统规避)
    - CGROUP_PIDS [=y]
      - General setup
        - Control Group support [=y]
          - PIDs controller [=y]
- CONFIG_PID_NS: missing
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  - NAMESPACES [=y]
    - General setup
      - Namespaces support [=y]
  - PID_NS [=y]
    - General setup
      - Namespaces support [=y]
        - PID Namespaces [=y]
- CONFIG_IPC_NS: missing
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  - NAMESPACES [=y]
    - General setup
      - Namespaces support [=y]
  # 开启 SYSVIPC 会导致 wifi 无法使用(需要联合编译配套系统规避)
  # 运行容器时必须加上 --ipc=host
  - SYSVIPC [=y]
    - General setup
      - System V IPC [=y]
  - NET [=y]
    - Networking support [=y]
  # 开启 POSIX_MQUEUE 会导致 wifi 无法使用(需要联合编译配套系统规避)
  # 运行容器时必须加上 --ipc=host
  - POSIX_MQUEUE [=y]
    - General setup
      - POSIX Message Queues [=y]
  # 依赖 SYSVIPC 或 POSIX_MQUEUE 二选一开启都会无法使用wifi
  # 进而导致无法开启(需要联合编译配套系统规避)
  # 运行容器时必须加上 --ipc=host
  # Depends on: NAMESPACES [=y] && (SYSVIPC [=y] || POSIX_MQUEUE [=y])
  - IPC_NS [=y]
    - General setup
      - Namespaces support [=y]
        - IPC namespace [=y]
- CONFIG_CGROUP_DEVICE: missing
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  # 开启 CGROUP_DEVICE 会导致 wifi 无法使用(需要联合编译配套系统规避)
  - CGROUP_DEVICE [=y]
    - General setup
      - Control Group support [=y]
        - Device controller [=y]
- CONFIG_BRIDGE_NETFILTER: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  # Depends on: NET [=y] && INET [=y] 
  - IPV6 [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
          - The IPv6 protocol [=y]
  # Depends on: NET [=y] && (IPV6 [=y] || IPV6 [=y]=n [=n]) 
  - BRIDGE [=y]
    - Networking support [=y]
      - Networking options [=y]
        - 802.1d Ethernet Bridging [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && NETFILTER [=y]
  - NETFILTER_ADVANCED [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Advanced netfilter configuration [=y]
  # 开启 BRIDGE_NETFILTER 会导致 wifi 无法使用(需要联合编译配套系统规避)
  # 使用 host 网络模式(--net=host)或者通过手动配置 iptables 规则来辅助。
  # Depends on: NET [=y] && BRIDGE [=y] && NETFILTER [=y] && INET [=y] && NETFILTER_ADVANCED [=y]
  - BRIDGE_NETFILTER [=y]
    - Networking support [=y]
       - Networking options [=y]
         - Network packet filtering framework [=y]
           - Advanced netfilter configuration [=y]
             - Bridged IP/ARP packets filtering [=y]
- CONFIG_IP6_NF_TARGET_MASQUERADE: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  # Depends on: NET [=y] && INET [=y] 
  - IPV6 [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
          - The IPv6 protocol [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && INET [=y] && IPV6 [=y] 
  - IP6_NF_IPTABLES [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IP6 tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && INET [=y] && IPV6 [=y] && NF_CONNTRACK [=y]
  - NF_CONNTRACK_IPV6 [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration [=y]
            - IPv6 connection tracking support [=y]
  # Depends on: NET [=y] && NETFILTER [=y]
  - NETFILTER_ADVANCED [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Advanced netfilter configuration [=y]
  # Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && NF_CONNTRACK_IPV6 [=y] && NETFILTER_ADVANCED [=y]
  - IP6_NF_NAT [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IP6 tables support [=y]
            - ip6tables NAT support [=y]
  # Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && IP6_NF_NAT [=y]
  - IP6_NF_TARGET_MASQUERADE [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IP6 tables support [=y]
            - ip6tables NAT support [=y]
                - MASQUERADE target support [=y]
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y]
  - NETFILTER_XTABLES [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
         - Core Netfilter Configuration [=y]
           -  Netfilter Xtables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=y]
  - NETFILTER_XT_MATCH_ADDRTYPE [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
         - Core Netfilter Configuration [=y]
           - Netfilter Xtables support [=y]
             - "addrtype" address type match support [=y]
- CONFIG_NETFILTER_XT_MATCH_IPVS: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y]
  - NETFILTER_XTABLES [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
         - Core Netfilter Configuration [=y]
           -  Netfilter Xtables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # 开启 IP_VS 会导致 wifi 无法使用(需要联合编译配套系统规避)
  # 使用 host 网络模式(--net=host)或者通过手动配置 iptables 规则来辅助。
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n]) 
  - IP_VS [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
  # Depends on: NET [=y] && NETFILTER [=y]
  - NETFILTER_ADVANCED [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Advanced netfilter configuration [=y]
  # 依赖 IP_VS 开启会无法使用wifi,进而导致无法开启(需要联合编译配套系统规避)
  # 使用 host 网络模式(--net=host)或者通过手动配置 iptables 规则来辅助。
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=y] && IP_VS [=y] && NETFILTER_ADVANCED [=y] && NF_CONNTRACK [=y] 
  - NETFILTER_XT_MATCH_IPVS [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
         - Core Netfilter Configuration [=y]
           - Netfilter Xtables support [=y]
             - "ipvs" match support [=y]
- CONFIG_IP6_NF_NAT: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  # Depends on: NET [=y] && INET [=y] 
  - IPV6 [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
          - The IPv6 protocol [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && INET [=y] && IPV6 [=y] 
  - IP6_NF_IPTABLES [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IP6 tables support [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && INET [=y] && IPV6 [=y] && NF_CONNTRACK [=y]
  - NF_CONNTRACK_IPV6 [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration [=y]
            - IPv6 connection tracking support [=y]
  # Depends on: NET [=y] && NETFILTER [=y]
  - NETFILTER_ADVANCED [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Advanced netfilter configuration [=y]
  # Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && NF_CONNTRACK_IPV6 [=y] && NETFILTER_ADVANCED [=y]
  - IP6_NF_NAT [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IP6 tables support [=y]
              - ip6tables NAT support [=y]
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
- CONFIG_POSIX_MQUEUE: missing
  - POSIX_MQUEUE [=y]
    - General setup
      - POSIX Message Queues [=y]

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

经过摸索总结出开启内核功能命令
再覆盖一遍,万一 make menuconfig 操作不小心污染了 .config 就不好了

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

# 开启功能项
# android 16 支持 docker 必要条件,全部开启
scripts/config --enable CONFIG_CGROUPS
# 开启 CGROUP_SCHED 无效(需要联合编译配套系统规避)
# 运行容器时必须加上 --exec-opt native.cgroupdriver=cgroupfs
scripts/config --enable CONFIG_CGROUP_SCHED
scripts/config --enable CONFIG_SMP
# Depends on: CGROUPS [=y] && SMP [=y]
scripts/config --enable CONFIG_CPUSETS
scripts/config --enable CONFIG_BLOCK
# Depends on: CGROUPS [=y] && BLOCK [=y]
scripts/config --enable CONFIG_BLK_CGROUP
scripts/config --enable CONFIG_MEMCG
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
scripts/config --enable CONFIG_CGROUP_PIDS
scripts/config --enable CONFIG_MULTIUSER
scripts/config --enable CONFIG_NAMESPACES
scripts/config --enable CONFIG_PID_NS
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
# 运行容器时必须加上 --ipc=host
scripts/config --enable CONFIG_SYSVIPC
scripts/config --enable CONFIG_NET
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
# 运行容器时必须加上 --ipc=host
scripts/config --enable CONFIG_POSIX_MQUEUE
# 依赖 SYSVIPC 或 POSIX_MQUEUE 二选一开启都会无法使用wifi(需要联合编译配套系统规避)
# 运行容器时必须加上 --ipc=host
# Depends on: NAMESPACES [=y] && (SYSVIPC [=y] || POSIX_MQUEUE [=y])
scripts/config --enable CONFIG_IPC_NS
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
scripts/config --enable CONFIG_CGROUP_DEVICE
scripts/config --enable CONFIG_INET
# Depends on: NET [=y] && INET [=y] 
scripts/config --enable CONFIG_IPV6
# Depends on: NET [=y] && (IPV6 [=y] || IPV6 [=y]=n [=n]) 
scripts/config --enable CONFIG_BRIDGE
scripts/config --enable CONFIG_NETFILTER
# Depends on: NET [=y] && NETFILTER [=y]
scripts/config --enable CONFIG_NETFILTER_ADVANCED
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
# 使用 host 网络模式(--net=host)或者通过手动配置 iptables 规则来辅助。
# Depends on: NET [=y] && BRIDGE [=y] && NETFILTER [=y] && INET [=y] && NETFILTER_ADVANCED [=y]
scripts/config --enable CONFIG_BRIDGE_NETFILTER
# Depends on: NET [=y] && NETFILTER [=y] && INET [=y] && IPV6 [=y] 
scripts/config --enable CONFIG_IP6_NF_IPTABLES
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
scripts/config --enable CONFIG_NF_CONNTRACK
# Depends on: NET [=y] && NETFILTER [=y] && INET [=y] && IPV6 [=y] && NF_CONNTRACK [=y]
scripts/config --enable CONFIG_NF_CONNTRACK_IPV6
# Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && NF_CONNTRACK_IPV6 [=y] && NETFILTER_ADVANCED [=y]
scripts/config --enable CONFIG_IP6_NF_NAT
# Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && IP6_NF_IPTABLES [=y] && IP6_NF_NAT [=y]
scripts/config --enable CONFIG_IP6_NF_TARGET_MASQUERADE
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y]
scripts/config --enable CONFIG_NETFILTER_XTABLES
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=y]
scripts/config --enable CONFIG_NETFILTER_XT_MATCH_ADDRTYPE
# 开启会导致 wifi 无法使用(需要联合编译配套系统规避)
# 使用 host 网络模式(--net=host)或者通过手动配置 iptables 规则来辅助。
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n]) 
scripts/config --enable CONFIG_IP_VS
# 依赖 CONFIG_IP_VS 开启会无法使用wifi,进而导致无法开启(需要联合编译配套系统规避)
# 使用 host 网络模式(--net=host)或者通过手动配置 iptables 规则来辅助。
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NETFILTER_XTABLES [=y] && IP_VS [=y] && NETFILTER_ADVANCED [=y] && NF_CONNTRACK [=y] 
scripts/config --enable CONFIG_NETFILTER_XT_MATCH_IPVS

# 最后检查一遍
EXP_INFO='
CONFIG_CGROUPS=
CONFIG_CGROUP_SCHED=
CONFIG_SMP=
CONFIG_CPUSETS=
CONFIG_BLOCK=
CONFIG_BLK_CGROUP=
CONFIG_MEMCG=
CONFIG_CGROUP_PIDS=
CONFIG_MULTIUSER=
CONFIG_NAMESPACES=
CONFIG_PID_NS=
CONFIG_SYSVIPC=
CONFIG_NET=
CONFIG_POSIX_MQUEUE=
CONFIG_IPC_NS=
CONFIG_CGROUP_DEVICE=
CONFIG_INET=
CONFIG_IPV6=
CONFIG_BRIDGE=
CONFIG_NETFILTER=
CONFIG_NETFILTER_ADVANCED=
CONFIG_BRIDGE_NETFILTER=
CONFIG_IP6_NF_IPTABLES=
CONFIG_NF_CONNTRACK=
CONFIG_NF_CONNTRACK_IPV6=
CONFIG_IP6_NF_NAT=
CONFIG_IP6_NF_TARGET_MASQUERADE=
CONFIG_NETFILTER_XTABLES=
CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=
CONFIG_IP_VS=
CONFIG_NETFILTER_XT_MATCH_IPVS=
'

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

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

# 回到源码目录
popd

# 清理 kernel obj 目录,避免历史构建污染
rm -fr $OUT/obj/KERNEL_OBJ

# 生成支持 docker 的 boot.img 经测试单独编译wifi会失效
# 看来需要联合编译
#make bootimage -j$(($(nproc)*2))
# 构建成功后进入目录,你就能看到 boot.img docker支持版文件
#echo $OUT
#ls -al $OUT/*.img

# 联合编译内核生成镜像,看机器性能了
# 第二次编译镜像就不会消耗太多时间大概9~22min左右就能结束,耐心点
brunch guacamole

# 查看得到 img 镜像
echo $OUT
ls -al $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip*

# 创建备份目录
# 防止后续配套系统镜像覆盖已经开启必要性支持的docker配套系统
# 防止后续修改内核导致系统无法开机可以随时通过fastboot和recovery刷机还原
rm -frv /root/workspace/custom_build_docker_1
mkdir -pv /root/workspace/custom_build_docker_1
mv -fv $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip* /root/workspace/custom_build_docker_1

接下来就是刷入自定义内核联合编译的 lineage-23.0 guacamole 的镜像了

# 手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
# 进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试,启用 Rooted debugging 模式,连接电脑  
# 连接电脑,手机提示是否允许,就允许
# 连接电脑 重启到 bootloader 模式
adb -d reboot bootloader
fastboot devices

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

# 然后 fastboot 模式界面音量键选择重启进入 recovery 恢复模式
# 恢复模式点击 apply update -> Apply from ADB
# 连接电脑,使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入
adb -d sideload /root/workspace/custom_build_docker_1/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,选择 Yes 切换 boot 分区

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 No 或者没有提示也别怕别哭,可以手动切换
注意观察 recovery 界面上的 Ativate slot 值,假设是 b
然后在 recovery 模式点击 Advanced -> Enter fastboot 进入 fastboot 模式
回到容器中,使用命令手动完成切换 boot 分区为 a 如下

# fastboot模式下连接的设备
fastboot devices
# 获取当前分区
fastboot getvar current-slot
# 设置a分区
fastboot set_active a
# 获取检查当前分区
fastboot getvar current-slot

然后再回到手机 fastboot 界面,点击 Enter recovery 回到 recovery 模式
然后在 recovery 模式点击 Advanced -> Reboot to recovery 重启 recovery 模式
注意观察 recovery 界面上的 Ativate slot 值,此时此刻应该是 a 了
重复刷机流程

# recovery 模式点击 apply update -> Apply from ADB
# 连接电脑,再次使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入另一个 boot 分区
adb -d sideload /root/workspace/custom_build_docker_1/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,这次选择 No 并在 recovery 模式点击 Advanced -> Reboot System now 重启系统

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 Yes 或者没有提示也别怕别哭,只是会切换 boot 分区重启到 recovery 模式
这时只要重新在 recovery 模式点击 Advanced -> Reboot System now 重启系统就可以了,等待重启需要有耐心

通过 magisk app 修改 boot.img

# 将 $OUT 的 boot.img 传入手机 /sdcard/
adb push /root/workspace/custom_build_docker_1/boot.img /sdcard/

通过 magisk app 修改 boot.img 得到 /sdcard/Download/magisk_patched-29000_i2Elj.img
检查文件是生成成功

adb shell ls -al /sdcard/Download/

重命名 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 /root/workspace/custom_build_docker_1/

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

运行 Termux 执行脚本查看固件内核 docker 必要的支持功能是否全部开启

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: available
  - pids: available
- CONFIG_NAMESPACES: enabled
- CONFIG_NET_NS: enabled
- CONFIG_PID_NS: enabled
- CONFIG_IPC_NS: enabled
- CONFIG_UTS_NS: enabled
- CONFIG_CGROUPS: enabled
- CONFIG_CGROUP_CPUACCT: enabled
- CONFIG_CGROUP_DEVICE: enabled
- CONFIG_CGROUP_FREEZER: enabled
- CONFIG_CGROUP_SCHED: enabled
- CONFIG_CPUSETS: enabled
- CONFIG_MEMCG: enabled
- CONFIG_KEYS: enabled
- CONFIG_VETH: enabled
- CONFIG_BRIDGE: enabled
- CONFIG_BRIDGE_NETFILTER: enabled
- CONFIG_IP_NF_FILTER: enabled
- CONFIG_IP_NF_MANGLE: enabled
- CONFIG_IP_NF_TARGET_MASQUERADE: enabled
- CONFIG_IP6_NF_FILTER: enabled
- CONFIG_IP6_NF_MANGLE: enabled
- CONFIG_IP6_NF_TARGET_MASQUERADE: enabled
- CONFIG_NETFILTER_XT_MATCH_ADDRTYPE: enabled
- CONFIG_NETFILTER_XT_MATCH_CONNTRACK: enabled
- CONFIG_NETFILTER_XT_MATCH_IPVS: enabled
- CONFIG_NETFILTER_XT_MARK: enabled
- CONFIG_IP_NF_RAW: enabled
- CONFIG_IP_NF_NAT: enabled
- CONFIG_NF_NAT: enabled
- CONFIG_IP6_NF_RAW: enabled
- CONFIG_IP6_NF_NAT: enabled
- CONFIG_NF_NAT: enabled
- CONFIG_POSIX_MQUEUE: enabled
- CONFIG_NF_NAT_IPV4: enabled
- CONFIG_NF_NAT_NEEDED: enabled

下面的步骤是开启非必要扩展功能,不想看可以跳到 安装测试运行 termux docker

非必要项可以不开启,想开启可以继续看,内核扩展功能开启操作同理
再次回到容器进入内核路径,根据上述信息,查找内核配置文件路径

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

# 这时就要备份已经修改的内核配置文件
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig arch/arm64/configs/vendor/sm8150-perf_defconfig_docker_1

# 复制已经修改的内核配置文件到当前目录
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig_docker_1 .config

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

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

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

Optional Features:
- CONFIG_USER_NS: missing
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  - NAMESPACES [=y]
    - General setup
      - Namespaces support [=y]
  - USER_NS [=y]
    - General setup
      - Namespaces support [=y]
        - User namespace [=y]
- CONFIG_CGROUP_PIDS: missing
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  # 开启 CGROUP_PIDS 会导致 wifi 无法使用(需要联合编译配套系统规避)
  - CGROUP_PIDS [=y]
    - General setup
      - Control Group support [=y]
        - PIDs controller [=y]
- CONFIG_BLK_DEV_THROTTLING: missing
  - SBITMAP [=y]
  - SRCU [=y]
  - BLOCK [=y]
    - Enable the block layer [=y]
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  # Depends on: CGROUPS [=y] && BLOCK [=y]
  - BLK_CGROUP [=y]
    - General setup
      - Control Group support [=y]
        - IO controller [=y]
  - BLK_DEV_THROTTLING [=y]
    - Enable the block layer [=y]
      - Block layer bio throttling support [=y]
- CONFIG_CGROUP_PERF: missing
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  - HAVE_PERF_EVENTS [=y]
  - PERF_EVENTS [=y]
    - General setup
      - Kernel Performance Events And Counters [=y]
        - Kernel performance events and counters [=y]
  - CGROUP_PERF [=y]
    - General setup
      - Control Group support [=y]
        - Perf controller [=y]
- CONFIG_CGROUP_HUGETLB: missing
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  - X86 [=y]
  - IA64 [=?]
  - SPARC64 [=?]
  - S390 [=?]
  - 64BIT [=y]
    - 64-bit kernel [=y]
  - SYS_SUPPORTS_HUGETLBFS [=y]
  - BROKEN [=y]
  # HUGETLB_PAGE 和 CGROUP_HUGETLB 依赖项
  # X86 [=y] || IA64 || SPARC64 || S390 && 64BIT [=y] || SYS_SUPPORTS_HUGETLBFS || BROKEN [=n]
  - HUGETLBFS [=y]
    - File systems
      - Pseudo filesystems
        - HugeTLB file system support [=y]
  - HUGETLB_PAGE [=y]
  - CGROUP_HUGETLB [=y]
    - General setup
      - Control Group support [=y]
        - HugeTLB controller [=y]
- CONFIG_NET_CLS_CGROUP: missing
  - NET [=y]
    - Networking support [=y]
  - NET_SCHED [=y]
    - Networking support [=y]
      - Networking options
        - QoS and/or fair queueing [=y]
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  # Depends on: NET [=y] && NET_SCHED [=y] && CGROUPS [=y]
  - NET_CLS_CGROUP [=y]
    - Networking support [=y]
      - Networking options
        - QoS and/or fair queueing [=y]
          - Control Group Classifier [=y]
- CONFIG_CGROUP_NET_PRIO: missing
  - NET [=y]
    - Networking support [=y]
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  # Depends on: NET [=y] && CGROUPS [=y]
  - CGROUP_NET_PRIO [=y]
    - Networking support [=y]
      - Networking options
        - Network priority cgroup [=y]
- CONFIG_CFS_BANDWIDTH: missing
  - CGROUPS [=y]
    - General setup
      - Control Group support [=y]
  # 开启 CGROUP_SCHED 会导致 wifi 无法使用(需要联合编译配套系统规避)
  # 运行容器时必须加上 --exec-opt native.cgroupdriver=cgroupfs
  - CGROUP_SCHED [=y]
    - General setup
      - Control Group support
        - CPU controller [=y]
  # Depends on: CGROUPS [=y] && CGROUP_SCHED [=y]
  - FAIR_GROUP_SCHED [=y]
    - General setup
      - Control Group support [=y]
        - CPU controller [=y]
          - Group scheduling for SCHED_OTHER [=y]
  - SMP [=y]
    - Processor type and features
      - Symmetric multi-processing support [=y]
	# CONFIG_SCHED_WALT 和 CONFIG_CFS_BANDWIDTH 互为冲突
	# CONFIG_SCHED_WALT WALT 调度(Window Assisted Load Tracking,Pixel/Qualcomm 特有的调度器),默认启用就必须屏蔽掉 CONFIG_CFS_BANDWIDTH。
  - SCHED_WALT [=y]
    - General setup [=y]
      - CPU/Task time and stats accounting [=y]
        - Support window based load tracking [=y]
  # !SCHED_WALT 意味着和 SCHED_WALT 逻辑冲突
  # Depends on: CGROUPS [=y] && CGROUP_SCHED [=y] && FAIR_GROUP_SCHED [=y] && !SCHED_WALT [=y]
  # 开启会导致编译镜像失败,“退一步,海阔天空”
  # 在内核开发中,保持源码的完整性和稳定性永远比追求一个难以适配的功能更重要。
  # 关闭此项,docker 就无法使用 cpus: 0.5  cpuset: "0,1,2,3"  
  - CFS_BANDWIDTH [=n]
    - General setup
      - Control Group support [=y]
        - CPU controller [=y]
          - Group scheduling for SCHED_OTHER [=y]
            - CPU bandwidth provisioning for FAIR_GROUP_SCHED [=n]
- CONFIG_IP_VS: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n])
  - IP_VS [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
- CONFIG_IP_VS_NFCT: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n])
  - IP_VS [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y] && NF_CONNTRACK [=y]
  - IP_VS_NFCT [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
            - Netfilter connection tracking [=y]
- CONFIG_IP_VS_PROTO_TCP: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n])
  - IP_VS [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y]
  - IP_VS_PROTO_TCP [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
            - TCP load balancing support [=y]
- CONFIG_IP_VS_PROTO_UDP: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n])
  - IP_VS [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y] 
  - IP_VS_PROTO_UDP [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
            - UDP load balancing support [=y]
- CONFIG_IP_VS_RR: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && (NF_CONNTRACK [=y] || NF_CONNTRACK [=y]=n [=n])
  - IP_VS [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
  # Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y]
  - IP_VS_RR [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP virtual server support [=y]
            - round-robin scheduling [=y]
- CONFIG_SECURITY_APPARMOR: missing
  - SYSFS [=y]
    - File systems
      - Pseudo filesystems
        - sysfs file system support [=y]
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  # Depends on: SYSFS [=y] && MULTIUSER [=y] 
  - SECURITY [=y]
    - Security options
      - Enable different security models [=y]
  - NET [=y]
    - Networking support [=y]
  # Depends on: SECURITY [=y] && NET [=y]
  - SECURITY_APPARMOR [=y]
    - Security options
      - AppArmor support [=y]
- CONFIG_NFT_CT: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=n] && NF_CONNTRACK [=y] 
  - NFT_CT [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter connection tracking support [=y]
              - Netfilter nf_tables conntrack module [=y]
- CONFIG_NFT_FIB_IPV4: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=y]
  - NF_TABLES_IPV4 [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP: Netfilter Configuration
            - IPv4 nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=n] && NF_TABLES_IPV4 [=n]
  - NFT_FIB_IPV4 [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IP: Netfilter Configuration
            - IPv4 nf_tables support [=y]
              - nf_tables fib / ip route lookup support [=y]
- CONFIG_NFT_FIB_IPV6: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  # Depends on: NET [=y] && INET [=y] 
  - IPV6 [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
          - The IPv6 protocol [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NF_TABLES [=y]
  - NF_TABLES_IPV6 [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IPv6 nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NF_TABLES [=y] && NF_TABLES_IPV6 [=y]
  - NFT_FIB_IPV6 [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - IPv6: Netfilter Configuration
            - IPv6 nf_tables support [=y]
              - nf_tables fib / ipv6 route lookup support [=y]
- CONFIG_NFT_FIB: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=y]
  - NFT_FIB [=y]
- CONFIG_NFT_MASQ: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=y] && NF_CONNTRACK [=y] 
  - NF_NAT [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
              - Netfilter nf_tables nat module [=y]
  - NFT_MASQ [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
              - Netfilter nf_tables masquerade support [=y]
- CONFIG_NFT_NAT: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_CONNTRACK [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration [=y]
            - Netfilter connection tracking support [=y]
  - NFT_NAT [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
              - Netfilter nf_tables nat module [=y]
- CONFIG_NF_TABLES: missing
  - NET [=y]
    - Networking support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  - NETFILTER [=y]
    - Networking support [=y]
      - Networking options [=y]
        - Network packet filtering framework [=y]
  # Depends on: NET [=y] && INET [=y] && NETFILTER [=y] 
  - NF_TABLES [=y]
    - Networking support [=y]
      - Networking options
        - Network packet filtering framework [=y]
          - Core Netfilter Configuration
            - Netfilter nf_tables support [=y]
- Network Drivers:
  - "bridge":
    - sysctl net.ipv4.ip_forward: disabled
    - sysctl net.ipv6.conf.all.forwarding: disabled
    - sysctl net.ipv6.conf.default.forwarding: disabled
  - "overlay":
    - CONFIG_VXLAN: missing
      - NET [=y]
        - Networking support [=y]
      - NETDEVICES [=y]
        - Device Drivers
          - Network device support [=y]
      - NET_CORE [=y]
        - Device Drivers
          - Network device support [=y]
            - Network core driver support [=y]
      - INET [=y]
        - Networking support [=y]
          - Networking options [=y]
            - TCP/IP networking [=y]
      # Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y]
      - VXLAN [=y]
        - Device Drivers
          - Network device support [=y]
            - Network core driver support [=y]
              - Virtual eXtensible Local Area Network (VXLAN) [=y]
    - CONFIG_BRIDGE_VLAN_FILTERING: missing
      - NET [=y]
        - Networking support [=y]
      # Depends on: NET [=y] && INET [=y] 
      - IPV6 [=y]
        - Networking support [=y]
          - Networking options [=y]
            - TCP/IP networking [=y]
              - The IPv6 protocol [=y]
      # Depends on: NET [=y] && (IPV6 [=y] || IPV6 [=y]=n [=n]) 
      - BRIDGE [=y]
        - Networking support [=y]
          - Networking options [=y]
            - 802.1d Ethernet Bridging [=y]
      - VLAN_8021Q [=y]
        - Networking support [=y]
          - Networking options [=y]
            - 802.1Q/802.1ad VLAN Support [=y]
      # Depends on: NET [=y] && BRIDGE [=y] && VLAN_8021Q [=y]
      - BRIDGE_VLAN_FILTERING [=y]
        - Networking support [=y]
          - Networking options
            - 802.1d Ethernet Bridging [=y]
              - VLAN filtering [=y]
  - "ipvlan":
    - CONFIG_IPVLAN: missing
      - NETDEVICES [=y]
        - Device Drivers
          - Network device support [=y]
      - NET_CORE [=y]
        - Device Drivers
          - Network device support [=y]
            - Network core driver support [=y]
      - NET [=y]
        - Networking support [=y]
      - INET [=y]
        - Networking support [=y]
          - Networking options [=y]
            - TCP/IP networking [=y]
      # Depends on: NET [=y] && INET [=y] 
      - IPV6 [=y]
        - Networking support [=y]
          - Networking options [=y]
            - TCP/IP networking [=y]
              - The IPv6 protocol [=y]
      - NETFILTER [=y]
        - Networking support [=y]
          - Networking options [=y]
            - Network packet filtering framework [=y]
      # Depends on: NET [=y] && (INET [=y] || IPV6 [=y])
      - NET_L3_MASTER_DEV [=y]
        - Networking support [=y]
          - Networking options
            - L3 Master device support [=y]
      # Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NET_L3_MASTER_DEV [=y]
      - IPVLAN [=y]
        - Device Drivers
          - Network device support [=y]
            - Network core driver support [=y]
              - IP-VLAN support [=y]
  - "macvlan":
    - CONFIG_MACVLAN: missing
      - NET [=y]
        - Networking support [=y]
      - NETDEVICES [=y]
        - Device Drivers
          - Network device support [=y]
      - NET_CORE [=y]
        - Device Drivers
          - Network device support [=y]
            - Network core driver support [=y]
      # Depends on: NETDEVICES [=y] && NET_CORE [=y] 
      - MACVLAN [=y]
        - Device Drivers
          - Network device support [=y]
            - Network core driver support [=y]
              - MAC-VLAN support [=y]
- Storage Drivers:
  - "btrfs":
    - CONFIG_BTRFS_FS: missing
      - SBITMAP [=y]
      - SRCU [=y]
      - BLOCK [=y]
        - Enable the block layer [=y]
      - PPC_256K_PAGES [=n]
      - PAGE_SIZE_256KB [=n]
      # !PPC_256K_PAGES 和 !PAGE_SIZE_256KB 意味着与 PPC_256K_PAGES 和 PAGE_SIZE_256KB 内核逻辑冲突
      # Depends on: BLOCK [=y] && !PPC_256K_PAGES && !PAGE_SIZE_256KB
      - BTRFS_FS [=y]
        - File systems
          - Btrfs filesystem support [=y]
    - CONFIG_BTRFS_FS_POSIX_ACL: missing
      - SBITMAP [=y]
      - SRCU [=y]
      - BLOCK [=y]
        - Enable the block layer [=y]
      # !PPC_256K_PAGES 和 !PAGE_SIZE_256KB 意味着与 PPC_256K_PAGES 和 PAGE_SIZE_256KB 内核逻辑冲突
      # Depends on: BLOCK [=y] && !PPC_256K_PAGES && !PAGE_SIZE_256KB
      - BTRFS_FS [=y]
        - File systems
          - Btrfs filesystem support [=y]
      # Depends on: BLOCK [=y] && BTRFS_FS [=y] 
      - BTRFS_FS_POSIX_ACL [=y]
        - File systems
          - Btrfs filesystem support [=y]
            - Btrfs POSIX Access Control Lists [=y]
  - "zfs":
    - /dev/zfs: missing
    - zfs command: missing
    - zpool command: missing

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

# 额外参数扩展兼容
- CONFIG_MEMCG_SWAP_ENABLED [=y]
	- CGROUPS [=y]
	  - General setup
	    - Control Group support [=y]
	- MMU [=y]
	- BLOCK [=y]
	  - Enable the block layer [=y]
	# Depends on: MMU [=y] && BLOCK [=y]
	- SWAP [=y]
	  - General setup
	    - Support for paging of anonymous memory [=y]
	# Depends on: CGROUPS [=y] && MEMCG [=y] && SWAP [=y]
	- MEMCG_SWAP [=y]
	  - General setup
	    - Control Group support (CGROUPS [=y])
	      - Memory controller (MEMCG [=y])
	       - Swap controller [=y] 
	# Depends on: CGROUPS [=y] && MEMCG_SWAP [=y]
	- MEMCG_SWAP_ENABLED [=y]
	  - General setup
	    - Control Group support (CGROUPS [=y])
	      - Memory controller (MEMCG [=y])
	        - Swap controller (MEMCG_SWAP [=y])
	          - Swap controller enabled by default [=y]
- CONFIG_BLK_DEV_LOOP [=y]
  - BLOCK [=y]
	  - Enable the block layer [=y]
  - BLK_DEV [=y]
    - Device Drivers
      - Block devices [=y]
  - BLK_DEV_LOOP [=y]
    - Device Drivers
      - Block devices [=y]
        - Loopback device support [=y]
# 对杂项二进制文件格式的支持,可以让系统识别并运行非标准格式的可执行文件(例如通过 binfmt_misc 可直接运行脚本或虚拟格式的二进制)。
- CONFIG_BINFMT_MISC [=y]
  - BINFMT_MISC [=y]
    - Executable file formats / Emulations 
        - Kernel support for MISC binaries [=y]
# 不确定需不需要的跨平台兼容项位置
# 为 x64 位内核添加对 32 位 (IA-32) 应用的兼容支持,使得旧的 32 位软件可以在 x64 位系统上正常运行,这里不需要。
- CONFIG_IA32_EMULATION [=n]
  - 64BIT [=y]
    - 64-bit kernel [=y]
  - X86_64 [=y]
  - IA32_EMULATION [=y]
    - Executable file formats / Emulations
      - IA32 Emulation [=n]

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

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

启用扩展功能

# 非必要条件
scripts/config --enable CONFIG_USER_NS
scripts/config --enable CONFIG_SBITMAP
scripts/config --enable CONFIG_SRCU
scripts/config --enable CONFIG_BLK_DEV_THROTTLING
scripts/config --enable CONFIG_HAVE_PERF_EVENTS
scripts/config --enable CONFIG_PERF_EVENTS
scripts/config --enable CONFIG_CGROUP_PERF
scripts/config --enable CONFIG_X86
scripts/config --disable CONFIG_IA64
scripts/config --disable CONFIG_SPARC64
scripts/config --disable CONFIG_S390
scripts/config --enable CONFIG_64BIT
scripts/config --enable CONFIG_SYS_SUPPORTS_HUGETLBFS
scripts/config --enable CONFIG_BROKEN
# ARM64 内存管理代码中的一个 Bug。由于高通内核通常不开启 HugePages,这段代码在发布前可能根本没有通过编译测试
# X86 [=y] || IA64 || SPARC64 || S390 && 64BIT [=y] || SYS_SUPPORTS_HUGETLBFS || BROKEN [=n]
# HUGETLB_PAGE 和 CGROUP_HUGETLB 依赖项
scripts/config --disable CONFIG_HUGETLBFS
scripts/config --disable CONFIG_HUGETLB_PAGE
scripts/config --disable CONFIG_CGROUP_HUGETLB
scripts/config --enable CONFIG_NET_SCHED
# NET [=y] && NET_SCHED [=y] && CGROUPS [=y]
scripts/config --enable CONFIG_NET_CLS_CGROUP
# Depends on: NET [=y] && CGROUPS [=y]
scripts/config --enable CONFIG_CGROUP_NET_PRIO
# Depends on: CGROUPS [=y] && CGROUP_SCHED [=y]
scripts/config --enable CONFIG_FAIR_GROUP_SCHED
# CONFIG_SCHED_WALT 和 CONFIG_CFS_BANDWIDTH 互为冲突
# CONFIG_SCHED_WALT  WALT 调度(Window Assisted Load Tracking,Pixel/Qualcomm 特有的调度器),默认启用就必须屏蔽掉 CONFIG_CFS_BANDWIDTH。
scripts/config --enable CONFIG_SCHED_WALT
# !SCHED_WALT 意味着和 SCHED_WALT 逻辑冲突
# Depends on: CGROUPS [=y] && CGROUP_SCHED [=y] && FAIR_GROUP_SCHED [=y] && !SCHED_WALT [=y]
# 开启会导致编译镜像失败,“退一步,海阔天空”
# 在内核开发中,保持源码的完整性和稳定性永远比追求一个难以适配的功能更重要。
# 关闭此项,docker 就无法使用 cpus: 0.5 cpuset: "0,1,2,3"  
scripts/config --disable CONFIG_CFS_BANDWIDTH
# Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y] && NF_CONNTRACK [=y]
scripts/config --enable CONFIG_IP_VS_NFCT
# Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y]
scripts/config --enable CONFIG_IP_VS_PROTO_TCP
# Depends on: NET [=y] && NETFILTER [=y] && IP_VS [=y] 
scripts/config --enable CONFIG_IP_VS_PROTO_UDP
scripts/config --enable CONFIG_IP_VS_RR
scripts/config --enable CONFIG_SYSFS
# Depends on: SYSFS [=y] && MULTIUSER [=y] 
scripts/config --enable CONFIG_SECURITY
# Depends on: SECURITY [=y] && NET [=y]
scripts/config --enable CONFIG_SECURITY_APPARMOR
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=n] && NF_CONNTRACK [=y] 
scripts/config --enable CONFIG_NFT_CT
scripts/config --enable CONFIG_NF_TABLES
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=y] 
scripts/config --enable CONFIG_NF_TABLES_IPV4
# Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NF_TABLES [=y]
scripts/config --enable CONFIG_NF_TABLES_IPV6
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=n] && NF_TABLES_IPV4 [=n]
scripts/config --enable CONFIG_NFT_FIB_IPV4
# Depends on: NET [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NF_TABLES [=y] && NF_TABLES_IPV6 [=y]
scripts/config --enable CONFIG_NFT_FIB_IPV6
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=y]
scripts/config --enable CONFIG_NFT_FIB
# Depends on: NET [=y] && INET [=y] && NETFILTER [=y] && NF_TABLES [=y] && NF_CONNTRACK [=y] 
scripts/config --enable CONFIG_NF_NAT
scripts/config --enable CONFIG_NFT_MASQ
scripts/config --enable CONFIG_NFT_NAT
scripts/config --enable CONFIG_NETDEVICES
scripts/config --enable CONFIG_NET_CORE
# Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y]
scripts/config --enable CONFIG_VXLAN
# Depends on: NET [=y] && (IPV6 [=y] || IPV6 [=y]=n [=n]) 
scripts/config --enable CONFIG_VLAN_8021Q
# Depends on: NET [=y] && BRIDGE [=y] && VLAN_8021Q [=y]
scripts/config --enable CONFIG_BRIDGE_VLAN_FILTERING
# Depends on: NET [=y] && (INET [=y] || IPV6 [=y])
scripts/config --enable CONFIG_NET_L3_MASTER_DEV
# Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y] && IPV6 [=y] && NETFILTER [=y] && NET_L3_MASTER_DEV [=y]
scripts/config --enable CONFIG_IPVLAN
# Depends on: NETDEVICES [=y] && NET_CORE [=y] 
scripts/config --enable CONFIG_MACVLAN
scripts/config --disable CONFIG_PPC_256K_PAGES
scripts/config --disable CONFIG_PAGE_SIZE_256KB
# 对于在手机上运行 Docker,Overlay2 才是官方推荐且性能最好的存储驱动。Btrfs 在手机闪存(UFS)上的性能并不理想,且占用大量额外内存。
# !PPC_256K_PAGES 和 !PAGE_SIZE_256KB 意味着与 PPC_256K_PAGES && PAGE_SIZE_256KB 内核逻辑冲突
# Depends on: BLOCK [=y] && !PPC_256K_PAGES && !PAGE_SIZE_256KB
scripts/config --disable CONFIG_BTRFS_FS
# Depends on: BLOCK [=y] && BTRFS_FS [=y] 
scripts/config --disable CONFIG_BTRFS_FS_POSIX_ACL
# 额外参数扩展兼容
scripts/config --enable CONFIG_MMU
# Depends on: MMU [=y] && BLOCK [=y]
scripts/config --enable CONFIG_SWAP
# Depends on: CGROUPS [=y] && MEMCG [=y] && SWAP [=y]
scripts/config --enable CONFIG_MEMCG_SWAP
# Depends on: CGROUPS [=y] && MEMCG_SWAP [=y]
scripts/config --enable CONFIG_MEMCG_SWAP_ENABLED
scripts/config --enable CONFIG_BLK_DEV
scripts/config --enable CONFIG_BLK_DEV_LOOP
# 对杂项二进制文件格式的支持,可以让系统识别并运行非标准格式的可执行文件(例如通过 binfmt_misc 可直接运行脚本或虚拟格式的二进制)。
scripts/config --enable CONFIG_BINFMT_MISC
# 不确定需不需要的跨平台兼容项位置
# 为 x64 位内核添加对 32 位 (IA-32) 应用的兼容支持,使得旧的 32 位软件可以在 x64 位系统上正常运行,这里不需要。
scripts/config --enable CONFIG_X86_64
scripts/config --disable CONFIG_IA32_EMULATION

# 最后检查一遍
EXP_INFO='
CONFIG_USER_NS=
CONFIG_SBITMAP=
CONFIG_SRCU=
CONFIG_BLK_DEV_THROTTLING=
CONFIG_HAVE_PERF_EVENTS=
CONFIG_PERF_EVENTS=
CONFIG_CGROUP_PERF=
CONFIG_X86=
CONFIG_IA64=
CONFIG_SPARC64=
CONFIG_S390=
CONFIG_64BIT=
CONFIG_SYS_SUPPORTS_HUGETLBFS=
CONFIG_BROKEN=
CONFIG_HUGETLBFS=
CONFIG_HUGETLB_PAGE=
CONFIG_CGROUP_HUGETLB=
CONFIG_NET_SCHED=
CONFIG_NET_CLS_CGROUP=
CONFIG_CGROUP_NET_PRIO=
CONFIG_FAIR_GROUP_SCHED=
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_SYSFS=
CONFIG_SECURITY=
CONFIG_SECURITY_APPARMOR=
CONFIG_NFT_CT=
CONFIG_NF_TABLES=
CONFIG_NF_TABLES_IPV4=
CONFIG_NF_TABLES_IPV6=
CONFIG_NFT_FIB_IPV4=
CONFIG_NFT_FIB_IPV6=
CONFIG_NFT_FIB=
CONFIG_NF_NAT=
CONFIG_NFT_MASQ=
CONFIG_NFT_NAT=
CONFIG_NETDEVICES=
CONFIG_NET_CORE=
CONFIG_VXLAN=
CONFIG_VLAN_8021Q=
CONFIG_BRIDGE_VLAN_FILTERING=
CONFIG_NET_L3_MASTER_DEV=
CONFIG_IPVLAN=
CONFIG_MACVLAN=
CONFIG_PPC_256K_PAGES=
CONFIG_PAGE_SIZE_256KB=
CONFIG_BTRFS_FS=
CONFIG_BTRFS_FS_POSIX_ACL=
CONFIG_MMU=
CONFIG_SWAP=
CONFIG_MEMCG_SWAP=
CONFIG_MEMCG_SWAP_ENABLED=
CONFIG_BLK_DEV=
CONFIG_BLK_DEV_LOOP=
CONFIG_BINFMT_MISC=
CONFIG_X86_64=
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

# 清理 kernel obj 目录,避免历史构建污染
rm -fr $OUT/obj/KERNEL_OBJ

# 生成支持 docker 的 boot.img 经测试单独编译wifi会失效
# 看来需要联合编译
#make bootimage -j$(($(nproc)*2))
# 构建成功后进入目录,你就能看到 boot.img docker支持版文件
#echo $OUT
#ls -al $OUT/*.img

# 联合编译内核生成镜像,看机器性能了
# 第三次编译镜像就不会消耗太多时间大概9~22min左右就能结束,耐心点
brunch guacamole

# 查看得到 img 镜像
echo $OUT
ls -al $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip*

# 创建备份目录
# 防止后续配套系统镜像覆盖已经开启必要性支持的docker二代配套系统
# 防止后续修改内核导致系统无法开机可以随时通过fastboot和recovery刷机还原
rm -frv /root/workspace/custom_build_docker_2
mkdir -pv /root/workspace/custom_build_docker_2
mv -fv $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip* /root/workspace/custom_build_docker_2

接下来就是刷入自定义内核联合编译的 lineage-23.0 guacamole 的镜像了

# 手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
# 进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试,启用 Rooted debugging 模式,连接电脑  
# 连接电脑,手机提示是否允许,就允许
# 连接电脑 重启到 bootloader 模式
adb -d reboot bootloader
fastboot devices

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

# 然后 fastboot 模式界面音量键选择重启进入 recovery 恢复模式
# 恢复模式点击 apply update -> Apply from ADB
# 连接电脑,使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入
adb -d sideload /root/workspace/custom_build_docker_2/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,选择 Yes 切换 boot 分区

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 No 或者没有提示也别怕别哭,可以手动切换
注意观察 recovery 界面上的 Ativate slot 值,假设是 a
然后在 recovery 模式点击 Advanced -> Enter fastboot 进入 fastboot 模式
回到容器中,使用命令手动完成切换 boot 分区为 b 如下

# fastboot模式下连接的设备
fastboot devices
# 获取当前分区
fastboot getvar current-slot
# 设置b分区
fastboot set_active b
# 获取检查当前分区
fastboot getvar current-slot

然后再回到手机 fastboot 界面,点击 Enter recovery 回到 recovery 模式
然后在 recovery 模式点击 Advanced -> Reboot to recovery 重启 recovery 模式
注意观察 recovery 界面上的 Ativate slot 值,此时此刻应该是 b 了
重复刷机流程

# recovery 模式点击 apply update -> Apply from ADB
# 连接电脑,再次使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入另一个 boot 分区
adb -d sideload /root/workspace/custom_build_docker_2/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,这次选择 No 并在 recovery 模式点击 Advanced -> Reboot System now 重启系统

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 Yes 或者没有提示也别怕别哭,只是会切换 boot 分区重启到 recovery 模式
这时只要重新在 recovery 模式点击 Advanced -> Reboot System now 重启系统就可以了,等待重启需要有耐心

通过 magisk app 修改 boot.img

# 将 $OUT 的 boot.img 传入手机 /sdcard/
adb push /root/workspace/custom_build_docker_2/boot.img /sdcard/

通过 magisk app 修改 boot.img 得到 /sdcard/Download/magisk_patched-29000_i2Elj.img
检查 /sdcard/Download

adb shell ls -al /sdcard/Download

重命名 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 /root/workspace/custom_build_docker_2/

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

运行 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

Optional Features:
- CONFIG_CGROUP_HUGETLB: missing
- CONFIG_CFS_BANDWIDTH: 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

然后那个 linux docker 容器可以保留,省得以后测试需要用容器编译测试的时候还要反复执行安装环境。
当然你要删除也可以,我不阻止你
打开新的命令终端窗口执行以下命令即可删除编译容器(唉,虽然不太建议删除。毕竟以后如果想做做研究呢?)

# 停止并删除编译容器
docker stop android-build
docker rm -fv android-build

到此时此刻就手机就应该开启了全部功能,虽然仍不完美,但是已经非常贴近 linux docker 原生功能了,还在等什么呢?这就是生活!


测试运行 termux docker
连接电脑,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 app 直接运行 docker

# 安装 docker tmux
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

# 后台启用 dockerd 保持一个可以随时查看和交互的会话,可以使用 tmux 启动 tmux 会话
tmux new -s dockerd

# 保持当前环境,进入 Root
su -m

# 设置 Termux 环境(让 root 能找到二进制文件)
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock

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

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

# 挂载跨平台 binfmt_misc 支持
mkdir -p /proc/sys/fs/binfmt_misc
mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc
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 \
  --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 \
  --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 跨平台测试

# 保持当前环境,进入 Root
su -m

# 设置 Termux 环境(让 root 能找到二进制文件)
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock

# All emulators:
docker run --privileged --rm docker.io/tonistiigi/binfmt:master --install all
# Show currently supported architectures and installed emulators
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
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
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 ?

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 ?

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
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
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 主机之间的网络隔离,并直接使用主机的网络,可能会不安全?,总之二选一吧

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

此后使用docker都需要提前加载 termux 和 docker host 环境变量,这个需要注意一下。

# 保持当前环境,进入 Root
su -m

# 设置 Termux 环境(让 root 能找到二进制文件)
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock

docker version

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


其它关于termux的docker-compose和docker-buildx更新
安装用于校验的工具

pkg i jq perl git

# 保持当前环境,进入 Root
su -m

# 设置 Termux 环境(让 root 能找到二进制文件)
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock

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

mv -fv "${PREFIX}/tmp/${TARGET_FILE}" ${PREFIX}/bin/docker-compose
# Apply executable permissions to the binary
## 赋予执行权
chmod -v +x ${PREFIX}/bin/docker-compose
# create a symbolic link to ${PREFIX}/libexec/docker/cli-plugins/
# 创建插件目录和软链接
mkdir -pv ${PREFIX}/libexec/docker/cli-plugins/
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
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 "${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

mv -fv "${PREFIX}/tmp/${TARGET_FILE}" ${PREFIX}/bin/docker-buildx
# Apply executable permissions to the binary
## 赋予执行权
chmod -v +x ${PREFIX}/bin/docker-buildx
# create a symbolic link to ${PREFIX}/libexec/docker/cli-plugins/
# 创建插件目录和软链接
mkdir -pv ${PREFIX}/libexec/docker/cli-plugins/
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
docker-buildx version
docker buildx version

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

# 保持当前环境,进入 Root
su -m

# 设置 Termux 环境(让 root 能找到二进制文件)
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock

docker-compose version
docker-buildx version


开机自启动和容器化部署使用例子

写这个例子的原因是我一次部署1panel docker版本后创建其他容器发现的目录创建没有权限的问题
这个很难描述啊,就是android的分区很乱,我一开始用的/sdcard/
但是su环境中的docker容器竟然没有创建权限?这,这这。唉解决的过程很崎岖,所以才有了这一章节

  1. 就是假设 docker 主要的工作空间比如数据或者 compose 都存储在 Termux 的 $HOME/docker-workspace 目录那么就有如下创建流程,注意在非 root 模式下使用 su 执行命令,需要给环境变量引用前加上 \ ,比如 $ -> \$
su -c "
  export HOME=/data/data/com.termux/files/home
  export PREFIX=/data/data/com.termux/files/usr
  export PATH=\${PREFIX}/bin:\$PATH
  export DOCKER_HOST=unix://\${PREFIX}/var/run/docker.sock

  # 确保物理目录存在 (在 EXT4 分区)
  mkdir -p \$HOME/docker-workspace
  chmod -Rv 777 \$HOME/docker-workspace

  # 挂载 / 为可读写 (无视那个怪异的 ssh 路径)
  mount -o remount,rw /
"
  1. 假设部署 1panel 容器,需要创建一个目录并创建排版文件,如下
  • 其中注意按照自己的需求修改 environment 和 volumes
  • 挂载了 termux 主目录到容器的 /termux
  • 挂载了 /sdcard 目录到容器的 /sdcard
  • 1panel 默认端口:10086
  • 1panel 默认账户:1panel
  • 1panel 默认密码:1panel_password
  • 1panel 默认入口:entrance
mkdir -pv $HOME/docker-workspace/docker-arch-1panel
cat << '469138946ba5fa' | tee $HOME/docker-workspace/docker-arch-1panel/docker-compose.yml
services:
  1panel:
    cpu_shares: 256  # 默认 1024,设为 256 意味着在 CPU 繁忙时只给它 1/4 的算
    container_name: 1panel
    deploy:
      resources:
        limits: {cpus: 0,memory: '0'}
    environment:
      - TZ=Asia/Shanghai
      - HTTP_PROXY=http://192.168.255.253:7890
      - HTTPS_PROXY=http://192.168.255.253:7890
      - ALL_PROXY=socks5://192.168.255.253:7890
      - NO_PROXY='localhost,127.0.0.1,192.168.255.0/24'
      - http_proxy=http://192.168.255.253:7890
      - https_proxy=http://192.168.255.253:7890
      - all_proxy=socks5://192.168.255.253:7890
      - no_proxy='localhost,127.0.0.1,192.168.255.0/24'
      - DOCKER_API_VERSION=1.43
    image: docker.io/moelin/1panel:latest
    init: true # 解决杀不死的关键
    logging:
      driver: json-file
      options:
        max-size: 1m
    mem_swappiness: 0 # 尽量不使用 Swap,保护手机闪存
    networks:
      - 1panel-network
    platform: linux/arm64/v8
    ports:
      - 10086:10086
    privileged: true
    restart: always
    stop_signal: SIGKILL # 用信号强杀 (避开 docker-init 路径问题)
    stop_grace_period: 1s  # 缩短强杀等待时间
    volumes:
      - $PREFIX/var/run/docker.sock:/var/run/docker.sock
      - $PREFIX/var/lib/docker/volumes:/var/lib/docker/volumes
      - $HOME/docker-workspace/docker-arch-1panel/1panel:/opt/1panel
      - /sdcard:/sdcard
      - $HOME:/termux
networks:
  1panel-network:
    name: 1panel-network
    external: false
    driver: bridge
469138946ba5fa
  1. 假设此时 dockerd 服务正在后台运行,则运行容器的办法如下
cd $HOME/docker-workspace/docker-arch-1panel
su -m
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock
docker-compose up -d
exit
  1. 然而这又涉及到了一个问题,每次开机总不能反反复复,复复反反的执行繁琐的 dockerd 服务启动对吧,那么这个就是关键的开机自启动脚本。
    首先,你需要安装 Termux:boot app 打开,Termux:boot app 应用内有教程,然后切回到 termux 在 $HOME/.termux/boot/ 目录创建自启动脚本,比如名字就叫 start-docker.sh
    如此一来,手机每次开机重启都可以自动启动 dockerd 服务了
    以下是我自定义的脚本 ,请自行检查并根据需求自行修改替换
    如果设备开机后长时间(1min)未连接网络,你需要在联网后尝试手动执行这个脚本以启动dockerd服务
    我没尝试过sim卡数据流量,所以你要根据需求自己修改
    其它关于termux的docker-compose和docker-buildx更新
# 安装用于远程连接的工具 openssh(sshd)
pkg i openssh
mkdir -pv $HOME/.termux/boot
touch $HOME/.termux/boot/start-docker.sh
chmod -v +x $HOME/.termux/boot/start-docker.sh
cat << '469138946ba5fa' | tee $HOME/.termux/boot/start-docker.sh
#!/data/data/com.termux/files/usr/bin/sh
# 基础环境
termux-wake-lock
sshd

# 以 Root 身份初始化
su -c "
  # ================= 配置区 =================
  # 是否启用代理 (true/false)
  ENABLE_PROXY=false
  # 启动前等待网络的最长时间 (秒),设为 0 则不等待,无网直接退出
  WAIT_NETWORK_TIMEOUT=60

  # 性能配置
  LITTLE_RATIO=1.0  # 小核(0-3)
  GOLD_RATIO=0.6    # 中核(4-6)
  PRIME_RATIO=0.3   # 超大核(7)
  # =========================================

  # 导入 termux 环境
  export HOME=/data/data/com.termux/files/home
  export PREFIX=/data/data/com.termux/files/usr
  export PATH=\${PREFIX}/bin:\$PATH
  export DOCKER_HOST=unix://\${PREFIX}/var/run/docker.sock

  # --- [新增] 网络状态预检 ---
  echo '正在检查网络连接状态...'
  check_network() {
      # 尝试获取去往阿里DNS的路由,成功则说明有网
      ip route get 223.5.5.5 >/dev/null 2>&1
  }

  waited=0
  while ! check_network; do
      if [ \"\$waited\" -ge \"\$WAIT_NETWORK_TIMEOUT\" ]; then
          echo \"✘ 错误:等待网络超时 (\$WAIT_NETWORK_TIMEOUT 秒)。\"
          echo \"Docker 未启动。请在连接网络后手动重新运行此脚本。\"
          exit 1
      fi
      echo \"无网络连接,等待中... (\$waited/\$WAIT_NETWORK_TIMEOUT)\"
      sleep 2
      waited=\$((waited + 2))
  done
  echo \"✔ 网络已连接,准备启动 Docker...\"


  # --- CPU 频率优化 (WALT 抑制) ---
  # 既然内核开启了 WALT,通过 sysctl 压制它的积极性
  (
  while true; do
    for i in 0 1 2 3 4 5 6 7; do
      FREQS=\$(cat /sys/devices/system/cpu/cpu\$i/cpufreq/scaling_available_frequencies)
      MAX_F=\$(echo \$FREQS | awk '{print \$NF}')

      if [ \$i -le 3 ]; then R=\$LITTLE_RATIO;
      elif [ \$i -le 6 ]; then R=\$GOLD_RATIO;
      else R=\$PRIME_RATIO; fi

      FINAL_F=\$(echo \$FREQS | tr ' ' '\n' | awk -v max=\$MAX_F -v ratio=\$R 'BEGIN {target=max*ratio} \$1 <= target {f=\$1} END {print f}')

      if [ -n \"\$FINAL_F\" ]; then
        echo \$FINAL_F > /sys/devices/system/cpu/cpu\$i/cpufreq/scaling_max_freq
      fi
    done
    echo 95 > /proc/sys/kernel/sched_upmigrate
    echo 85 > /proc/sys/kernel/sched_downmigrate
    echo 0 > /proc/sys/kernel/sched_boost
    sleep 10
  done
  ) &

  # 禁用激进温控
  stop thermal-engine
  stop vendor.thermal-engine
  for i in 0 1 2 3 4 5 6 7; do
    echo 'schedutil' > /sys/devices/system/cpu/cpu\$i/cpufreq/scaling_governor
  done
  echo 342000000 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel

  # --- 核心清理增强版 ---
  echo 'Cleaning up old docker & containerd processes...'
  pkill -9 dockerd
  pkill -9 containerd
  pkill -9 containerd-shim

  # 清理所有可能残留的锁文件和 Socket
  find \$PREFIX/var/run -name \"*.pid\" -delete
  find \$PREFIX/var/run -name \"*.sock\" -delete
  # 彻底清理 containerd 残留 (解决 timeout 问题的关键)
  rm -rf \$PREFIX/var/run/docker/containerd/*
  rm -rf \$PREFIX/var/run/containerd/*
  rm -rf \$PREFIX/var/lib/containerd/*

  sleep 2

  # --- 挂载 cgroup ---
  umount -l /sys/fs/cgroup/* 2>/dev/null
  mount -t tmpfs -o mode=755 tmpfs /sys/fs/cgroup
  for subsys in devices net_cls memory cpu cpuacct cpuset freezer pids; do
    mkdir -p /sys/fs/cgroup/\$subsys
    mount -t cgroup -o \$subsys none /sys/fs/cgroup/\$subsys
  done
  if [ -d \"/sys/fs/cgroup/cpuset\" ]; then
      ln -sf /sys/fs/cgroup/cpuset/cpus /sys/fs/cgroup/cpuset/cpuset.cpus
      ln -sf /sys/fs/cgroup/cpuset/mems /sys/fs/cgroup/cpuset/cpuset.mems
  fi

  # --- 挂载 binfmt_misc ---
  mountpoint -q /proc/sys/fs/binfmt_misc || mount -t binfmt_misc binfmt_misc /proc/sys/fs/binfmt_misc

  # --- 网络配置基础 ---
  sysctl -w net.ipv4.ip_forward=1

  # --- 启动守护进程 ---
  echo 'Starting dockerd...'

  # 构建启动参数
  DOCKER_ARGS_USE_PROXY=\"--iptables=true --mtu 1300 --dns 8.8.8.8 --dns 1.1.1.1 --exec-opt native.cgroupdriver=cgroupfs\"
  DOCKER_ARGS_UNUSE_PROXY=\"--iptables=true --mtu 1300 --dns 223.5.5.5 --dns 114.114.114.114 --exec-opt native.cgroupdriver=cgroupfs\"

  if [ \"\$ENABLE_PROXY\" = true ]; then
    export http_proxy='http://192.168.255.253:40000'
    export https_proxy='http://192.168.255.253:40000'
    export all_proxy='socks5://192.168.255.253:40000'
    export no_proxy='localhost,127.0.0.1,192.168.255.0/24'
    echo '[Docker] 代理模式启动...'

    nohup dockerd \
      --http-proxy \"\${http_proxy}\" \
      --https-proxy \"\${https_proxy}\" \
      --no-proxy \"\${no_proxy}\" \
      \$DOCKER_ARGS_USE_PROXY \
      > \$PREFIX/tmp/dockerd.log 2>&1 &
    unset http_proxy https_proxy all_proxy
  else
    echo '[Docker] 普通模式启动...'
    nohup dockerd \$DOCKER_ARGS_UNUSE_PROXY > \$PREFIX/tmp/dockerd.log 2>&1 &
  fi

  # 等待启动
  sleep 5
  chmod 666 \$PREFIX/var/run/docker.sock
  docker restart \$(docker ps -qa) 2>/dev/null

  # --- [新增] 智能网络守护进程 (无损切换网关 + 守护 NAT) ---
  (
    echo \"启动智能网络守护进程...\"
    while true; do
      # 1. 智能探测真实网关 (不触碰 ARP,防止 WiFi 断连)
      # 获取去往 223.5.5.5 的真实路径
      ROUTE_INFO=\$(ip route get 223.5.5.5 2>/dev/null)

      # 提取 via 后面的 IP 和 dev 后面的接口
      REAL_GW=\$(echo \"\$ROUTE_INFO\" | awk '{for(i=1;i<=NF;i++) if(\$i==\"via\") print \$(i+1)}')
      REAL_DEV=\$(echo \"\$ROUTE_INFO\" | awk '{for(i=1;i<=NF;i++) if(\$i==\"dev\") print \$(i+1)}')

      if [ -n \"\$REAL_GW\" ] && [ -n \"\$REAL_DEV\" ]; then
          CURRENT_GW=\$(ip route show table main default | awk '{print \$3}')

          # 如果 Docker 用的网关不对,更新它
          if [ \"\$CURRENT_GW\" != \"\$REAL_GW\" ]; then
              echo \"检测到网络变动: 更新 Docker 网关 -> \$REAL_GW (\$REAL_DEV)\"
              ip route del default table main 2>/dev/null
              ip route add default via \$REAL_GW dev \$REAL_DEV table main
          fi
      fi

      # 2. 守护 NAT 规则 (放行 172.16.0.0/12 所有私有网段)
      if ! iptables -t nat -C POSTROUTING -s 172.16.0.0/12 -j MASQUERADE 2>/dev/null; then
          iptables -t nat -I POSTROUTING -s 172.16.0.0/12 -j MASQUERADE
      fi

      # 3. 守护策略路由 (锁定 main 表)
      if ! ip rule show | grep -q \"lookup main\"; then
          ip rule add from all lookup main pref 30000
      fi

      sleep 5
    done
  ) &

  # --- AI 进程核心绑定 ---
  (
    echo \"开始监控并锁定 AI 进程核心...\"
    for i in \$(seq 1 10); do
      for name in ollama open_webui; do
        for pid in \$(pgrep -f \$name); do
          taskset -ap 0x7F \$pid >/dev/null 2>&1
        done
      done
      sleep 6
    done
  ) &
"
echo "脚本执行完毕。Docker 已配置为仅在网络可用时启动。"
469138946ba5fa

然后注意运行 docker 还是 compose 和 buildx 都需要执行这一步骤
哎呀终于写完了,这次可算是全面一些了

su -m
export HOME=/data/data/com.termux/files/home
export PREFIX=/data/data/com.termux/files/usr
export PATH=${PREFIX}/bin:$PATH
export DOCKER_HOST=unix://${PREFIX}/var/run/docker.sock

docker version
docker-compose version
docker-buildx version


Android16尝试开启KVM失败的例子(不用试了,唉)

下面的步骤是开启kvm扩展功能失败的尝试,这里只是留个记录
回到上次那个容器中,如果你保留了那个容器的话,没有保留也没关系,可以按照以下步骤

执行环境的部署,直到能对接到以下这个步骤即可,我就不重复了
我直接进入容器,并加载用于编译的环境变量文件

# 进入编译容器
docker exec -it android-build bash

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

# 如果你的容器是按照步骤执行的话,容器内的目录应该是不变的
cd /root/workspace/android-build/lineage-23.0

# 同步源码?
repo sync

# 跑一次官方推荐的垃圾回收命令即可
repo sync --auto-gc

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

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

# 编译镜像 croot brunch guacamole
croot

kvm项可以不开启,开启也没用,我失败了,我总以为内核扩展功能开启操作同理,唉可是始终没用 /dev/kvm
再次回到容器进入内核路径,根据上述信息,查找内核配置文件路径

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

# 这时就要备份已经修改的内核配置文件
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig arch/arm64/configs/vendor/sm8150-perf_defconfig_docker_2

# 复制已经修改的内核配置文件到当前目录
cp -fv arch/arm64/configs/vendor/sm8150-perf_defconfig_docker_2 .config

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

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

- CONFIG_VSOCKETS [=y]
  - NET [=y]
    - Networking support [=y]
  - VSOCKETS [=y]
    - Networking support (NET [=y])
      - Networking options
        - Virtual Socket protocol [=y]
- CONFIG_KVM [=y]
  - PCI [=y]
    - Bus options (PCI etc.)
      - PCI support [=y]
  - PCI_MSI [=y]
    - Bus options (PCI etc.)
      - PCI support (PCI [=y])
        - Message Signaled Interrupts (MSI and MSI-X) [=y]
  - X86_32 [=n]
  - SMP [=y]
    - Processor type and features
      - Symmetric multi-processing support [=y]
  - X86_EXTENDED_PLATFORM [=y]
    - Processor type and features
      - Support for extended (non-PC) x86 platforms [=y]
  # Depends on: X86_32 [=n] && SMP [=y] && X86_EXTENDED_PLATFORM [=y]
  - X86_32_NON_STANDARD [=n]
    - Processor type and features
      - Support non-standard 32-bit SMP architectures [=n]
  # Depends on: X86_32 [=n] && !SMP [=y] && !X86_32_NON_STANDARD [=n]
  - X86_UP_APIC [=n]
    - Processor type and features
      - Local APIC support on uniprocessors [=n]
  - 64BIT [=y]
  - X86_64 [=y]
  # Depends on: X86_64 [=y] || SMP [=y] || X86_32_NON_STANDARD [=n] || X86_UP_APIC [=n] || PCI_MSI [=y]
  - X86_LOCAL_APIC [=y]
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  - NET [=y]
    - Networking support [=y]
  - ARCH_USES_GETTIMEOFFSET [=n]
  - GENERIC_CLOCKEVENTS [=y]
  # Depends on: !ARCH_USES_GETTIMEOFFSET [=n] && GENERIC_CLOCKEVENTS [=y] 
  - HIGH_RES_TIMERS [=y]
    - General setup
      - Timers subsystem
        - High Resolution Timer Support [=y]
  - X86 [=y]
  - HAVE_KVM [=y]
  # Depends on: HAVE_KVM [=y] || X86 [=y]
  - VIRTUALIZATION [=y]
    - Virtualization [=y]
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  # Depends on: VIRTUALIZATION [=y] && HAVE_KVM [=y] && HIGH_RES_TIMERS [=y] && NET [=y] && MULTIUSER [=y] && X86_LOCAL_APIC [=y]
  - KVM [=y]
    - Virtualization (VIRTUALIZATION [=y])
      - Kernel-based Virtual Machine (KVM) support [=y]
- CONFIG_VHOST_NET [=y]
  - NET [=y]
    - Networking support [=y]
  - NETDEVICES [=y]
    - Device Drivers
      - Network device support [=y]
  - NET_CORE [=y]
    - Device Drivers
      - Network device support [=y]
        - Network core driver support [=y]
  - INET [=y]
    - Networking support [=y]
      - Networking options [=y]
        - TCP/IP networking [=y]
  # Depends on: NETDEVICES [=y] && NET_CORE [=y]
  - TAP [=y]
  # Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y]
  - TUN [=y]
    - Device Drivers
      - Network device support (NETDEVICES [=y])
        - Network core driver support (NET_CORE [=y])
          - Universal TUN/TAP device driver support [=y]
  - EVENTFD [=y]
    - General setup
      - Configure standard kernel features (expert users) (EXPERT [=y])
        - Enable eventfd() system call [=y]
  - X86 [=y]
  - HAVE_KVM [=y]
  # Depends on: HAVE_KVM [=y] || X86 [=y]
  - VIRTUALIZATION [=y]
    - Virtualization [=y]
  - MULTIUSER [=y]
    - General setup
      - Configure standard kernel features [=y]
        - Multiple users, groups and capabilities support [=y]
  # Depends on: VIRTUALIZATION [=y] && NET [=y] && EVENTFD [=y] && (TUN [=y] || !TUN [=y]) && (TAP [=n] || !TAP [=n])
  - VHOST_NET [=y]
    - Virtualization (VIRTUALIZATION [=y])
      - Host kernel accelerator for virtio net [=y]
- CONFIG_VIRTUALIZATION [=y]
  - X86 [=y]
  - HAVE_KVM [=y]
  # Depends on: HAVE_KVM [=y] || X86 [=y]
  - VIRTUALIZATION [=y]
    - Virtualization [=y]
- CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT [=y]
  - KVM_GENERIC_DIRTYLOG_READ_PROTECT [=y]
- CONFIG_VIRTIO [=y]
  - VIRTIO [=y]
- CONFIG_NO_IOMEM [=n]
  - NO_IOMEM [=n]
- CONFIG_HAS_IOMEM [=y]
  - HAS_IOMEM [=y]
- CONFIG_NO_DMA [=n]
  - NO_DMA [=n]
- CONFIG_HAS_DMA [=y]
  - HAS_DMA [=y]
# Depends on: HAS_IOMEM [=y] && HAS_DMA [=y]
- CONFIG_VIRTIO_MMIO [=y]
  - VIRTIO_MMIO [=y]
    - Device Drivers
      - Virtio drivers
        - Platform bus driver for memory mapped virtio devices [=y]
- CONFIG_ARM64_VHE [=y]
  - ARM64_VHE [=y]
- CONFIG_ARM_VIRT_EXT [=y]
  - ARM_VIRT_EXT [=y]

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

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

启用扩展功能

# kvm条件
scripts/config --enable CONFIG_VSOCKETS
scripts/config --enable CONFIG_PCI
scripts/config --enable CONFIG_PCI_MSI
scripts/config --enable CONFIG_X86_32
scripts/config --enable CONFIG_X86_EXTENDED_PLATFORM
# Depends on: X86_32 [=n] && SMP [=y] && X86_EXTENDED_PLATFORM [=y]
scripts/config --disable CONFIG_X86_32_NON_STANDARD
# Depends on: X86_32 [=n] && !SMP [=y] && !X86_32_NON_STANDARD [=n]
scripts/config --disable CONFIG_X86_UP_APIC
# Depends on: X86_64 [=y] || SMP [=y] || X86_32_NON_STANDARD [=n] || X86_UP_APIC [=n] || PCI_MSI [=y]
scripts/config --enable CONFIG_X86_LOCAL_APIC
scripts/config --disable CONFIG_ARCH_USES_GETTIMEOFFSET
scripts/config --enable CONFIG_GENERIC_CLOCKEVENTS
# Depends on: !ARCH_USES_GETTIMEOFFSET [=n] && GENERIC_CLOCKEVENTS [=y] 
scripts/config --enable CONFIG_HIGH_RES_TIMERS
scripts/config --enable CONFIG_HAVE_KVM
# Depends on: HAVE_KVM [=y] || X86 [=y]
scripts/config --enable CONFIG_VIRTUALIZATION
# Depends on: VIRTUALIZATION [=y] && HAVE_KVM [=y] && HIGH_RES_TIMERS [=y] && NET [=y] && MULTIUSER [=y] && X86_LOCAL_APIC [=y]
scripts/config --enable CONFIG_KVM
# Depends on: NETDEVICES [=y] && NET_CORE [=y]
scripts/config --enable CONFIG_TAP
# Depends on: NETDEVICES [=y] && NET_CORE [=y] && INET [=y]
scripts/config --enable CONFIG_TUN
scripts/config --enable CONFIG_EVENTFD
# Depends on: VIRTUALIZATION [=y] && NET [=y] && EVENTFD [=y] && (TUN [=y] || !TUN [=y]) && (TAP [=n] || !TAP [=n])
scripts/config --enable CONFIG_VHOST_NET
# 完全没找到 CONFIG_KVM_GENERIC 难道是改名字了?CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
# grep -r CONFIG_KVM_GENERIC * ; grep -r "KVM_GENERIC" arch/arm64/Kconfig
scripts/config --enable CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT
scripts/config --enable CONFIG_VIRTIO
scripts/config --disable CONFIG_NO_IOMEM
scripts/config --enable CONFIG_HAS_IOMEM
scripts/config --disable CONFIG_NO_DMA
scripts/config --enable CONFIG_HAS_DMA
# Depends on: HAS_IOMEM [=y] && HAS_DMA [=y]
scripts/config --enable CONFIG_VIRTIO_MMIO
# arm64 虚拟,能查到源码里面有,但是 .config 没有提供的参数
# grep -r CONFIG_ARM64_VHE * ; grep -r "ARM64_VHE" arch/arm64/Kconfig
scripts/config --enable CONFIG_ARM64_VHE
# arm 虚拟,仅查到了一个源码含有,其他源码都关闭了此项且 .config 没有提供参数,我试试开启看看
# grep -r CONFIG_ARM_VIRT_EXT * ; grep -r "ARM_VIRT_EXT" arch/arm64/Kconfig
scripts/config --enable CONFIG_ARM_VIRT_EXT

# 最后检查一遍
EXP_INFO='
CONFIG_VSOCKETS=
CONFIG_PCI=
CONFIG_PCI_MSI=
CONFIG_X86_32=
CONFIG_X86_EXTENDED_PLATFORM=
CONFIG_X86_32_NON_STANDARD=
CONFIG_X86_UP_APIC=
CONFIG_X86_LOCAL_APIC=
CONFIG_ARCH_USES_GETTIMEOFFSET=
CONFIG_GENERIC_CLOCKEVENTS=
CONFIG_HIGH_RES_TIMERS=
CONFIG_HAVE_KVM=
CONFIG_VIRTUALIZATION=
CONFIG_KVM=
CONFIG_TAP=
CONFIG_TUN=
CONFIG_EVENTFD=
CONFIG_VHOST_NET=
CONFIG_KVM_GENERIC_DIRTYLOG_READ_PROTECT=
CONFIG_VIRTIO=
CONFIG_NO_IOMEM=
CONFIG_HAS_IOMEM=
CONFIG_NO_DMA=
CONFIG_HAS_DMA=
CONFIG_VIRTIO_MMIO=
CONFIG_ARM64_VHE=
CONFIG_ARM_VIRT_EXT=
'

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

# 清理 kernel obj 目录,避免历史构建污染
rm -fr $OUT/obj/KERNEL_OBJ

# 生成支持 docker 的 boot.img 经测试单独编译wifi会失效
# 看来需要联合编译
#make bootimage -j$(($(nproc)*2))
# 构建成功后进入目录,你就能看到 boot.img docker支持版文件
#echo $OUT
#ls -al $OUT/*.img

# 联合编译内核生成镜像,看机器性能了
# 第四次编译镜像就不会消耗太多时间大概9~22min左右就能结束,耐心点
brunch guacamole

# 查看得到 img 镜像
echo $OUT
ls -al $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip*

# 创建备份目录
# 防止后续配套系统镜像覆盖已经开启必要性支持的docker三代配套系统
# 防止后续修改内核导致系统无法开机可以随时通过fastboot和recovery刷机还原
rm -frv /root/workspace/custom_build_docker_3
mkdir -pv /root/workspace/custom_build_docker_3
mv -fv $OUT/dtbo.img* $OUT/vbmeta.img* $OUT/boot.img* $OUT/lineage-23.0-*-UNOFFICIAL-guacamole.zip* /root/workspace/custom_build_docker_3

接下来就是刷入自定义内核联合编译的 lineage-23.0 guacamole 的镜像了

# 手机点击 设置 -> 关于手机 -> 点击 build number 5次启用开发者模式
# 进入 设置 -> 系统 -> 开发者设置,设置 oem 解锁,启用 usb 调试,启用 Rooted debugging 模式,连接电脑  
# 连接电脑,手机提示是否允许,就允许
# 连接电脑 重启到 bootloader 模式
adb -d reboot bootloader
fastboot devices

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

# 然后 fastboot 模式界面音量键选择重启进入 recovery 恢复模式
# 恢复模式点击 apply update -> Apply from ADB
# 连接电脑,使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入
adb -d sideload /root/workspace/custom_build_docker_3/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,选择 Yes 切换 boot 分区

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 No 或者没有提示也别怕别哭,可以手动切换
注意观察 recovery 界面上的 Ativate slot 值,假设是 a
然后在 recovery 模式点击 Advanced -> Enter fastboot 进入 fastboot 模式
回到容器中,使用命令手动完成切换 boot 分区为 b 如下

# fastboot模式下连接的设备
fastboot devices
# 获取当前分区
fastboot getvar current-slot
# 设置b分区
fastboot set_active b
# 获取检查当前分区
fastboot getvar current-slot

然后再回到手机 fastboot 界面,点击 Enter recovery 回到 recovery 模式
然后在 recovery 模式点击 Advanced -> Reboot to recovery 重启 recovery 模式
注意观察 recovery 界面上的 Ativate slot 值,此时此刻应该是 b 了
重复刷机流程

# recovery 模式点击 apply update -> Apply from ADB
# 连接电脑,再次使用 adb sideload 将 lineage-23.0 guacamole 系统固件刷入另一个 boot 分区
adb -d sideload /root/workspace/custom_build_docker_3/lineage-23.0-*-UNOFFICIAL-guacamole.zip

应该会有提示,这次选择 No 并在 recovery 模式点击 Advanced -> Reboot System now 重启系统

To install additional packages, you need to reboot recovery first
Do you want to reboot to recovery now?

如果点错了点了 Yes 或者没有提示也别怕别哭,只是会切换 boot 分区重启到 recovery 模式
这时只要重新在 recovery 模式点击 Advanced -> Reboot System now 重启系统就可以了,等待重启需要有耐心

通过 magisk app 修改 boot.img

# 将 $OUT 的 boot.img 传入手机 /sdcard/
adb push /root/workspace/custom_build_docker_3/boot.img /sdcard/

通过 magisk app 修改 boot.img 得到 /sdcard/Download/magisk_patched-29000_i2Elj.img

adb shell ls -al /sdcard/Download/

重命名 magisk_patched-28100_AivWF.img 为 boot-docker-3_magisk_patched.img (我重命名了,生成的名字结尾是随机的,我觉得不好记)

adb shell "mv -fv /sdcard/Download/magisk_patched-*.img /sdcard/boot-docker-3_magisk_patched.img"
# 检查文件是否命名成功
adb shell ls -al /sdcard/Download/ /sdcard/ 
# 将 boot-docker-3_magisk_patched.img 文件导出到 android 镜像存放目录
adb pull /sdcard/boot-docker-3_magisk_patched.img /root/workspace/custom_build_docker_3/

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

回到 termux 检查 /dev/kvm 虚拟设备是否存在,唉我失败了。啥也没有白折腾。

su -c 'ls /dev/kvm'

参考&感谢

kernel-a16-raphael-antigravity-kernel-with-docker-support-for-raphael.4769126
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
Termux:boot app
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