# android_emu **Repository Path**: pangxiongfei/android_emu ## Basic Information - **Project Name**: android_emu - **Description**: 基于 Ubuntu 24.04 的容器化 Android 模拟器工程 - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 4 - **Forks**: 1 - **Created**: 2026-09-02 - **Last Updated**: 2026-09-10 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # android_emu > 一行命令拉起带 VNC 界面的 Android 模拟器(Docker 化,开箱即用,无需在宿主机安装 Android Studio)。 基于 **Ubuntu 24.04** 的容器化 Android 模拟器工程。容器启动后自动完成 `Xvfb → Android Emulator → x11vnc` 整条链路,直接获得一个可以通过 **VNC 操作界面**、 通过 **ADB 调试** 的 Android 设备。 ![Docker](https://img.shields.io/badge/docker-latest-blue?logo=docker) ![Base](https://img.shields.io/badge/base-Ubuntu%2024.04-E95420?logo=ubuntu) ![Android](https://img.shields.io/badge/Android-13%2B-3DDC84?logo=android) ![Arch](https://img.shields.io/badge/arch-x86__64-orange) ![License](https://img.shields.io/badge/license-MIT-green) - 仓库地址: --- ## ✨ 特性 - **一键启动**:`./run.sh` 完成构建 + 启动,无需手工安装 SDK / 创建 AVD - **可视化操作**:内置 Xvfb + x11vnc,任意 VNC 客户端连 `localhost:5900` 即可操作安卓界面 - **ADB 直连**:host 网络模式,宿主机 `adb connect localhost:5555` 直接可调 - **API 版本可切换**:`./run.sh up 34`,支持 Android 13 / 14 / 15 / 16(API 33~36) - **数据持久化**:模拟器用户数据存于 Docker volume,`docker compose down` 不丢失 - **自愈能力**:AVD 与系统镜像版本不一致时自动重建,避免 `Broken AVD system path` 死循环 - **无 KVM 可跑**:无 `/dev/kvm` 时自动降级为软件模拟(较慢,但可用) - **国内友好**:apt / SDK / AOSP 均提供镜像源与代理参数 --- ## 📋 环境要求 | 项目 | 要求 | 说明 | |------|------|------| | 操作系统 | Linux(已在 Ubuntu 22.04+ 验证) | 需能运行 Docker | | Docker | 20.10+,含 Buildx 插件 | 必须支持 `docker buildx bake` | | 磁盘 | ≥ 15 GB | 系统镜像 2~3 GB + AVD 数据 5~10 GB | | 内存 | ≥ 8 GB(建议 16 GB) | 模拟器默认分配 2048 MB | | KVM | 可选 | 有 `/dev/kvm` 时性能提升一个数量级,详见 [启用 KVM 加速](#启用-kvm-加速) | 检查环境: ```bash docker version docker buildx version ls -l /dev/kvm # 存在则支持硬件加速 ``` --- ## 🚀 快速开始 ```bash git clone https://gitee.com/pangxiongfei/android_emu.git cd android_emu ./run.sh # 构建镜像 + 后台启动容器 ./run.sh logs # 跟踪启动日志(首次需等待模拟器开机) ``` > 首次构建需下载 Android SDK 与系统镜像(约 2 GB),耗时较长属正常现象。 > 首次开机(冷启动):有 KVM 约 **1~3 分钟**,无 KVM 约 **10~30 分钟**。 日志中出现以下输出即表示就绪: ``` ============================================================== Android Emulator 已就绪! VNC : localhost:5900 (无密码直连) ADB : adb connect localhost:5555 ============================================================== ``` --- ## 🖥️ 连接方式 ### VNC(图形界面) | 项目 | 值 | |------|-----| | 地址 | `localhost:5900` | | 密码 | 默认无密码直连 | | 分辨率 | 默认 `1440x900x24` | ```bash # Linux sudo apt install tigervnc-viewer vncviewer localhost:5900 ``` Windows / macOS 可用 TigerVNC、RealVNC、MobaXterm 等任意 VNC 客户端; macOS 也可直接用 `open vnc://localhost:5900`。 > 本工程未集成 noVNC(Web 界面),如需浏览器访问请自行在宿主机部署 websockify + noVNC > 转发到 `localhost:5900`。 ### ADB(命令行调试) 宿主机直连(host 网络模式,端口直接暴露在宿主): ```bash adb connect localhost:5555 adb devices adb shell getprop ro.build.version.release ``` 也可在容器内操作(容器内 ADB 服务端口为 `5038`,避免与宿主机 `5037` 冲突): ```bash ./run.sh shell adb devices adb shell ``` --- ## 🧰 命令速查 所有操作统一通过 `run.sh` 入口(它会自动导出 `PROJECT_ROOT`,勿直接执行 `docker compose`): ```bash ./run.sh # 构建镜像 + 启动容器(默认) ./run.sh up 35 # 指定 Android API level(默认 33) ./run.sh shell # 进入容器 shell(工作目录 /workspace) ./run.sh logs # 跟踪容器日志 ./run.sh status # 查看容器状态 ./run.sh stop # 停止容器 ./run.sh down # 停止并删除容器(AVD 卷保留) ./run.sh reset_avd # 停止容器并删除 AVD 数据卷(下次启动重建 AVD) ./run.sh rebuild # 无缓存重新构建镜像 + 启动 ./run.sh dl_aosp [TAG] # 用国内镜像下载 AOSP 源码到 source/ ``` --- ## 🎯 实战:从零拉起并连入模拟器 下面是一组**完整可复制**的最小操作流程,分两个终端窗口执行。 **终端 1 — 重置并启动** ```bash ./run.sh stop ./run.sh reset_avd # 清掉旧的 AVD 数据卷,避免残留配置导致启动失败 ./run.sh # 构建镜像 + 启动容器(模拟器自动拉起) # 另开终端跟踪启动日志(首次冷启动无 KVM 约需 10~30 分钟) ./run.sh logs # 看到 "Android Emulator 已就绪!" 即成功 ``` > `reset_avd` 会删除 `docker_android-avd` 卷;若只是第一次启动或已确认 AVD 正常, > 可省略 `stop` / `reset_avd`,直接 `./run.sh`。 **终端 2 — 进容器并连入安卓** ```bash ./run.sh shell # 进入容器(工作目录 /workspace,adb 用 5038 端口) adb devices # 应显示 emulator-5554 device adb shell # 进入安卓 shell,提示符变为 emu64x:/ $ ``` 进入安卓 shell 后即可使用常规命令: ```bash emu64x:/ $ getprop ro.build.version.release # 13 emu64x:/ $ getprop ro.product.model # sdk_gphone64_x86_64 emu64x:/ $ ls /system # 安卓系统目录 emu64x:/ $ exit # 退回容器 ``` --- ## 📁 目录结构 ``` android_emu/ ├── README.md # 本文件 ├── LICENSE # MIT 许可证 ├── run.sh # 唯一入口(构建 / 启动 / 运维) ├── docker/ │ ├── docker-compose.yml # 容器定义:网络、端口、卷、设备 │ ├── docker-bake.hcl # 镜像构建定义(buildx bake) │ ├── scripts/ │ │ └── entrypoint.sh # 启动链路 + 自检 + 自愈 │ └── ubuntu/ │ ├── 24.04/Dockerfile # Ubuntu 24.04 + Android SDK + AVD │ ├── 22.04/ │ ├── 20.04/ │ └── 18.04/ ├── source/ │ └── android_source_dl.sh # AOSP 源码下载(清华 TUNA 镜像) └── tools/ # 预留:辅助脚本 ``` 启动链路: ``` entrypoint.sh ├─ 1. 准备 AVD 数据(/opt/avd 模板 → /data/avd 卷,版本不匹配时自愈重建) ├─ 2. Xvfb :99 虚拟显示 ├─ 3. x11vnc :99 → 5900 VNC 暴露 ├─ 4. emulator -avd android 启动模拟器(渲染到 :99) └─ 5. 等待 sys.boot_completed=1 就绪后前台常驻 ``` --- ## ⚙️ 配置项 ### 运行期环境变量(`docker-compose.yml` 的 `environment`) | 变量 | 默认值 | 说明 | |------|--------|------| | `SCREEN_RESOLUTION` | `1440x900x24` | 虚拟屏幕分辨率 | | `VNC_PORT` | `5900` | VNC 端口(host 模式直接使用宿主端口) | | `VNC_PASSWORD` | 空 | 设置后 VNC 需密码连接 | | `AVD_NAME` | `android` | AVD 名称 | | `EMULATOR_ARGS` | 空 | 追加给 `emulator` 的参数 | | `BOOT_TIMEOUT` | `3600` | 等待开机完成的秒数 | | `ADB_TIMEOUT` | `600` | 等待 `adb wait-for-device` 的秒数 | | `DISPLAY` | `:99` | X display 编号 | 示例: ```yaml services: android-emu: environment: SCREEN_RESOLUTION: "1920x1080x24" VNC_PASSWORD: "123456" EMULATOR_ARGS: "-memory 4096 -cores 8" BOOT_TIMEOUT: 5400 ``` ### 构建参数(`docker buildx bake`) | 参数 | 默认值 | 说明 | |------|--------|------| | `ANDROID_API` | `33` | 系统镜像 API level | | `CMDLINE_TOOLS_URL` | Google 官方 | cmdline-tools 下载地址 | | `SDK_PROXY_HOST` / `SDK_PROXY_PORT` | 空 / `8080` | `sdkmanager` 下载系统镜像的代理 | | `HTTP_PROXY` / `HTTPS_PROXY` | 空 | apt / wget / git 代理 | --- ## 🔧 进阶用法 ### 切换 Android 版本 ```bash ./run.sh stop ./run.sh reset_avd # 建议执行;不清也会由 entrypoint 自动重建 AVD ./run.sh up 34 # Android 14 ``` 对应关系:`33` = Android 13(默认)、`34` = Android 14、`35` = Android 15、`36` = Android 16。 也可用环境变量:`ANDROID_API=35 ./run.sh`。 > ⚠️ **无 KVM 时建议使用 33**。Android 15 在纯软件模拟(TCG)下会因宿主机 CPU 特性缺失, > 出现 `system_app` 反复 ANR、长时间无法开机的问题。 ### 启用 KVM 加速 1. BIOS 开启虚拟化(Intel VT-x / AMD SVM) 2. 宿主机确认存在 `/dev/kvm` 3. 在 `docker-compose.yml` 中追加: ```yaml environment: EMULATOR_ARGS: "-accel on" ``` `docker-compose.yml` 已默认挂载 `/dev/kvm` 并开启 `privileged`。 ### 网络不佳时使用代理 ```bash # sdkmanager 走 Java 网络栈,需单独指定代理 SDK_PROXY_HOST=127.0.0.1 SDK_PROXY_PORT=7890 ./run.sh up 35 # apt / wget 代理 HTTP_PROXY=http://127.0.0.1:7890 HTTPS_PROXY=http://127.0.0.1:7890 ./run.sh ``` ### 下载 AOSP 源码 ```bash ./run.sh dl_aosp # 默认 android-13.0.0_r82 ./run.sh dl_aosp android-14.0.0_r21 # 指定 Tag ``` 源码落在 `source//`,使用清华 TUNA 镜像,并已规避 repo 工具在 Python 3.12+ 下的兼容问题。 ### 安装 APK ```bash # 把 APK 放到仓库根目录(容器 /workspace 与宿主机实时同步) adb connect localhost:5555 adb install -r app.apk ``` ### 截图 / 录屏 ```bash adb exec-out screencap -p > screen.png adb shell screenrecord --time-limit 10 /sdcard/demo.mp4 && adb pull /sdcard/demo.mp4 ``` --- ## ❓ 常见问题
1. FATAL: Broken AVD system path ... android-35/... is not a valid directory 原因:AVD 数据卷中残留旧版本 `config.ini`,其 `image.sysdir.1` 指向当前 SDK 不存在的系统镜像。 处理:`entrypoint.sh` 已内置自愈(检测到 sysdir 不存在时用镜像内模板重建 AVD); 若仍异常,手动清理: ```bash ./run.sh reset_avd && ./run.sh ``` > 直接执行 `docker compose down -v` 会报 `required variable PROJECT_ROOT is missing`, > 请统一使用 `./run.sh reset_avd`。
2. 模拟器启动很慢 / 长时间卡在 "等待 Android 启动完成" 无 `/dev/kvm` 时走纯软件模拟,Android 13 通常需 10~30 分钟属正常。 可观察进度: ```bash ./run.sh shell adb shell getprop sys.boot_completed # 空=启动中,1=完成 adb logcat -s ActivityManager | tail -20 ``` 超过 `BOOT_TIMEOUT`(默认 3600 秒)会判失败并重启,可调大该值。
3. adb server version (39) doesn't match this client (41) 容器内同时存在 SDK 的 adb(41)与模拟器自带的 adb(39)。首次执行 `adb` 命令时 新版客户端会重启 daemon,出现一次性 `offline` 抖动,随后即恢复正常,可忽略。
4. Emulator 启动后立刻退出(Qt / X server 相关) `entrypoint.sh` 已处理两类残留:启动前清理 `/tmp/.X*-lock`(否则 Xvfb 报 `Server is already active for display 99`)与 AVD 目录下的 `*.lock` (否则报 `Running multiple emulators with the same AVD`); 并强制 `QT_QPA_PLATFORM=xcb` 避免 Qt 插件初始化失败。
5. 端口 5900 被占用 容器使用 host 网络模式直接占用宿主端口。修改 `VNC_PORT` 环境变量换端口即可。
6. 进入 ./run.sh shell 后看不到安卓目录 `./run.sh shell` 进入的是 **Ubuntu 容器**,`/workspace` 是宿主机工程目录的挂载。 安卓系统运行在模拟器虚拟机内,需通过 `adb shell` 访问: ```bash ./run.sh shell adb shell # 提示符变为 emu64x:/ $ ``` > 注意:安卓内没有 `adb` 客户端,`adb` 是宿主机/容器侧工具,需先 `exit` 回容器再执行。
--- ## 🤝 参与贡献 1. Fork 本仓库并新建分支:`git checkout -b feat/your-feature` 2. 提交改动:`git commit -m "feat: 描述你的改动"` 3. 推送并创建 Pull Request 提交前建议验证: ```bash bash -n run.sh docker/scripts/entrypoint.sh # 语法检查 shellcheck docker/scripts/entrypoint.sh run.sh # 静态检查(可选) ./run.sh rebuild # 无缓存重建并启动验证 ``` --- ## 📄 许可证 本项目基于 [MIT License](./LICENSE) 开源,Copyright (c) 2026 pangxiongfei。 Android 是 Google LLC 的商标,Android SDK / Emulator 遵循其各自的 [Android Software Development Kit License Agreement](https://developer.android.com/studio/terms)。 本仓库仅提供自动化构建脚本,不分发 Android 系统镜像。