docker-android Android 16 支持与编译修改

镜像:yeshen/docker-android:emulator_16.0

sh 复制代码
docker push yeshen/docker-android:emulator_16.0

基础原理

  1. 系统镜像来源

    docker-android 项目 = 用 Docker 容器运行 Google 官方 Android 模拟器。

    容器里跑的是与 Android Studio 完全同源的组件:

    • emulator 二进制(QEMU/KVM 虚拟机)
    • system-images 系统镜像(Android 操作系统镜像)
      两者都来自 Google 官方仓库 dl.google.com/android/repository,
      通过 sdkmanager/avdmanager 下载和管理------和 Android Studio 的
      SDK Manager / Device Manager 是同一个仓库、同一套镜像、同一个 emulator。
  2. 容器内启动链路(CLI 驱动,Python)

    容器启动 -> supervisord -> docker-android start device

    -> avdmanager create avd(创建虚拟设备,首次)

    -> emulator @avd -gpu swiftshader ...(启动 QEMU,需宿主机 /dev/kvm)

    -> adb 轮询 sys.boot_completed / launcher 聚焦(就绪检查)

    -> device_status 写 READY -> keep_alive 保活(并检测崩溃自动重启)

  3. 对外连接方式

    • adb:容器暴露 5555 端口,宿主机 adb connect localhost:5555
    • noVNC / webVNC:容器暴露 6080 端口,浏览器访问 http://localhost:6080
      看画面、点按(x11vnc + noVNC 转发)
    • VNC:5900 端口
    • Appium:4723(可选,镜像已裁剪掉 Node/Appium,需要可自行加)
    • 日志共享:9000 端口
  4. 关键版本信息

    • 当前支持:Android 16(API 36),系统镜像 system-images;android-36;google_apis;x86_64
    • emulator:37.1.11(sdkmanager 安装的 channel-0 稳定版)
    • 架构:仅 x86_64;需要宿主虚拟化 /dev/kvm

修改点涉及

  1. 多阶段构建瘦身(docker/emulator)

    构建阶段(build stage):

    • FROM appium/appium:v3.6.0-p0(提供 JDK + cmdline-tools/sdkmanager/avdmanager)
    • 安装 system-images;android-36;google_apis;x86_64 + emulator + platform-tools
    • 不装 platforms / build-tools(运行期用不到)
      运行阶段(runtime stage):
    • FROM ubuntu:24.04
    • 保留:emulator + 系统镜像、adb、JRE(avdmanager 需要)、Python CLI、
      supervisord、Xvfb/openbox/x11vnc/noVNC、socat
    • 砍掉:Node/Appium(约 1GB)、JDK->JRE、build-tools、platforms
    • 结果:7.92GB -> 6.64GB
  2. CLI 版本支持(Android 16 适配,真正改动只有几行)

    • cli/src/device/emulator.py API_LEVEL 字典加 "16.0": "36"
    • app.sh supported_android_version 加 "16.0"
      api_levels 加 "16.0"=36
      IMAGE_NAME 改为 yeshen/docker-android(发布前缀)
    • .github/workflows/release.yml android 矩阵加 "16.0"
    • README.md 镜像表格加 16.0 行
  3. CLI 健壮性 / 兼容性修复(版本无关,但必要)

    • -screen multi-touch:保证 guest 创建触摸设备(X/noVNC 点击可用)
    • -feature -Vulkan:禁用 guest Vulkan,规避 SwiftShader Vulkan SIGSEGV
    • 自愈 keep_alive:检测 emulator 进程退出自动重启(原实现只是死循环)
    • DISABLE_SYSTEM_UI:opt-in 开关(Android 17 需要,16 不需要)
  4. 运行时修复

    • noVNC 响应加 Cache-Control: no-cache(防止浏览器混用新旧 JS 模块)
    • run.sh 启动时清理残留 X lock(docker restart 后 Xvfb 能正常启动)
    • data partition 2G(原 550m 太小导致安装应用空间不足)
    • CMD 改为 exec-form(保证 SIGTERM 优雅退出)
    • cli/setup.py 修复(py_modules 错误导致 CLI 无法 pip 安装)
    • .fehbg 修复(openbox 壁纸 autostart)

修改后编译镜像

  1. 构建命令
sh 复制代码
   DOCKER_BUILDKIT=1 docker build \
     -t yeshen/docker-android:emulator_16.0 \
     --build-arg DOCKER_ANDROID_VERSION=<ver> \
     --build-arg EMULATOR_ANDROID_VERSION=16.0 \
     --build-arg EMULATOR_API_LEVEL=36 \
     -f docker/emulator .
  1. 产物

    yeshen/docker-android:emulator_16.0 (版本 tag,滚动更新)

    yeshen/docker-android:emulator_16.0_v0.1 (具体发布 tag,与上面同镜像)

    体积:6.64GB(原基于 appium 的镜像 7.92GB)

  2. 启动方式

