LuoTianyi_HOLOMAIN/Tailscale + SSH 远程开发操作指南.md
Rdzleo d6a1e28975 远程开发环境升级:GitHub SSH 推送落地 + SMB 方案验证 + ESP32 串口优化
源代码管理 / 远程仓库(本次核心):
- 新增 GitHub 私有仓库 Leo-z8/OrangePi_CM5_Project(镜像 Android 13 SDK 关键路径)
- 本地 Git 仓库首次推送成功,远端 commit: c79995a30
- 白名单 .gitignore 追加通配符:device/rockchip/*/*/preinstall/*.apk
- 2 个 120MB camera360.apk 从 Git 历史排除(超 GitHub 100MB 限制,需另存备份)
- 认证方式切换为 SSH ed25519(ssh.github.com:443),永久免密,不依赖 Clash
- PAT 一次性推送后已撤销,凭证文件已清理

文档更新(Tailscale + SSH 远程开发操作指南 → v3.1):
- 4.5 新增 macOS SMB 挂载方案,并完整对比 Remote-SSH 在驱动开发场景下的差异
- 8.7 改写 GitHub 推送章节,SSH 为主推荐方案,HTTPS+PAT 降为应急备选
- 8.10 新增首次推送踩坑实录:100MB 单文件限制、git rev-list 去重陷阱、rwnd 瓶颈
- 8.11 新增实测数据:.git 774MB / 96,600 文件 / SSH 4-6 MiB/s 稳定无抖动
- 8.9 备份策略明确列出需另存的大文件清单

ESP32 HOLOMAIN 代码(02_HOLOMAIN_香橙派CM5开发板代码.ino):
- processCommand 响应统一走 Serial(USB CDC),不再回写 SerialLinux(UART0)
- 修复 Android 高频灯光命令占满 UART0 TX 导致 SORC_xxx/SO_BTx 刷卡数据延迟/丢失的问题

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 18:14:10 +08:00

1854 lines
60 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Tailscale + SSH 远程开发操作指南
## 文档概述
Mac 电脑通过 Tailscale 跨网络 SSH 连接 Windows 电脑上的 Linux 虚拟机VMware实现远程 Android 底层开发。
## 当前环境信息2026-04-17 已验证)
| 项目 | 信息 |
|------|------|
| Mac 电脑 | macOS, ClashX Pro (VPN), Tailscale |
| Windows 电脑 | VMware Workstation 17, Clash for Windows v0.19.10 |
| Linux 虚拟机 | Ubuntu 20.04 LTS, VMware 桥接模式 |
| 虚拟机用户 | zhangwenqi |
| Tailscale IP | 100.123.82.91 |
| 虚拟机局域网 IP | 192.168.6.60 |
| SSH 密钥 | Mac ~/.ssh/id_ed25519 已部署到虚拟机 |
| Docker | 28.1.1 |
| **Radxa CM5 环境** | Docker 镜像 android-builder:12.x (6.48GB, Ubuntu 20.04 基底)SDK 已编译验证 |
| **OrangePi CM5 环境** | Docker 镜像 android-builder-orangepi:13.x (待构建, Ubuntu 22.04 基底)SDK 已合并待解压 |
| 磁盘 | 700GB 虚拟磁盘,剩余空间足够双环境并行 |
---
# 第一部分:网络架构
## 1.1 整体架构
```
Mac (ClashX Pro VPN + Tailscale)
|
| Tailscale P2P (100.x.x.x)
|
Linux 虚拟机 (Tailscale, IP: 100.123.82.91)
|
| VMware 桥接 (192.168.6.60)
|
Windows (Clash for Windows, 端口 7890)
```
## 1.2 各设备职责
- Mac: 开发主机VPN 翻墙 + SSH 远程开发
- Windows: 宿主机,运行 VMware 虚拟机 + Clash 代理
- Linux 虚拟机: 编译服务器Docker + Android SDK 编译环境
---
# 第二部分ClashX Pro 与 Tailscale 共存配置(关键)
Mac 上 ClashX Pro增强模式/TUN与 Tailscale 存在两个冲突,必须同时解决。
## 2.1 问题一:增强模式流量劫持
ClashX Pro 增强模式创建 TUN 虚拟网卡拦截所有流量Tailscale 的 WireGuard UDP 流量也被劫持,导致 Tailscale 连不上。
**解决方法:** 在 ClashX Pro 代理配置文件的 rules 最前面添加直连规则。
配置文件路径: `~/.config/clash/你的订阅配置.yaml`
`rules:` 下方、第一条规则之前插入:
```yaml
rules:
- PROCESS-NAME,tailscaled,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT,no-resolve
- IP-CIDR6,fd7a:115c:a1e0::/48,DIRECT,no-resolve
- DOMAIN-SUFFIX,tailscale.com,DIRECT
- DOMAIN-SUFFIX,login.tailscale.com,DIRECT
# ... 原有规则保持不变 ...
```
各规则作用:
- `PROCESS-NAME,tailscaled,DIRECT` → Tailscale 进程所有流量直连(最关键)
- `IP-CIDR,100.64.0.0/10,DIRECT` → Tailscale 内网 IP 段直连
- `IP-CIDR6,fd7a:115c:a1e0::/48,DIRECT` → Tailscale IPv6 段直连
- `DOMAIN-SUFFIX,tailscale.com,DIRECT` → Tailscale 控制服务器直连
- `DOMAIN-SUFFIX,login.tailscale.com,DIRECT` → Tailscale 认证直连
## 2.2 问题二MagicDNS 劫持域名解析
Tailscale 默认开启 MagicDNS将系统 DNS 改为 100.100.100.100,与 ClashX Pro 增强模式的 fake-ip DNS198.18.0.2)冲突。
典型表现:浏览器能访问 YouTube但 Claude Code 等终端应用无法连接。
**解决方法:** 关闭 Tailscale DNS 接管。
操作步骤:
1. 点击 Mac 菜单栏 Tailscale 图标
2. 进入 Preferences偏好设置
3. 找到 "Use Tailscale DNS Settings" → 关闭
或通过管理后台:浏览器打开 https://login.tailscale.com/admin/dns → 关闭 MagicDNS
## 2.3 订阅更新覆盖问题
ClashX Pro 订阅更新会覆盖配置文件Tailscale 直连规则会丢失。
**应对:** 每次订阅更新后,重新在 `rules:` 下插入 2.1 中的 5 条规则,然后 ClashX Pro 菜单 → 配置 → 重新加载配置。
备份规则片段方便粘贴:
```
- PROCESS-NAME,tailscaled,DIRECT
- IP-CIDR,100.64.0.0/10,DIRECT,no-resolve
- IP-CIDR6,fd7a:115c:a1e0::/48,DIRECT,no-resolve
- DOMAIN-SUFFIX,tailscale.com,DIRECT
- DOMAIN-SUFFIX,login.tailscale.com,DIRECT
```
## 2.4 验证清单
1. 开启 ClashX Pro 增强模式 + 选择代理节点
2. 开启 Tailscale
3. 浏览器访问 YouTube → VPN 正常
4. 终端 `ssh zhangwenqi@100.123.82.91` → Tailscale SSH 正常
5. Claude Code 对话 → DNS 解析正常
失败排查:
- 第 3 步失败 → 检查代理节点
- 第 4 步失败 → 检查 rules 中 Tailscale 直连规则
- 第 5 步失败 → 检查 Tailscale DNS Settings 是否已关闭
---
# 第三部分Linux 虚拟机环境配置
## 3.1 Tailscale 安装
```bash
# 安装
curl -fsSL https://tailscale.com/install.sh | sh
# 启动并认证(浏览器打开输出的链接登录)
sudo tailscale up
# 查看分配的 IP
tailscale ip -4
```
## 3.2 SSH 服务
```bash
# 安装(如未安装)
sudo apt update && sudo apt install openssh-server -y
# 启动
sudo systemctl enable --now ssh
# 检查状态
sudo systemctl status ssh
```
## 3.3 Docker 安装
```bash
# 添加 Docker 清华镜像源
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/ubuntu focal stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# 安装
sudo apt-get update -y
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# 当前用户加入 docker 组(免 sudo
sudo usermod -aG docker $USER
# 需要重新登录生效
```
## 3.4 Docker 镜像加速(国内必须配置)
Docker Hub 在国内无法直接访问,需要配置镜像加速器:
```bash
sudo tee /etc/docker/daemon.json > /dev/null << 'EOF'
{
"registry-mirrors": [
"https://docker.1ms.run",
"https://docker.xuanyuan.me",
"https://docker.m.daocloud.io"
]
}
EOF
sudo systemctl daemon-reload && sudo systemctl restart docker
```
注意:镜像加速器地址可能失效,届时搜索"Docker 镜像加速 2026"获取最新可用地址。
## 3.5 构建 Android 12 编译镜像
Dockerfile 位于虚拟机 `~/Radxa_CM5/docker/Dockerfile`,内容基于 Radxa 官方文档,使用清华镜像源。
```bash
cd ~/Radxa_CM5/docker
sudo docker build -t android-builder:12.x .
```
构建完成验证:
```bash
sudo docker run --rm android-builder:12.x bash -c \
'java -version 2>&1; python3 --version; gcc --version | head -1; which repo'
```
预期输出:
- Java: openjdk 1.8.0
- Python: 3.8.x
- GCC: 9.4.0
- Repo: /usr/local/bin/repo
### 与官方 Dockerfile 的差异(重要)
当前镜像**缺少官方 Dockerfile 中的 5 套 Linaro 交叉编译工具链 COPY**
```
gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf → /opt/ 和 /opt/toolchains/
gcc-linaro-aarch64-none-elf-4.8-2013.11_linux → /opt/ 和 /opt/toolchains/
gcc-arm-none-eabi-6-2017-q2-update → /opt/toolchains/
gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu → /opt/toolchains/
gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf → /opt/toolchains/
```
**原因:** 这些工具链需要单独下载(官方文档未提供下载地址),放到 Dockerfile 同目录才能 COPY。
**影响评估:**
- Radxa Android SDK 的 `prebuilts/` 目录自带编译所需工具链
- 编译脚本 `build.sh` 优先使用 SDK 内的工具链
- 这些 Linaro 工具链主要给 U-Boot 和 kernel **单独编译**用
**编译时如果报错找不到工具链,按以下方式排查修复:**
1. 确认报错中缺少的具体工具链名称
2. 搜索 Linaro 官网下载对应版本https://releases.linaro.org/components/toolchain/binaries/
3. 解压到 Docker 容器的 `/opt/toolchains/` 目录:
```bash
# 在容器内
cd /opt/toolchains
wget <工具链下载地址>
tar -xf <工具链压缩包>
```
4. 或者将工具链放到 `~/Radxa_CM5/docker/` 目录,取消 Dockerfile 中 COPY 行注释后重新构建镜像
## 3.6 Radxa CM5 Android 12 编译环境(基于 Ubuntu 20.04
### 3.6.1 解压 SDK
```bash
cd ~/Radxa_CM5/SDK_Android
tar -xzf radxa_android_sdk_backup.tar.gz
# 解压后目录为 radxa-android-sdk/,耗时视磁盘速度而定
```
### 3.6.2 编译前必须修复的问题(重要)
SDK 存在两个已知问题,必须在编译前修复,否则编译会失败。
**问题一GMS 引用不存在lunch 阶段报错)**
错误信息:`vendor/partner_gms/products/gms.mk does not exist`
原因RadxaCM5.mk 引用了 Google GMS 包Google Play 服务),但开源 SDK 不包含 GMS需 Google 授权)。
修复:注释掉 GMS 引用行。
```bash
cd ~/Radxa_CM5/SDK_Android/radxa-android-sdk
sed -i 's/$(call inherit-product, vendor\/partner_gms\/products\/gms.mk)/#$(call inherit-product, vendor\/partner_gms\/products\/gms.mk)/' device/rockchip/rk3588/RadxaCM5/RadxaCM5.mk
```
验证:
```bash
grep "gms" device/rockchip/rk3588/RadxaCM5/RadxaCM5.mk
# 应看到该行前面有 # 注释符
```
注意:注释 GMS 后编译出的系统不含 Google Play 商店和 Google 服务,其他功能不受影响。
**问题二:缺少 RadxaCM5.config 内核配置文件kernel 编译阶段报错)**
错误信息:`No configuration exists for this target on this architecture - RadxaCM5.config`
原因BoardConfig.mk 指定 `PRODUCT_KERNEL_CONFIG := rockchip_defconfig android-11.config RadxaCM5.config`,但 `kernel-5.10/kernel/configs/` 目录下没有 `RadxaCM5.config` 文件。
修复:参考 rock5b.config 创建 CM5 内核配置文件。
```bash
cat > kernel-5.10/kernel/configs/RadxaCM5.config << 'EOF'
CONFIG_SND_SOC_ES8316=y
CONFIG_RTL8852BE=m
CONFIG_BT_RTKBTUSB=y
CONFIG_SENSORS_PWM_FAN=y
CONFIG_TOUCHSCREEN_GT9XX=y
CONFIG_TOUCHSCREEN_FTS=y
CONFIG_TOUCHSCREEN_FTS_RADXA=y
CONFIG_DRM_PANEL_RADXA=y
CONFIG_DRM_PANEL_RASPBERRYPI_TC358762=y
CONFIG_ROCKPI_MCU=y
CONFIG_VIDEO_IMX219=y
EOF
```
### 3.6.3 编译前增大 Swap防止 OOM重要
Android 全量编译内存峰值可超过 20GB虚拟机默认 Swap 仅 1GB编译到 99% 时会因内存不足被 OOM Killer 杀死进程。
```bash
# 创建 8GB Swap 文件
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 写入 fstab 永久生效
echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
# 验证(应显示 9GB 左右 Swap
free -h | grep -i swap
```
同时建议 VMware 虚拟机内存分配 **16GB 以上**20GB+ 更佳)。
### 3.6.4 进入 Docker 编译环境
```bash
# 注意挂载的是解压后的 radxa-android-sdk 目录
sudo docker run -it \
--name android-build \
-v ~/Radxa_CM5/SDK_Android/radxa-android-sdk:/workspace \
-w /workspace \
android-builder:12.x \
bash
```
### 3.6.5 执行编译
```bash
# 在 Docker 容器内执行
source build/envsetup.sh
lunch RadxaCM5-userdebug
# 方法一:全量编译(推荐,约 5 小时)
# 如果虚拟机内存 ≤ 20GB建议用 -j8 限制线程数减少内存峰值
./build.sh -AUCKup
# 方法二:如果 build.sh 因 OOM 中途失败,用 make 继续(会复用已编译缓存)
make -j8
```
编译参数说明:`-A` AOSP、`-U` U-Boot、`-C` Config、`-K` Kernel、`-u` update.img、`-p` 打包
编译过程中 `Build sandboxing disabled due to nsjail error` 是正常提示Docker 容器内不支持 nsjail 沙箱,不影响编译。
### 3.6.6 编译后打包镜像
如果使用 `make -j8` 单独编译 AOSP非 build.sh需要手动打包
```bash
# 在容器内执行
./mkimage.sh
```
### 3.6.7 验证编译结果
```bash
ls -lh rockdev/Image-RadxaCM5/
```
预期镜像文件:
| 文件 | 说明 |
|------|------|
| MiniLoaderAll.bin | Bootloader 加载器 |
| idbloader.img | IDB Loader |
| uboot.img | U-Boot |
| boot.img | Boot 镜像(内核+ramdisk |
| recovery.img | Recovery 模式镜像 |
| super.img | 系统分区system+vendor+odm约 1.6GB |
| dtbo.img | 设备树 Overlay |
| resource.img | 内核资源 |
### 3.6.8 退出和重新进入容器
```bash
# 退出容器
exit
# 重新进入已创建的容器
sudo docker start -ai android-build
```
### 3.6.9 烧录到开发板
编译完成的镜像在虚拟机 `~/Radxa_CM5/SDK_Android/radxa-android-sdk/rockdev/Image-RadxaCM5/` 目录。
拿到 CM5 开发板后:
1. 将镜像文件拷贝到 Windows
2. 使用 **RKDevTool**(瑞芯微官方烧录工具)烧录
3. 开发板进入 Loader 模式(按住 Recovery 按键上电)
4. 在 RKDevTool 中加载各 img 文件烧录
## 3.7 OrangePi CM5 Android 13 编译环境(基于 Ubuntu 22.04 Docker
OrangePi CM5 BaseRK3588S使用 Android 13 源码,与 Radxa CM5 的 Android 12 并行存在。
为避免污染主机环境,使用独立的 Docker 镜像(基于 Ubuntu 22.04,对齐 OrangePi 官方推荐环境)。
### 3.7.1 官方参考文档
- 《OrangePi_CM5_Base_RK3588S_用户手册_v1.3.pdf》第 7 章Android 13 源码的编译方法
- 《OrangePi_CM5_Base_Tablet_RK3588S_用户手册_v1.0.pdf》
### 3.7.2 SDK 文件准备
OrangePi Android 13 SDK 来自官方百度云/谷歌网盘,是 9 个分卷压缩包:
```
Android_13.tar.gz00 (4.0GB)
Android_13.tar.gz01 (4.0GB)
...
Android_13.tar.gz08 (1.9GB)
md5sum (校验文件)
```
存放路径:`~/OrangePi_CM5/Aandroid_OrangePi/`
### 3.7.3 MD5 校验
```bash
cd ~/OrangePi_CM5/Aandroid_OrangePi
md5sum -c md5sum
# 9 个文件全部显示"成功/确定"才能继续
```
### 3.7.4 合并压缩包(重要)
**经实测:官方文档的管道流式解压(`cat ... | tar -xzf -`)会在某个分卷边界出错**
(已解压 46GB 后报 `gzip: invalid compressed data--format violated`)。
**推荐做法:先合并成单个文件,再解压。**
```bash
cd ~/OrangePi_CM5/Aandroid_OrangePi
# 显式指定顺序合并(避免通配符顺序问题)
cat Android_13.tar.gz00 Android_13.tar.gz01 Android_13.tar.gz02 \
Android_13.tar.gz03 Android_13.tar.gz04 Android_13.tar.gz05 \
Android_13.tar.gz06 Android_13.tar.gz07 Android_13.tar.gz08 \
> Android_13.tar.gz
# 合并后约 34GB耗时约 15 分钟SSD 速度约 37MB/s
ls -lh Android_13.tar.gz
```
### 3.7.5 解压源码
```bash
# 解压到当前目录,产生 Android_13/ 目录
tar -xzf Android_13.tar.gz
# 解压后预计 80-100GB耗时约 20-30 分钟
du -sh Android_13/
```
解压成功后可以删除合并文件和分卷文件节省空间:
```bash
# 可选:保留分卷和 md5sum 作为备份源,删除合并文件
rm Android_13.tar.gz
# 或:已验证解压成功后,彻底清理(需确认 Android_13/ 完整)
# rm Android_13.tar.gz Android_13.tar.gz0*
```
### 3.7.6 创建 Dockerfile含所有踩坑补丁实测可用版
Dockerfile 位于虚拟机 `~/OrangePi_CM5/docker/Dockerfile`,基于 Ubuntu 22.04。
官方文档 7.2 的依赖列表不完整,本版本已加入所有实际踩坑后补齐的包。
```dockerfile
# OrangePi CM5 Android 13 编译环境
# 基础镜像Ubuntu 22.04(符合 OrangePi 官方推荐环境)
FROM ubuntu:22.04
# 清华镜像源
RUN sed -i 's@archive.ubuntu.com@mirrors.tuna.tsinghua.edu.cn@g; \
s@security.ubuntu.com@mirrors.tuna.tsinghua.edu.cn@g' /etc/apt/sources.list
ENV DEBIAN_FRONTEND=noninteractive
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 启用 i386 多架构Android 编译需要 32 位兼容库)
RUN dpkg --add-architecture i386
# 官方文档 7.2 要求的编译依赖
RUN apt-get update -y && apt-get install -y \
git gnupg flex bison gperf build-essential \
zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z1-dev ccache \
libgl1-mesa-dev libxml2-utils xsltproc unzip \
&& apt-get install -y u-boot-tools
# Android 13 需要 OpenJDK 11
RUN apt-get install -y openjdk-11-jdk
# 【踩坑 1】Ubuntu 22.04 默认没有 libncurses.so.5
# 但 Android 预编译 Clang 工具链依赖它,不装会导致编译到 40+ 分钟时报错
RUN apt-get install -y libncurses5 libncurses5:i386
# 【踩坑 2】Ubuntu 22.04 编译 Android 可能需要的预防性包
RUN apt-get install -y \
libssl-dev pkg-config m4 imagemagick \
python-is-python3 python3-protobuf \
protobuf-compiler libprotobuf-dev \
libncurses-dev
# 【踩坑 3】Rockchip U-Boot 的 make.sh 硬依赖 Python 2
# 不装会导致 MiniLoaderAll 合成阶段报 "ERROR: No python2"
RUN apt-get install -y python2 python2-dev python2.7
# 辅助工具
RUN apt-get install -y python3 python3-pip rsync cpio bc kmod \
device-tree-compiler liblz4-tool lzop sudo vim nano \
fontconfig schedtool
RUN apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /workspace
CMD ["/bin/bash"]
```
### 3.7.7 构建 Docker 镜像
```bash
cd ~/OrangePi_CM5/docker
sudo docker build -t android-builder-orangepi:13.x .
# 耗时约 5-10 分钟
```
验证镜像:
```bash
sudo docker images android-builder-orangepi
# 预期TAG=13.x, SIZE 约 2GB
```
### 3.7.8 进入 Docker 编译环境
```bash
sudo docker run -it \
--name orangepi-build \
-v ~/OrangePi_CM5/Aandroid_OrangePi/Android_13:/workspace \
-w /workspace \
android-builder-orangepi:13.x \
bash
```
### 3.7.9 执行编译
按官方文档 7.2 节编译参数:
| 参数 | 作用 |
|------|------|
| `-B` | 编译 U-Boot |
| `-K` | 编译 Kernel |
| `-a` | 编译 Android |
| `-F` | 编译 U-Boot + Kernel + Android三合一 |
| `-M` | 在 rockdev 目录生成分区镜像 |
| `-u` | 打包生成最终 update.img |
| `-b` | 指定开发板型号 |
| `--gapps` | 包含 Google Play 服务GApps |
推荐全量编译命令:
```bash
# 容器内或后台 docker run -d 执行
./make.sh -FMu -b orangepicm5 --gapps
```
实测耗时:**6 小时 11 分钟**VMware 虚拟机 8 核 20GB RAM + 9GB Swap
推荐后台执行(避免 SSH 断开中断):
```bash
sudo docker run -d --name orangepi-build \
-v /home/zhangwenqi/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13:/workspace \
-w /workspace \
android-builder-orangepi:13.x \
bash -c 'echo 开始: $(date) > /tmp/build.log && \
./make.sh -FMu -b orangepicm5 --gapps >> /tmp/build.log 2>&1; \
echo 结束: $(date) exit=$? >> /tmp/build.log'
# 查看进度
sudo docker exec orangepi-build tail -20 /tmp/build.log
sudo docker exec orangepi-build du -sh /workspace/out/
```
### 3.7.10 编译后的 U-Boot 修复(实测必需)
**`-F` 参数理论上会编译 U-Boot但实际只产出 `u-boot.img` 等基础文件,
不会自动调用 Rockchip 脚本合成 `MiniLoaderAll.bin` 和 `trust.img`。**
如果 `make.sh -FMu` 最后日志中出现:
```
u-boot/trust.img not fount! Please make it from u-boot first!
u-boot/*MiniLoaderAll_*.bin not fount! Please make it from u-boot first!
Error:<AddFile> open file failed,err=2!
Make firmware FAILED
```
需要手动执行两步修复:
**修复步骤 1合成 Rockchip U-Boot生成 MiniLoaderAll + uboot.img 新版)**
```bash
# 启动临时容器执行 u-boot/make.sh rk3588
sudo docker run --rm \
-v /home/zhangwenqi/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13:/workspace \
-w /workspace/u-boot \
android-builder-orangepi:13.x \
./make.sh rk3588
```
成功标志:
```
Image(no-signed, version=0): uboot.img (FIT with uboot, trust...) is ready
Image(no-signed): rk3588_spl_loader_v1.13.xxx.bin (with spl, ddr...) is ready
```
**修复步骤 2创建 trust.img 符号文件(新版 Rockchip 已将 trust 合并到 uboot.img**
```bash
# 在虚拟机宿主机执行(非容器内)
cd ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/u-boot/
sudo cp -a uboot.img trust.img
```
**修复步骤 3重新打包跳过编译只做 mkimage + update.img**
```bash
sudo docker run --rm \
-v /home/zhangwenqi/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13:/workspace \
-w /workspace \
android-builder-orangepi:13.x \
./make.sh -Mu -b orangepicm5 --gapps
```
`-Mu` 只做"生成分区镜像 + 打包 update.img",不重新编译 Android耗时约 5-10 分钟。
### 3.7.11 验证编译结果
成功后在 `rockdev/Image-rk3588s_t/` 目录生成所有镜像:
```bash
ls -lh ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/rockdev/Image-rk3588s_t/
```
预期产物(实测):
| 文件 | 大小 | 分区/作用 |
|------|------|----------|
| **update.img** | **2.3GB** | eMMC/TF 卡完整固件(首要烧录目标) |
| **update_spi_nvme.img** | **2.3GB** | SPI Flash + NVMe SSD 组合烧录 |
| MiniLoaderAll.bin | 465KB | bootloader 加载器MaskROM 引导) |
| uboot.img | 4.0MB | U-Boot已内含 trust |
| trust.img | 4.0MB | Trust 镜像(副本,兼容脚本) |
| boot.img | 37MB | 内核 + ramdiskboot 分区) |
| recovery.img | 47MB | Recovery 模式镜像 |
| super.img | 2.2GB | 超级分区(含 system+vendor+odm+product |
| dtbo.img | 443B | 设备树 Overlay |
| resource.img | 2.5MB | 内核资源(开机动画、字体等) |
| vbmeta.img | 4KB | 验证启动元数据 |
| misc.img | 48KB | 其他信息分区 |
| baseparameter.img | 1MB | 显示屏参数 |
| parameter.txt | - | 分区表定义 |
### 3.7.12 烧录到 OrangePi CM5 开发板
#### 首次烧录:只需 update.img
**`update.img` 是完整的 Android 13 系统固件**,包含所有分区镜像。
烧录 update.img 会一次性写入所有分区,等于给开发板全新刷系统。
烧录步骤:
1. 从虚拟机拷贝 `update.img`2.3GB)到 Windows 电脑:
```bash
# Mac 或虚拟机上执行(假设通过 Tailscale SSH
scp zhangwenqi@100.123.82.91:/home/zhangwenqi/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/rockdev/Image-rk3588s_t/update.img ~/Desktop/
```
2. Windows 电脑下载并安装 **RKDevTool**(瑞芯微官方烧录工具)
3. OrangePi CM5 进入 **MaskROM 模式**
- 按住板子上的 **Recovery / MaskROM 按键**
- 插入 USB 线到电脑
- 松开按键
4. RKDevTool 界面切换到 **升级固件** 标签
5. 点击 **固件** 按钮,选择 `update.img`
6. 点击 **升级** 按钮,等待烧录完成(约 2-5 分钟)
7. 烧录完成后开发板自动重启进入 Android 13
#### 镜像文件说明与高级烧录
`update.img` = Rockchip 打包格式,内部已包含所有其他 `.img` 文件。
单独的 `.img` 文件是给**开发调试**用的,用途:
| 场景 | 用哪个镜像 | 烧录方式 |
|------|-----------|---------|
| 首次刷机 / 完整升级 | `update.img` | RKDevTool 升级固件 |
| 只调试内核 | `boot.img` | `fastboot flash boot boot.img` |
| 只更新系统 | `super.img` | `fastboot flash super super.img` |
| 只更新 U-Boot | `uboot.img` | `fastboot flash uboot uboot.img` |
| 只刷 Recovery | `recovery.img` | `fastboot flash recovery recovery.img` |
| 改开机画面 | `resource.img` | `fastboot flash resource resource.img` |
| SPI Flash + NVMe 设备 | `update_spi_nvme.img` | RKDevTool 升级固件 |
**日常开发推荐**
- 改内核 / 驱动 → 单独烧 `boot.img`(几秒到 1 分钟)
- 改应用 / 系统框架 → 单独烧 `super.img`1-2 分钟)
- 改 Bootloader → 单独烧 `uboot.img` + `MiniLoaderAll.bin`
- 不确定或要彻底刷新 → 烧 `update.img`2-5 分钟)
这样可以避免每次修改都重刷整个系统。
### 3.7.12 关键差异对比(与 Radxa CM5
| 项目 | Radxa CM5 | OrangePi CM5 |
|------|-----------|--------------|
| Android 版本 | 12 | 13 |
| Docker 基础镜像 | ubuntu:20.04 | **ubuntu:22.04** |
| JDK 版本 | OpenJDK 8 | **OpenJDK 11** |
| 交叉编译工具链 | 需手动 COPY 5 套 Linaro | 编译脚本自动下载 |
| SDK 分发方式 | 单个压缩包 | 9 个分卷(需先合并) |
| 编译脚本 | `./build.sh -AUCKup` | `./make.sh -FMu -b orangepicm5 --gapps` |
| 镜像输出目录 | `rockdev/Image-RadxaCM5/` | `rockdev/Image-rk3588s_t/` |
| GMS 支持 | 需注释(官方不含) | `--gapps` 参数直接支持 |
| Docker 镜像名 | android-builder:12.x | android-builder-orangepi:13.x |
### 3.7.13 容器管理
```bash
# 退出容器(编译中断)
exit
# 重新进入已创建的容器(保留编译缓存)
sudo docker start -ai orangepi-build
# 删除容器(重新开始,会丢失容器内临时修改)
sudo docker rm -f orangepi-build
```
### 3.7.14 踩坑速查表(完整编译流水线)
以下所有坑都是实际编译过程中踩到的,新电脑按文档 3.7.1~3.7.12 操作时**严格按顺序**可以避开。
| # | 阶段 | 现象 | 根因 | 解决方法 |
|---|------|------|------|----------|
| 1 | SDK 校验 | gz03 分卷 MD5 校验通过但解压到 46GB 报 `invalid compressed data` | 百度网盘下载过程中该分卷损坏,但上游 md5sum 正好是损坏版本的 MD5 | 重新从百度网盘下载 gz03对比同网盘其他用户汇报的 MD5 |
| 2 | SDK 合并 | 官方文档推荐的 `cat ... \| tar -xzf -` 管道式解压在分卷边界处出错 | 管道模式下 tar 无法定位错误位置 | 改用"先合并成单文件 → 再解压"两步法 |
| 3 | 构建镜像 | Android ninja 42 分钟时报 `libncurses.so.5: cannot open shared object file` | Ubuntu 22.04 默认只有 libncurses.so.6 | Dockerfile 装 `libncurses5 libncurses5:i386` |
| 4 | 主体编译 | 6 小时编译完成后打包失败:`u-boot/trust.img not fount` | `make.sh -F` 只跑 U-Boot 编译,没调用 Rockchip 合成脚本 | 手动 `cd u-boot && ./make.sh rk3588` |
| 5 | U-Boot 合成 | Rockchip make.sh 报 `ERROR: No python2` | Ubuntu 22.04 没 Python 2默认只有 python3 | Dockerfile 装 `python2 python2-dev python2.7` |
| 6 | 打包阶段 | mkimage.sh 找不到 `trust.img` | 新版 Rockchip 把 trust 合并到 uboot.img不单独生成 | `cp uboot.img trust.img`(副本伪装) |
| 7 | 打包阶段 | 手动 lunch 后执行 mkimage.sh 编译目标变成 `aosp_arm` | OrangePi make.sh 内部根据 `-b orangepicm5` 设置 lunch手动设不对 | 直接用 `./make.sh -Mu -b orangepicm5 --gapps` 打包 |
| 8 | 资源管理 | Soong 阶段内存峰值 19GB会耗 Swap | Android 构建系统需要巨大内存 | 虚拟机分配 **20GB 内存 + 9GB Swap**(已配) |
| 9 | 编译效率 | 编译中断重启后重新跑全部阶段 | 未保留 out/ 缓存 | 不要 `rm -rf out/`,重启时 make.sh 会增量继续 |
| 10 | Docker 默认源 | `docker build` 拉 `ubuntu:22.04` 超时 | Docker Hub 国内访问慢 | `/etc/docker/daemon.json` 配置镜像加速器 |
### 3.7.15 完整编译流水线(新电脑复现)
如果换新电脑后需要重新编译,按以下顺序:
```bash
# === 准备阶段 ===
# 1. 恢复 SDK 分卷到 ~/OrangePi_CM5/Aandroid_OrangePi/archive/
# 2. MD5 校验所有分卷
cd ~/OrangePi_CM5/Aandroid_OrangePi/archive
md5sum -c md5sum
# 3. 合并成单文件到 merged/
cd ..
cat archive/Android_13.tar.gz00 archive/Android_13.tar.gz01 \
archive/Android_13.tar.gz02 archive/Android_13.tar.gz03 \
archive/Android_13.tar.gz04 archive/Android_13.tar.gz05 \
archive/Android_13.tar.gz06 archive/Android_13.tar.gz07 \
archive/Android_13.tar.gz08 > merged/Android_13.tar.gz
# 4. 解压源码
cd merged && tar -xzf Android_13.tar.gz
# === 编译阶段 ===
# 5. 构建 Docker 镜像(按 3.7.6 的 Dockerfile
cd ~/OrangePi_CM5/docker
sudo docker build -t android-builder-orangepi:13.x .
# 6. 主体编译(后台,约 6 小时)
sudo docker run -d --name orangepi-build \
-v ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13:/workspace \
-w /workspace \
android-builder-orangepi:13.x \
bash -c './make.sh -FMu -b orangepicm5 --gapps > /tmp/build.log 2>&1'
# 7. 等主体编译完成(会报 trust.img 缺失,正常)
# === 修复阶段 ===
# 8. 手动合成 Rockchip U-Boot
sudo docker run --rm \
-v ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13:/workspace \
-w /workspace/u-boot \
android-builder-orangepi:13.x \
./make.sh rk3588
# 9. 创建 trust.img 伪装
sudo cp -a ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/u-boot/uboot.img \
~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/u-boot/trust.img
# 10. 只打包(复用已编译产物,约 5-10 分钟)
sudo docker run --rm \
-v ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13:/workspace \
-w /workspace \
android-builder-orangepi:13.x \
./make.sh -Mu -b orangepicm5 --gapps
# === 完成 ===
# 11. 验证 update.img
ls -lh ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/rockdev/Image-rk3588s_t/update.img
# 预期2.3GB
```
## 3.8 Linux 虚拟机共享 Windows VPN外网访问
虚拟机通过 VMware 桥接网络使用 Windows 的 Clash 代理上外网。已配置开机自动生效。
### 当前配置信息2026-04-15 已验证)
| 项目 | 值 |
|------|-----|
| Windows 局域网 IP | 192.168.6.57 |
| Clash 代理端口 | 7890 |
| 虚拟机代理配置文件 | `/etc/profile.d/proxy.sh` |
### Windows 端配置(一次性)
1. Clash for Windows → 开启 **"允许局域网连接入Clash"**Allow LAN
2. Windows 防火墙放行 7890 端口(管理员 PowerShell 执行):
```powershell
netsh advfirewall firewall add rule name="Clash Proxy" dir=in action=allow protocol=tcp localport=7890
```
### Linux 虚拟机端配置(已完成,开机自动生效)
代理配置写入 `/etc/profile.d/proxy.sh`,每次登录自动加载:
```bash
export http_proxy="http://192.168.6.57:7890"
export https_proxy="http://192.168.6.57:7890"
export HTTP_PROXY="http://192.168.6.57:7890"
export HTTPS_PROXY="http://192.168.6.57:7890"
export no_proxy="localhost,127.0.0.1,100.64.0.0/10,192.168.0.0/16"
export NO_PROXY="localhost,127.0.0.1,100.64.0.0/10,192.168.0.0/16"
```
### 验证外网
```bash
curl -I https://www.google.com
curl -I https://releases.linaro.org/
```
### 前提条件
- Windows 电脑**开机且 Clash 运行中**
- Clash 的 "允许局域网连接入Clash" 保持开启
### 注意事项
- **Windows IP 变化**:如果 Windows 通过 DHCP 获取 IP重启路由器后 IP 可能变化。届时需要修改 `/etc/profile.d/proxy.sh` 中的 IP 地址:
```bash
sudo nano /etc/profile.d/proxy.sh
# 将 192.168.6.57 替换为新的 Windows IP
```
然后重新登录或执行 `source /etc/profile.d/proxy.sh` 生效。
建议在 Windows 上设置静态 IP 或在路由器中绑定 DHCP 避免此问题。
- **Docker 容器内使用代理**`/etc/profile.d/` 的代理对 Docker 容器内不生效,启动容器时需传入环境变量:
```bash
sudo docker run -it \
-e http_proxy="http://192.168.6.57:7890" \
-e https_proxy="http://192.168.6.57:7890" \
-e no_proxy="localhost,127.0.0.1" \
--name android-build \
-v ~/Radxa_CM5/SDK_Android:/workspace \
-w /workspace \
android-builder:12.x bash
```
---
# 第四部分Mac 端 SSH 连接配置
## 4.1 生成 SSH 密钥
```bash
ssh-keygen -t ed25519 -C "mac-to-linux-vm"
# 一路回车使用默认设置
```
## 4.2 部署公钥到虚拟机
```bash
ssh-copy-id zhangwenqi@100.123.82.91
# 输入虚拟机密码,完成后即可免密登录
```
## 4.3 SSH 配置文件
编辑 `~/.ssh/config`
```
Host linux-vm
HostName 100.123.82.91
User zhangwenqi
Port 22
ServerAliveInterval 30
TCPKeepAlive yes
ConnectTimeout 60
```
之后直接 `ssh linux-vm` 即可连接。
## 4.4 VS Code Remote-SSH推荐用于驱动开发
1. VS Code 安装 Remote - SSH 扩展
2. Cmd+Shift+P → "Remote-SSH: Connect to Host"
3. 选择 linux-vm
4. 连接成功后打开文件夹 `/home/zhangwenqi/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13`
Remote-SSH 模式下 VS Code 的后端vscode-server、扩展、终端都跑在虚拟机上Mac 只负责 UI。
编译、git、文件索引全都是虚拟机本地操作性能和稳定性最佳。
## 4.5 SMB 挂载(轻量文件浏览/编辑,不适合驱动开发)
macOS 原生支持 SMB通过 Tailscale 直接挂载虚拟机 Samba 共享目录:
**挂载方式**
1. Finder → `⌘+K`(连接到服务器)
2. 输入:`smb://100.123.82.91`
3. 输入虚拟机用户名/密码
4. 选择要挂载的共享目录,挂载点位于 `/Volumes/<share_name>`
挂载成功后 VS Code 可直接打开挂载目录,像本地文件一样编辑。
### 适用场景(轻量用途)
| 用途 | 可行性 |
|------|--------|
| 临时查看/编辑几个配置文件 | ✅ |
| 快速预览源码结构 | ✅ |
| Finder 里拖文件到 Mac 备份 | ✅ |
| 打开整个 84GB SDK 做索引开发 | ⚠️ 首次索引慢 |
| 跑编译 / 烧录 / git 大仓库操作 | ❌ 必须 SSH 到虚拟机 |
| 让 Claude Code 自动编译调试 | ❌ Mac shell 无 Linux 工具链 |
### SMB 方案关键局限
1. **文件访问 ≠ 执行环境**SMB 只能让 Mac 看到文件,无法在 Mac 上跑 Android 编译(缺 Rockchip 工具链、Docker、特定 Python/libncurses5 等依赖)
2. **符号链接支持有限**Android SDK 含大量符号链接SMB 可能表现异常
3. **Git 操作不稳定**:文件锁语义差异,`git status` 在 SMB 挂载目录上不可靠
4. **文件系统大小写**macOS 默认大小写不敏感 + Linux 大小写敏感,可能冲突
5. **`.DS_Store` 污染**Mac Finder 会在挂载目录留下元数据文件,进 git 会碍事
### 结论:两种方案如何选择
- **驱动开发主力**Remote-SSH编辑 + 编译 + 调试 + git 全部在虚拟机)
- **辅助场景**SMB只看几个文件、拖文件备份
两者不冲突,可以同时配好,按需使用。
---
# 第五部分:换新电脑配置指南
## 5.1 虚拟机备份说明
### 当前备份状态2026-04-16
| 项目 | 状态 |
|------|------|
| 备份格式 | OVF.ovf + .vmdk + .mf 三个文件) |
| 备份内容 | 系统 + Docker不含 SDK不含工具链 COPY 到镜像) |
| Docker 镜像 | android-builder:12.x 基础环境已装,**未对齐官方工具链** |
| SDK 压缩包 | 单独存放在 Windows 电脑/移动硬盘 |
### OVF 备份包含的设置
| 配置项 | 是否备份 | 导入后能否修改 |
|--------|---------|---------------|
| 硬盘大小700GB | 包含 | 可扩大,不可缩小 |
| 内存大小 | 包含 | 可自由调整 |
| CPU 核心数 | 包含 | 可自由调整 |
| 网络适配器类型(桥接) | 包含 | 可改为 NAT/桥接/仅主机 |
| 操作系统和所有软件 | 包含 | — |
三个文件必须放在同一文件夹,缺一不可:
- `.ovf` — 虚拟机配置描述CPU、内存、网卡等
- `.vmdk` — 虚拟磁盘数据(系统和所有文件)
- `.mf` — 校验文件(验证完整性)
## 5.2 新电脑是 Windows — 完整恢复步骤
### 步骤 1导入虚拟机
1. 新电脑安装 **VMware Workstation 17**(或更高版本)
2. VMware → 文件 → **打开** → 选择 `.ovf` 文件
3. 选择虚拟机存放位置(建议放在 SSD 上)
4. 等待导入完成
5. (可选)调整虚拟机参数:右键虚拟机 → 设置
- 内存:建议 16GB+Android 编译非常吃内存)
- CPU建议分配 8 核+
- 网络:选择**桥接模式**(与宿主机同网段)
### 步骤 2启动虚拟机并恢复网络
1. 启动虚拟机,登录(用户: zhangwenqi
2. 检查网络:
```bash
ip addr show # 确认获取到 IP
ping 8.8.8.8 # 测试内网连通性
```
3. 恢复 Tailscale
```bash
sudo systemctl status tailscaled # 检查 Tailscale 服务
sudo tailscale up # 重新认证(可能需要)
tailscale ip -4 # 记录新的 Tailscale IP
```
4. 更新代理配置Windows IP 可能变化):
```bash
# 在 Windows cmd 执行 ipconfig 获取新的局域网 IP
# 然后更新虚拟机代理配置
sudo nano /etc/profile.d/proxy.sh
# 将 192.168.6.57 替换为新 Windows 的局域网 IP
source /etc/profile.d/proxy.sh
# 测试外网
curl -I https://www.google.com
```
### 步骤 3恢复 SDK
```bash
# 将 SDK 压缩包从移动硬盘拷贝到虚拟机
# 可以通过 VMware 共享文件夹、scp、或 USB 挂载
cd ~/Radxa_CM5/SDK_Android/
# 确认文件
ls -lh radxa_android_sdk_backup.tar.gz
# 校验 MD5
md5sum radxa_android_sdk_backup.tar.gz
```
### 步骤 4对齐官方 Dockerfile 环境(重要)
备份的虚拟机中 Docker 镜像是基础版本,**缺少 5 套 Linaro 交叉编译工具链**。需要重新下载工具链并重建镜像。
#### 4.1 确认 Docker 和基础镜像正常
```bash
docker images android-builder
# 预期看到 android-builder:12.x 镜像
```
#### 4.2 确认代理可用(下载工具链需要外网)
```bash
curl -I https://releases.linaro.org/
# 预期 HTTP 200
```
如果不通,先按 3.7 节配置虚拟机代理。
#### 4.3 下载 5 套交叉编译工具链
```bash
cd ~/Radxa_CM5/docker
# 1. gcc-linaro-6.3.1 arm-linux-gnueabihf99MB
curl -L -o gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz \
'https://releases.linaro.org/components/toolchain/binaries/6.3-2017.02/arm-linux-gnueabihf/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz'
# 2. gcc-linaro-aarch64-none-elf-4.850MB
curl -L -o gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.bz2 \
'https://releases.linaro.org/archive/13.11/components/toolchain/binaries/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.bz2'
# 3. gcc-arm-none-eabi-6-2017-q2-update96MB
curl -L -o gcc-arm-none-eabi-6-2017-q2-update.tar.bz2 \
'https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2017q2/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2'
# 4. gcc-linaro-6.3.1 aarch64-linux-gnu106MB
curl -L -o gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu.tar.xz \
'https://releases.linaro.org/components/toolchain/binaries/6.3-2017.02/aarch64-linux-gnu/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu.tar.xz'
# 5. gcc-linaro-7.2.1 aarch64-elf51MB
curl -L -o gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf.tar.xz \
'https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11/aarch64-elf/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf.tar.xz'
```
#### 4.4 解压工具链
```bash
cd ~/Radxa_CM5/docker
tar -xf gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf.tar.xz
tar -xf gcc-linaro-aarch64-none-elf-4.8-2013.11_linux.tar.bz2
tar -xf gcc-arm-none-eabi-6-2017-q2-update.tar.bz2
tar -xf gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu.tar.xz
tar -xf gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf.tar.xz
# 确认解压结果(应有 5 个目录)
ls -d gcc-*/
```
#### 4.5 确认 Dockerfile 包含 COPY 命令
查看 `~/Radxa_CM5/docker/Dockerfile`,确认包含以下 COPY 行:
```dockerfile
COPY ./gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf /opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf
COPY ./gcc-linaro-aarch64-none-elf-4.8-2013.11_linux /opt/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux
COPY ./gcc-linaro-aarch64-none-elf-4.8-2013.11_linux /opt/toolchains/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux
COPY ./gcc-arm-none-eabi-6-2017-q2-update /opt/toolchains/gcc-arm-none-eabi-6-2017-q2-update
COPY ./gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf /opt/toolchains/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf
COPY ./gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu /opt/toolchains/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu
COPY ./gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf /opt/toolchains/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf
```
如果 Dockerfile 中没有这些行(备份时可能是旧版本),用以下完整 Dockerfile 替换:
```bash
cat > ~/Radxa_CM5/docker/Dockerfile << 'EOF'
FROM ubuntu:20.04
RUN rm /etc/apt/sources.list
RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse" | tee /etc/apt/sources.list
RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse" >> /etc/apt/sources.list
RUN echo "deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse" >> /etc/apt/sources.list
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update -y && apt-get install -y software-properties-common apt-utils
RUN add-apt-repository -y ppa:deadsnakes/ppa
RUN apt-get update -y && apt-get install -y python3.8
RUN update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.8 150
RUN apt-get install -y python3-pip && pip install pycrypto
RUN apt-get update -y && apt-get install -y openjdk-8-jdk python git-core gnupg flex bison gperf build-essential \
zip curl gawk liblz4-tool zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 \
libncurses5 libncurses-dev x11proto-core-dev libx11-dev lib32z-dev ccache \
libgl1-mesa-dev libxml2-utils xsltproc unzip mtools u-boot-tools \
htop iotop sysstat iftop pigz bc device-tree-compiler lunzip \
dosfstools vim-common parted udev libssl-dev sudo rsync python3-pyelftools cpio
RUN curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo > /usr/local/bin/repo && \
chmod +x /usr/local/bin/repo && \
which repo
ENV REPO_URL='https://mirrors.tuna.tsinghua.edu.cn/git/git-repo/'
RUN apt-get install -y lzop swig
RUN apt-get update -y && apt-get install -y tzdata
RUN mkdir /opt/toolchains
COPY ./gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf /opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf
COPY ./gcc-linaro-aarch64-none-elf-4.8-2013.11_linux /opt/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux
COPY ./gcc-linaro-aarch64-none-elf-4.8-2013.11_linux /opt/toolchains/gcc-linaro-aarch64-none-elf-4.8-2013.11_linux
COPY ./gcc-arm-none-eabi-6-2017-q2-update /opt/toolchains/gcc-arm-none-eabi-6-2017-q2-update
COPY ./gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf /opt/toolchains/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf
COPY ./gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu /opt/toolchains/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu
COPY ./gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf /opt/toolchains/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf
RUN apt-get install -y net-tools gcc-arm-linux-gnueabihf gcc-arm-none-eabi
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
EOF
```
#### 4.6 重建 Docker 镜像
```bash
cd ~/Radxa_CM5/docker
sudo docker build -t android-builder:12.x .
# 耗时约 10-15 分钟
```
#### 4.7 验证环境完整
```bash
sudo docker run --rm android-builder:12.x bash -c \
'echo "=== 工具链 ===" && ls /opt/toolchains/ && \
echo "" && echo "=== 编译器 ===" && \
/opt/gcc-linaro-6.3.1-2017.02-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-gcc --version | head -1 && \
/opt/toolchains/gcc-linaro-7.2.1-2017.11-x86_64_aarch64-elf/bin/aarch64-elf-gcc --version | head -1 && \
/opt/toolchains/gcc-linaro-6.3.1-2017.02-x86_64_aarch64-linux-gnu/bin/aarch64-linux-gnu-gcc --version | head -1 && \
java -version 2>&1 | head -1 && python3 --version && which repo'
```
预期输出:
- /opt/toolchains/ 下有 5 个工具链目录
- arm-linux-gnueabihf-gcc 6.3.1
- aarch64-elf-gcc 7.2.1
- aarch64-linux-gnu-gcc 6.3.1
- openjdk 1.8.0
- Python 3.8.x
- /usr/local/bin/repo
#### 4.8 清理下载的压缩包
```bash
cd ~/Radxa_CM5/docker
rm -f *.tar.xz *.tar.bz2
```
注意Docker 镜像加速器配置(`/etc/docker/daemon.json`)在备份中已保留,但镜像加速地址可能失效。
如果 `docker build` 拉取 ubuntu:20.04 失败,参考 3.4 节更新加速器地址。
## 5.2 新电脑是 Windows — 快速恢复
### 步骤 1导入虚拟机
1. 新电脑安装 **VMware Workstation 17**
2. VMware → 文件 → 打开 → 选择 `.ovf` 文件
3. 选择存放位置,等待导入
4. 调整参数(右键 → 设置):内存 16GB+CPU 8 核+,网络桥接模式
### 步骤 2恢复网络和代理
1. 启动虚拟机,检查网络
2. 更新 `/etc/profile.d/proxy.sh` 中的 Windows IP如果 IP 变化)
3. Windows 安装 Clash开启 Allow LAN防火墙放行 7890
4. 安装 TailscaleWindows + 虚拟机),同账号登录
### 步骤 3恢复 SDK 并对齐 Dockerfile
1. 拷贝 SDK 压缩包到虚拟机 `~/Radxa_CM5/SDK_Android/`
2. 按上方 **步骤 44.1~4.8** 对齐官方 Dockerfile 环境
3. 解压 SDK 并编译验证
### 步骤 4配置 Mac 远程开发(如有)
按第四部分重新配置 Mac 端 SSH 和 Tailscale。
## 5.3 新电脑是 Mac远程控制 Windows 开发)
Mac M 芯片无法运行 x86 虚拟机,采用 Mac 远程控制 Windows 方案。
### 前提条件
- Windows 电脑保持运行(作为编译服务器)
- Windows 上已按 5.2 完成虚拟机恢复和 Dockerfile 对齐
- Mac 和 Windows 都安装 Tailscale
### 步骤 1Windows 端配置
1. 按 5.2 完成虚拟机导入、网络恢复、SDK 恢复、Dockerfile 对齐
2. 安装 TailscaleWindows 版),用同一账号登录
3. 安装 Clash for Windows导入订阅开启 "允许局域网连接入Clash"
防火墙放行:
```powershell
netsh advfirewall firewall add rule name="Clash Proxy" dir=in action=allow protocol=tcp localport=7890
```
4. 启动虚拟机,确认服务正常:
```bash
tailscale status
sudo systemctl status ssh
curl -I https://www.google.com # 验证外网代理
docker images android-builder # 验证 Docker 镜像
```
5. 可选设置虚拟机开机自启VMware → 编辑 → 首选项 → 共享虚拟机 → 开机启动
### 步骤 2新 Mac 端配置
1. 安装 TailscaleApp Store用同一账号登录
2. 安装 ClashX Pro导入订阅
3. 配置 ClashX Pro 与 Tailscale 共存(按第二部分操作):
- 添加 Tailscale 直连规则到代理配置
- 关闭 Tailscale DNS Settings
4. 生成 SSH 密钥并部署:
```bash
ssh-keygen -t ed25519 -C "new-mac-to-linux-vm"
ssh-copy-id zhangwenqi@<虚拟机Tailscale_IP>
```
注意Tailscale IP 可能与之前不同,在虚拟机中执行 `tailscale ip -4` 确认。
5. 配置 SSH config`~/.ssh/config`
```
Host linux-vm
HostName <虚拟机Tailscale_IP>
User zhangwenqi
Port 22
ServerAliveInterval 30
TCPKeepAlive yes
ConnectTimeout 60
```
6. 安装 VS Code + Remote-SSH 扩展
7. Cmd+Shift+P → "Remote-SSH: Connect to Host" → linux-vm
### 步骤 3验证
```bash
# Mac 终端测试
ping <虚拟机Tailscale_IP>
ssh linux-vm
# 验证 Docker 环境完整(应显示 5 套工具链)
ssh linux-vm "docker run --rm android-builder:12.x ls /opt/toolchains/"
# 验证 VPN
# 浏览器访问 YouTube
```
### 日常使用流程
1. Windows 电脑开机 → 虚拟机自动启动(或手动启动)
2. Mac 打开 Tailscale + ClashX Pro
3. VS Code → Remote-SSH → linux-vm
4. 打开 `/home/zhangwenqi/Radxa_CM5` 开始开发
---
# 第六部分:故障排除
## 6.1 Tailscale 连不上
```bash
# Linux 端检查
sudo tailscale status
sudo systemctl restart tailscaled
sudo tailscale up
# 诊断
tailscale netcheck
```
## 6.2 SSH 连接被拒绝
```bash
# Linux 端检查
sudo systemctl status ssh
sudo netstat -tlnp | grep :22
sudo ufw status
# 重启 SSH
sudo systemctl restart ssh
```
## 6.3 VPN 开启 Tailscale 后失效
检查两个配置:
1. ClashX Pro 配置文件中 Tailscale 直连规则是否存在(订阅更新会覆盖)
2. Tailscale DNS Settings 是否已关闭
## 6.4 Docker 拉取镜像超时
Docker Hub 被墙,检查镜像加速配置:
```bash
cat /etc/docker/daemon.json
# 确认 registry-mirrors 配置正确
sudo systemctl restart docker
```
## 6.5 VS Code Remote-SSH 连接超时
在 `~/.ssh/config` 中增大超时:
```
Host linux-vm
ConnectTimeout 120
ServerAliveInterval 30
ServerAliveCountMax 5
```
---
# 第七部分:快速参考
## 日常连接命令
```bash
# Mac 终端直连
ssh linux-vm
# 文件传输
scp file.txt linux-vm:~/
scp -r folder/ linux-vm:~/destination/
```
## VS Code 操作
- Cmd+Shift+P → "Remote-SSH: Connect to Host" → linux-vm
- Cmd+Shift+P → "Remote-SSH: Disconnect"
## Linux 虚拟机管理
```bash
# Tailscale
tailscale ip -4
tailscale status
sudo tailscale down / up
# Docker
docker images
docker run -it --name android-build -v ~/Radxa_CM5/SDK_Android:/workspace -w /workspace android-builder:12.x bash
docker start -ai android-build # 重新进入已创建的容器
# SSH
sudo systemctl status ssh
sudo systemctl restart ssh
```
---
---
# 第八部分Android SDK Git 代码管理
## 8.1 方案说明
OrangePi CM5 Android 13 SDK 共 84GB、数十万文件不可能全量入 Git。
采用**白名单 `.gitignore` 方案**:在 SDK 根目录初始化 Git默认忽略所有文件只放行会被修改的核心目录。
- Git 仓库路径:`~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13/`
- 远程仓库GitHub`OrangePi_CM5_Project`Private
- 首次推送96,602 个文件,.git 约 1.3GB)约需 30-60 分钟
## 8.2 追踪的核心目录
| 目录 | 作用 |
|------|------|
| `device/rockchip/` | 产品配置、开机画面、init.rc、权限 |
| `kernel-5.10/arch/arm64/boot/dts/` | 设备树(屏幕/LED/NFC/GPIO 等) |
| `kernel-5.10/arch/arm64/configs/` | 内核配置文件 |
| `kernel-5.10/drivers/` | 内核驱动源码 |
| `kernel-5.10/include/` | 内核头文件 |
| `hardware/rockchip/` | Rockchip 硬件 HAL |
| `hardware/interfaces/` | Android 硬件接口 |
| `hardware/libhardware/` | Android hardware 库 |
| `u-boot/arch/arm/` | U-Boot 架构相关代码 |
| `u-boot/configs/` | U-Boot 配置 |
| `u-boot/board/` | 板级支持 |
| `u-boot/drivers/` | U-Boot 驱动 |
| `u-boot/include/` | U-Boot 头文件 |
| `u-boot/dts/` | U-Boot 设备树 |
| `frameworks/base/core/res/` | 系统默认资源(开机动画等) |
## 8.3 .gitignore 白名单内容
```gitignore
# 策略:根目录忽略所有,只白名单放行会改的目录
# 1. 默认忽略根目录所有内容
/*
# 2. 白名单:允许这些顶层目录/文件
!/.gitignore
!/README.md
!/device/
!/kernel-5.10/
!/hardware/
!/u-boot/
!/frameworks/
# ===== device 目录:只保留 rockchip =====
/device/*
!/device/rockchip/
/device/rockchip/*
!/device/rockchip/common/
!/device/rockchip/rk3588/
# ===== kernel-5.10:只保留驱动、设备树、配置 =====
/kernel-5.10/*
!/kernel-5.10/arch/
!/kernel-5.10/drivers/
!/kernel-5.10/kernel/
!/kernel-5.10/include/
!/kernel-5.10/Documentation/
# kernel-5.10/arch 只保留 arm64
/kernel-5.10/arch/*
!/kernel-5.10/arch/arm64/
/kernel-5.10/arch/arm64/*
!/kernel-5.10/arch/arm64/boot/
!/kernel-5.10/arch/arm64/configs/
/kernel-5.10/arch/arm64/boot/*
!/kernel-5.10/arch/arm64/boot/dts/
# ===== hardware 只保留 rockchip =====
/hardware/*
!/hardware/rockchip/
!/hardware/interfaces/
!/hardware/libhardware/
# ===== u-boot 只保留配置、设备树、板级代码 =====
/u-boot/*
!/u-boot/arch/
!/u-boot/board/
!/u-boot/configs/
!/u-boot/include/
!/u-boot/drivers/
!/u-boot/dts/
/u-boot/arch/*
!/u-boot/arch/arm/
/u-boot/arch/arm/*
!/u-boot/arch/arm/dts/
!/u-boot/arch/arm/mach-rockchip/
!/u-boot/arch/arm/include/
# ===== frameworks 只保留 base/core/res =====
/frameworks/*
!/frameworks/base/
/frameworks/base/*
!/frameworks/base/core/
/frameworks/base/core/*
!/frameworks/base/core/res/
# ===== 编译产物和临时文件 =====
out/
*.o
*.ko
*.a
*.so
*.so.dbg
*.pyc
*.swp
*.swo
*~
__pycache__/
.DS_Store
# ===== 子仓库的 .git 内部目录 =====
**/.git/
```
## 8.4 日常工作流
```bash
# 在 SDK 中直接改代码(例如 NFC 驱动)
cd ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13
vi kernel-5.10/drivers/nfc/my_nfc.c
# 查看修改
git status
git diff
# 提交
git add kernel-5.10/drivers/nfc/
git commit -m "添加 PN532 NFC 驱动支持"
git push
```
## 8.5 回滚操作
```bash
# 查看历史
git log --oneline
# 回滚单个文件到上一版本
git checkout HEAD~1 -- kernel-5.10/drivers/nfc/my_nfc.c
# 回滚整个目录
git checkout HEAD~1 -- kernel-5.10/drivers/nfc/
# 慎用:回滚全部到某个 commit
git reset --hard <commit_hash>
```
## 8.6 分支管理(推荐功能分支)
```bash
# 创建功能分支
git checkout -b feature/nfc-pn532
# 开发、多次 commit 后合并回 main
git checkout main
git merge feature/nfc-pn532
# 废弃分支
git branch -D feature/nfc-pn532
```
## 8.7 首次推送到 GitHubSSH 密钥方式,推荐)
**当前仓库**: `git@github.com:Leo-z8/OrangePi_CM5_Project.git`Private
**认证方式**: SSH ed25519 密钥,永久免密
**网络路径**: 虚拟机 → GitHub `ssh.github.com:443`(直连,不经 Clash 代理)
### 为什么选 SSH 而非 HTTPS + PAT
| 对比项 | HTTPS + PAT | SSH 密钥 |
|--------|-------------|----------|
| 有效期 | 最长 1 年,需定期更新 | 永久有效 |
| 网络路径 | 必须走 Clash 代理HTTPS 国内慢) | 443 端口直连 GitHub |
| 稳定性 | TLS 握手依赖代理链,大文件易挂断 | SSH 原生流控,错误信息清晰 |
| 推送速度 | 受 Clash 带宽 + rwnd 限制 | 实测稳定 4-6 MiB/s |
| 首次推送 758 MiB | 多次中断重试 | 约 2-3 分钟完成 |
### 步骤 1虚拟机生成 SSH 密钥
```bash
ssh-keygen -t ed25519 -C "zhangwenqi-orangepi-vm-github" \
-f ~/.ssh/github_ed25519 -N ''
```
生成后两个文件:
- `~/.ssh/github_ed25519`(私钥,权限 600
- `~/.ssh/github_ed25519.pub`(公钥)
### 步骤 2配置 `~/.ssh/config` 走 443 端口
```
Host github.com
HostName ssh.github.com
User git
Port 443
IdentityFile ~/.ssh/github_ed25519
IdentitiesOnly yes
ServerAliveInterval 30
```
**关键点**:
- `HostName ssh.github.com` + `Port 443` 绕过国内对 22 端口的封锁
- `IdentitiesOnly yes` 强制只用这个密钥,防止扔其他密钥被 GitHub 拒绝
- 此方案不依赖 Clash 代理,虚拟机可直连
### 步骤 3添加公钥到 GitHub
```bash
cat ~/.ssh/github_ed25519.pub
```
复制整行内容,到 https://github.com/settings/ssh/new 添加:
- Title`OrangePi-VM-Linux`
- Key typeAuthentication Key
- Key粘贴公钥
### 步骤 4测试连通性
```bash
ssh -T git@github.com
# 预期输出Hi Leo-z8! You've successfully authenticated
```
### 步骤 5切换仓库 remote 到 SSH
```bash
cd ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13
# 清除旧 HTTPS 配置(如果之前用过 PAT
rm -f ~/.git-credentials
git config --local --unset credential.helper 2>/dev/null
git config --local --unset http.proxy 2>/dev/null
git config --local --unset https.proxy 2>/dev/null
# 改 remote 为 SSH
git remote set-url origin git@github.com:Leo-z8/OrangePi_CM5_Project.git
git remote -v
# 推送(永久免密)
git push -u origin main
```
### 备选方案HTTPS + PAT不推荐作为长期方案
仅在没有 SSH 配置权限或临时应急时使用:
```bash
# 配置 git 代理HTTPS 必须走 Clash
git config http.proxy http://192.168.6.57:7890
git config https.proxy http://192.168.6.57:7890
git config http.postBuffer 524288000 # 增大缓冲,大仓库必需
git remote set-url origin https://github.com/Leo-z8/OrangePi_CM5_Project.git
git config credential.helper store
# 提示时:用户名 = GitHub 账号,密码 = PAT 令牌
git push -u origin main
```
> **PAT 生成**https://github.com/settings/tokens/new → 勾 `repo` → 生成后立即复制。
> 推送完成后建议立即 Revoke一次性使用因为 PAT 明文存在 `~/.git-credentials` 有泄露风险。
## 8.8 推送后日常 push
SSH 方式配置后完全免密:
```bash
cd ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13
git add kernel-5.10/drivers/nfc/
git commit -m "添加 PN532 NFC 驱动"
git push # 免密,永久免代理
git pull # 同理
```
## 8.9 备份策略
| 资产 | 备份位置 |
|------|---------|
| 驱动/配置修改 | GitHub 仓库(`Leo-z8/OrangePi_CM5_Project`Private |
| SDK 原始源码分卷9个 tar.gz | Windows 电脑(永久保留,不能删) |
| Docker 镜像定义 | `~/OrangePi_CM5/docker/Dockerfile` |
| 编译产物update.img | 按需保留,体积大不进 Git |
| 被 `.gitignore` 排除的大文件 | 需单独备份(见 8.10 |
## 8.10 GitHub 推送踩坑实录2026-04-22 首次推送)
### 踩坑 1GitHub 单文件 100MB 硬性限制
**现象**HTTPS 推送数据上传完后 "远端意外挂断了"SSH 推送明确报错:
```
remote: error: File device/rockchip/rk3588/rk3588m_car/preinstall/camera360.apk
is 120.48 MB; this exceeds GitHub's file size limit of 100.00 MB
remote: error: GH001: Large files detected.
! [remote rejected] main -> main (pre-receive hook declined)
```
**根因**GitHub pre-receive hook 在服务端验收阶段拒绝 >100MB 单文件。HTTPS 协议表现为 TLS 连接异常终止难诊断SSH 协议会直接打印错误(易诊断)。
**教训****大文件推送问题要用 SSH 调试**HTTPS 的"远端挂断"往往掩盖真实原因。
### 踩坑 2扫大文件要用 `git ls-tree`,不能用 `git rev-list`
```bash
# ❌ 错误方式:按 blob 扫描Git 去重会掩盖多路径
git rev-list --objects --all | \
git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | \
awk '$1=="blob" && $3>=100000000'
# ✅ 正确方式:按 HEAD 中的路径扫描
git ls-tree -r -l HEAD | awk '$4>=100000000 {printf "%.1f MB %s\n", $4/1024/1024, $5}'
```
**根因**:两个产品目录下存在完全相同的 `camera360.apk`(内容 hash 相同Git 按 blob 去重存储,`rev-list` 只列出一个 blob但 `ls-tree` 会展开所有路径。
**教训**:初次 `git rm --cached` 只去掉一个路径,第二次推送时另一个路径的 APK 仍会撞限,必须一次性用通配符覆盖所有。
### 踩坑 3`.gitignore` 用具体路径易遗漏,通配符更健壮
```gitignore
# ❌ 窄规则:只管一个路径
device/rockchip/rk3588/rk3588m_car/preinstall/camera360.apk
# ✅ 通配符:所有产品配置下的预装 APK 一次性处理
device/rockchip/*/*/preinstall/*.apk
```
**教训**多产品配置项目中rk3588m_car / rk3588m_s / …)类似的二进制资源可能分布在多个目录,写 `.gitignore` 规则时默认用通配符。
### 踩坑 4HTTPS + Clash 代理的 TCP rwnd 瓶颈
推送过程 `ss -tni` 显示 **`rwnd_limited: 95.1%`** —— 95% 时间卡在 GitHub 端接收窗口Clash 代理到 GitHub 的上行链路成瓶颈,平均速度被压到 1-2 MiB/s。
切到 SSH 443 直连后 **`rwnd_limited: 0.8%`**,速度稳定 4-6 MiB/s。
**结论**:大仓库首次推送坚决用 SSH不要 HTTPS。
### 踩坑 5凭证泄露风险
HTTPS + PAT 方案下,凭证明文存在 `~/.git-credentials`
```
https://用户名:PAT@github.com
```
即使 PAT 只用一次,也要:
1. 推送完成后到 https://github.com/settings/tokens 立即 Revoke
2. `rm -f ~/.git-credentials`
3. `git config --unset credential.helper`
**SSH 方式无此风险**:私钥只存本地 ~/.ssh/,不会经过对话或日志。
### 本次推送完整大文件排除流程(已落地)
```bash
cd ~/OrangePi_CM5/Aandroid_OrangePi/merged/Android_13
# 1. 扫出所有 >100MB 路径
git ls-tree -r -l HEAD | awk '$4>=100000000 {printf "%.1f MB %s\n", $4/1024/1024, $5}'
# 2. 从索引移除(磁盘文件保留)
git rm --cached device/rockchip/rk3588/rk3588m_car/preinstall/camera360.apk
git rm --cached device/rockchip/rk3588/rk3588m_s/preinstall/camera360.apk
# 3. .gitignore 追加通配符规则
cat >> .gitignore << 'EOF'
# 排除所有预装 APKGitHub 100MB 限制 + 非驱动开发必需)
device/rockchip/*/*/preinstall/*.apk
EOF
# 4. amend 原 commit
git add .gitignore
git commit --amend --no-edit
# 5. 验证 HEAD 里无 >100MB 文件
git ls-tree -r -l HEAD | awk '$4>=100000000' # 应无输出
# 6. 推送
git push -u origin main
```
### 需要单独备份的大文件清单
以下文件已从 Git 历史排除,需另存(网盘/内网文件服务器):
| 文件 | 大小 | 路径 |
|------|------|------|
| camera360.apk (rk3588m_car) | 120 MB | `device/rockchip/rk3588/rk3588m_car/preinstall/` |
| camera360.apk (rk3588m_s) | 120 MB | `device/rockchip/rk3588/rk3588m_s/preinstall/` |
这些是产品预装 APK不是驱动开发所需完整 SDK 部署时再从备份恢复即可。
## 8.11 GitHub 推送关键数据(本次首次推送)
| 指标 | 数值 |
|------|------|
| 本地仓库大小(`.git` | 774 MB |
| 追踪文件总数 | 96,600 |
| 上传 pack 大小 | 约 518 MiB移除两个 120MB APK 后) |
| 网络路径 | 虚拟机 → Tailscale不经 Clash → `ssh.github.com:443` |
| 实测速度 | 4-6 MiB/sSSH 443 直连,无 rwnd 瓶颈) |
| 首次推送耗时 | 约 2-3 分钟(纯网络时间,排除多次重推) |
| 最终 commit | `c79995a30a9db560899bf0845440720edf3e5e3d` |
| 远程仓库 | https://github.com/Leo-z8/OrangePi_CM5_Project |
---
文档版本: 3.1
最后更新: 2026-04-22
适用系统: Ubuntu 20.04/22.04 LTS (x86_64), macOS
网络环境: 跨网络远程开发Tailscale + ClashX Pro 共存 + GitHub SSH 443
主要变更v3.1:
- 4.5 新增 SMB 挂载方式Mac 端轻量文件访问方案)与 Remote-SSH 对比
- 8.7 首次推送 GitHub 改为 SSH 密钥为主PAT 降为备选
- 8.10 新增首次推送踩坑实录(单文件 100MB 限制、Git 去重陷阱、rwnd 瓶颈等)
- 8.11 新增首次推送实测数据