sh 复制代码
   docker run -d -p 6080:6080 -p 5555:5555 \
     -e EMULATOR_DEVICE="Pixel 8" -e WEB_VNC=true \
     --device /dev/kvm --name android-16 \
     yeshen/docker-android:emulator_16.0
  • 访问 http://localhost:6080 看画面
  • adb connect localhost:5555 用 adb
  • 无需 DISABLE_SYSTEM_UI,SystemUI 完整可用
  1. 端到端验证结果(Android 16)
    • boot 到 READY 约 50 秒
    • SystemUI 完整运行,无崩溃
    • 网络:wifi 连 AndroidWifi,ping 8.8.8.8 0% 丢失
    • 触摸输入:X 点击 -> guest 触摸事件正常
    • Chrome 压力:多页面导航 + 快速返回 x12,0 崩溃、qemu 存活
    • scrcpy:MediaCodec 编码器可用,可正常投屏
    • 单元测试 34 passed

遇到的问题

【阶段一:先试 Android 17(API 37),因上游 bug 放弃】

  1. SurfaceFlinger 崩溃循环("模拟器一直重启")

    • 现象:framework 每 20~90 秒整体重启,进不去稳定 launcher
    • 根因:API 37 系统镜像的 mapper.ranchu gralloc HAL 断言崩溃
      (Assertion failed: !rcEnc->featureInfo()->hasReadColorBufferDma)
      emulator 的 gfxstream host 广播 ReadColorBufferDMA 特性,但 API 37
      的 mapper 预期关闭 -> 版本错配,属上游 bug(API 33~36 均正常)
    • 处理:DISABLE_SYSTEM_UI=true(禁用 SystemUI 后亮度采样触发源消失)
    • 结论:能压住但无法根治;同时连带触摸/投屏/任务快照多个问题
  2. 触摸输入无效

    • 根因:emulator 在 hw.screen=touch 模式下不创建触摸设备(API 37)
    • 处理:-screen multi-touch
  3. 任务快照间歇崩溃

    • 现象:打开/切换 App(尤其 Chrome)时 system_server 崩溃
    • 根因:TaskSnapshotPersister 截取窗口快照走同一 mapper.ranchu 读回路径
    • 处理:无运行时开关(编译期配置),靠自愈兜底
  4. scrcpy / screencap 不可用

    • 根因:编码器与截屏都走 gralloc 读回 -> 同一断言
    • 处理:无法规避,等上游修复
  5. "CPU 494%" 假象

    • ps -o %cpu 是生命周期平均值,被崩溃循环拉高;瞬时采样实际 ~40%

结论:Android 17 无法稳定使用,改为 Android 16(API 33~36 不受影响)。

【阶段二:Android 16 遇到的问题】

  1. SwiftShader Vulkan SIGSEGV(打开 Chrome 偶发整个模拟器段错误)

    • 现象:emulator 进程 exit code -11(SIGSEGV),崩溃前有
      VkInstance application:'Chromium' 日志
    • 根因:emulator 37.1.11 的 SwiftShader Vulkan 实现 bug(宿主机侧)
    • 处理:-feature -Vulkan 禁用 guest Vulkan,Chrome 退回 GLES 路径
    • 验证:修复后 Chrome 压力测试 0 次 SIGSEGV
  2. 网络"没网"多为崩溃连锁 + wifi 关联慢

    • 容器本身网络正常;guest wifi 关联需几分钟,且 framework 崩溃会掉线
    • 稳定后 ping 0% 丢失
  3. 容器重建清空 /data

    • 未挂持久卷时 docker rm+run 会清空 /data,应用私有目录需重新初始化,
      曾出现应用写失败(目录缺失),补齐目录即可

【阶段三:通用工程问题】

  1. app.sh last_key bug

    • keys-2 用未排序关联数组序导致 :latest tag 指错版本,改 sorted_keys-2
  2. noVNC 浏览器报错 supportsWebCodecsH264Decode

    • 服务端文件一致,是浏览器启发式缓存混用新旧 JS 模块
    • 处理:websockify 响应加 Cache-Control: no-cache
  3. 多阶段构建运行时库风险

    • emulator 二进制依赖众多系统库,精简镜像需按 ldd 实测补齐
    • Java 不能省(avdmanager 创建 AVD 需要 JRE)
相关推荐
天空之城--6 小时前
【无标题】
android
mmsx7 小时前
osmdroid 接入谷歌影像底图:瓦片 URL 拼接与多域名轮询实战
android·osmdroid
ZYJCSZKJ7 小时前
基于大语言模型的地域实体语义增强:生成式引擎优化(GEO)中的多模态内容生成实践
android·人工智能·语言模型
ssshooter7 小时前
Tauri + GitHub Actions 自动化发布 Android APK 技术总结
android·github·android studio
2401_885885047 小时前
国际语音php接口代码示例:PHP使用cURL快速调用语音发送API
android·开发语言·前端·人工智能·python·php·语音识别
_李小白7 小时前
【Android UI开发】Android VideoView 使用介绍(一)
android·ui
Mr数据杨8 小时前
【Codex】用学生支持周报模块跟踪个性化支持进展
android·java·javascript·django·codex·项目开发
名剑走天下8 小时前
Android 面试题大全
android·kotlin
mmsx9 小时前
osmdroid 自定义地图视图:继承 MapView 的正确姿势与生命周期管理
android·osmdroid