Android 模拟器是 AOSP 生态中最为关键的开发者工具之一。它绝非简单的仿真器,而是一套完整的系统级虚拟机,在经过定制修改的 QEMU 管理程序内运行量产版 Android 系统镜像;在 Linux 平台借助 KVM 实现硬件加速,在其余平台则使用 HAXM / 虚拟机框架完成加速。本章由内到外剖析模拟器:QEMU 执行引擎、Goldfish 与 Ranchu 虚拟硬件平台、衔接虚拟设备与模拟器宿主机的客户侧 HAL 实现、面向云环境的替代方案 Cuttlefish,以及快照、多显示器、可折叠设备仿真等一系列开发者功能,正是这些能力让模拟器成为不可或缺的工具。
支撑模拟器运行的设备树位于 AOSP 源码的device/generic/goldfish/目录。第二个虚拟设备平台 Cuttlefish,代码存放于device/google/cuttlefish/。这两个目录合计包含数十万行 C++ 代码、Shell 脚本、SELinux 策略与 Makefile 配置,这些内容定义了无实体硬件时,"一台 Android 设备" 的具体形态。
60.1 模拟器架构总览
60.1.1 软件栈
Android 模拟器基于 QEMU 的定制分支构建,QEMU 是开源的机器仿真与虚拟化工具。开发者在命令行输入emulator指令时,下面这套分层架构便开始工作:
- 宿主机(Linux/macOS/Windows)
-
Android 模拟器二进制程序(emulator、qemu‑system‑*)
- QEMU 核心(TCG 用于软件仿真;KVM/HAXM 用于硬件加速)
- 虚拟 CPU(vCPU):执行 ARM/x86/RISC‑V 指令
- 虚拟内存管理(影子页表 / EPT)
- 中断控制器(ARM 平台为 GICv2/v3;x86 平台为 IOAPIC)
- Goldfish/Ranchu 虚拟硬件
- goldfish‑pipe:宿主机与客户机之间的通信通道
- virtio‑gpu:GPU 透传 / 宿主机渲染
- virtio‑net:虚拟网络
- virtio‑input:触摸、键盘、传感器
- virtio‑blk:块设备仿真
- virtio‑console:串口 / 控制台端口
- 模拟器 UI /gRPC 控制接口
- 外观渲染、扩展控制面板
- 快照管理
- 位置 / 电话 / 电池仿真
Host machine (Linux/macOS/Windows)
|
+-- Android Emulator binary (emulator, qemu-system-*)
|
+-- QEMU core (TCG for software emulation, or KVM/HAXM for HW accel)
| |
| +-- Virtual CPU (vCPU) executing ARM/x86/RISC-V instructions
| +-- Virtual memory management (shadow page tables / EPT)
| +-- Interrupt controller (GICv2/v3 for ARM, IOAPIC for x86)
|
+-- Goldfish/Ranchu virtual hardware
| +-- goldfish-pipe: host<->guest communication channel
| +-- virtio-gpu: GPU passthrough / host rendering
| +-- virtio-net: virtual networking
| +-- virtio-input: touch, keyboard, sensors
| +-- virtio-blk: block device emulation
| +-- virtio-console: serial/console ports
|
+-- Emulator UI / gRPC control interface
+-- Skin rendering, Extended Controls
+-- Snapshot management
+-- Location / Telephony / Battery simulation - QEMU 核心(TCG 用于软件仿真;KVM/HAXM 用于硬件加速)
-
60.1.2 执行模式
模拟器支持两种基础执行模式:
KVM 加速模式(Linux):客户机代码借助基于内核的虚拟机模块 KVM,直接在宿主机 CPU 上原生运行。该模式性能最优,当客户机与宿主机架构相同时优先启用(x86 客户机运行在 x86 宿主机,ARM 客户机运行在 ARM 宿主机)。启用 KVM 后,绝大多数客户机指令可以接近原生速度执行;只有 IO、页表操作这类特权操作会陷入模拟器完成处理。
软件翻译模式(TCG):QEMU 的微型代码生成器 TCG,实时将客户机指令翻译为宿主机指令。用于架构不匹配的场景,例如在 x86 宿主机运行 ARM 客户机镜像。虽然性能远低于 KVM,但 TCG 实现了跨架构开发。
macOS 平台使用苹果虚拟机框架替代 KVM;Windows 平台则使用英特尔 HAXM(硬件加速执行管理器)或者 Windows 虚拟机平台 WHPX,实现同等能力。
60.1.3 高层数据流

核心认知:模拟器并不是 "模拟" Android,而是真正运行 Android。内核是真实的 Linux 内核,用户空间镜像和实体设备出厂镜像基本一致。模拟器的职责,就是提供这套真实软件所期望的虚拟硬件。
60.1.4 关键源码目录
| 目录 | 用途 |
|---|---|
device/generic/goldfish/ |
Goldfish 虚拟设备定义、HAL、初始化脚本 |
device/google/cuttlefish/ |
Cuttlefish 虚拟设备定义 |
device/generic/goldfish/hals/ |
硬件抽象层 HAL 实现 |
device/generic/goldfish/init/ |
模拟器启动的 init RC 脚本 |
device/generic/goldfish/sepolicy/ |
模拟器专属域的 SELinux 策略 |
device/generic/goldfish/board/ |
板级配置(区分不同架构) |
device/generic/goldfish/product/ |
产品配置 Makefile |
60.1.5 产品配置
模拟器定义了若干产品目标,在device/generic/goldfish/AndroidProducts.mk中声明:
Go
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/64bitonly/product/sdk_phone64_x86_64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone16k_x86_64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone64_x86_64_minigbm.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone64_x86_64_riscv64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_tablet_arm64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_tablet_x86_64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone64_arm64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone64_arm64_minigbm.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone16k_arm64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_phone64_arm64_riscv64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_slim_x86_64.mk \
$(LOCAL_DIR)/64bitonly/product/sdk_slim_arm64.mk
这些目标覆盖 x86_64、ARM64、RISC‑V 架构;同时包含手机、平板、精简版等不同设备形态,以及标准 /minigbm 两类图形后端。
60.2 Goldfish 设备平台
"Goldfish" 是 Android 模拟器初代虚拟硬件平台。该名称指代 QEMU 向客户机内核呈现的一整套虚拟设备(定时器、中断控制器、IO 总线等)。随着迭代,绝大多数原始的自定义 Goldfish 设备,已经在现代 Ranchu 平台替换为标准 virtio 设备,但 Goldfish 这个名称依旧保留在 AOSP 源码树中。
60.2.1 产品配置继承层级
Goldfish 产品配置采用分层继承结构:

根配置文件为device/generic/goldfish/product/generic.mk,它定义模拟器设备的核心配置,节选如下:
PRODUCT_VENDOR_PROPERTIES += \
ro.hardware.power=ranchu \
ro.kernel.qemu=1 \
ro.soc.manufacturer=AOSP \
ro.soc.model=ranchu
属性ro.kernel.qemu=1是框架用来识别当前运行在模拟器内部的标志性标志。SoC 型号标识为ranchu,即模拟器虚拟平台的现代代号。
60.2.2 板级配置
板级配置存放于device/generic/goldfish/board/,每种架构变体拥有独立子目录:
| 目录 | 架构 |
|---|---|
board/emu64x/ |
x86_64 |
board/emu64a/ |
ARM64 |
board/emu64xr/ |
x86_64 + RISC‑V(原生桥接) |
board/emu64ar/ |
ARM64 + RISC‑V(原生桥接) |
board/emu64x16k/ |
x86_64,16KB 页大小 |
board/emu64a16k/ |
ARM64,16KB 页大小 |
全部架构均继承board/BoardConfigCommon.mk,该文件定义通用板级配置,关键片段:
TARGET_BOOTLOADER_BOARD_NAME := goldfish_$(TARGET_ARCH)
# 编译OpenGL ES仿真的客户机与宿主机库
BUILD_EMULATOR_OPENGL := true
BUILD_QEMU_IMAGES := true
USE_OPENGL_RENDERER := true
# 模拟器不支持稀疏镜像格式
TARGET_USERIMAGES_SPARSE_EXT_DISABLED := true
# 模拟器属于非A/B设备
AB_OTA_UPDATER := none
# 模拟器需要super.img
BOARD_BUILD_SUPER_IMAGE_BY_DEFAULT := true
# 8G + 8M
BOARD_SUPER_PARTITION_SIZE ?= 8598323200
BOARD_SUPER_PARTITION_GROUPS := emulator_dynamic_partitions
关键要点:
- 模拟器使用 super 分区与动态分区,对齐现代实体设备;
- 属于非 A/B 设备,没有双分区无缝 OTA 能力;
- 同时编译客户机侧、宿主机侧的 OpenGL ES 仿真库;
- WiFi 子系统基于 NL80211 与内核模块
mac80211_hwsim,仿真无线网络接口。
60.2.3 HAL 实现
Goldfish 设备平台的核心是整套 HAL(硬件抽象层)实现,代码位于device/generic/goldfish/hals/,承担 Android 硬件接口与模拟器虚拟设备之间的桥接工作。

60.2.3.1 音频 HAL
路径:device/generic/goldfish/hals/audio/
音频 HAL 实现android.hardware.audio@7.1接口,借助 TinyALSA 访问 QEMU 提供的虚拟声卡。实现包含如下文件:
primary_device.cpp:主音频设备,处理音量、麦克风静音、流创建stream_out.cpp / stream_in.cpp:输出流、输入流实现talsa.cpp:TinyALSA 封装层device_port_sink.cpp / device_port_source.cpp:音频路由端口抽象
primary_device.cpp节选:
cpp
constexpr size_t kInBufferDurationMs = 15;
constexpr size_t kOutBufferDurationMs = 22;
Device::Device() {}
Return<Result> Device::initCheck() {
return Result::OK;
}
Return<Result> Device::setMasterVolume(float volume) {
if (isnan(volume) || volume < 0 || volume > 1.0) {
return FAILURE(Result::INVALID_ARGUMENTS);
}
mMasterVolume = volume;
updateOutputStreamVolume(mMasterMute ? 0.0f : volume);
return Result::OK;
}
音频延迟参数在产品 Makefile 配置:
Go
PRODUCT_VENDOR_PROPERTIES += \
ro.hardware.audio.tinyalsa.period_count=4 \
ro.hardware.audio.tinyalsa.period_size_multiplier=2 \
ro.hardware.audio.tinyalsa.host_latency_ms=80
80ms 的宿主机延迟高于实体设备(实体设备目标 5‑20ms),原因是音频数据需要经过 QEMU 虚拟声卡再流转到宿主机音频子系统。
60.2.3.2 摄像头 HAL
路径:device/generic/goldfish/hals/camera/
摄像头 HAL 实现 AIDL Camera Provider 接口,支持多种摄像头数据源:
- QEMU 摄像头(
BaseQemuCamera、GasQemuCamera、MinigbmQemuCamera):对接宿主机摄像头或者虚拟场景,通过 QEMU 管道机制通信; - 虚拟旋转摄像头(
FakeRotatingCamera):合成测试用摄像头,输出旋转 3D 图案。
与 QEMU 宿主机通信基于qemu_channel抽象,qemu_channel.cpp节选:
cpp
const char kServiceName[] = "camera";
base::unique_fd qemuOpenChannel() {
return base::unique_fd(qemud_channel_open(kServiceName));
}
int qemuRunQuery(const int fd,
const char* const query,
const size_t querySize,
std::vector<uint8_t>* result) {
int e = qemu_pipe_write_fully(fd, query, querySize);
if (e < 0) {
return FAILURE(e);
}
std::vector<uint8_t> reply;
e = qemuReceiveMessage(fd, &reply);
if (e < 0) {
return e;
}
// ... 解析ok/ko应答 ...
}
Camera Provider 使用带device@1.1/internal/前缀的 ID 体系,CameraProvider.cpp节选:
cpp
constexpr char kCameraIdPrefix[] = "device@1.1/internal/";
std::string getLogicalCameraId(const int index) {
char buf[sizeof(kCameraIdPrefix) + 8];
snprintf(buf, sizeof(buf), "%s%d", kCameraIdPrefix, index);
return buf;
}
60.2.3.3 传感器 HAL
路径:device/generic/goldfish/hals/sensors/
传感器 HAL 是模拟器硬件虚拟化极具代表性的模块,基于 QEMU 传感器协议实现android.hardware.sensors@2.1。
完整仿真传感器列表定义在sensor_list.cpp:
cpp
const char* const kQemuSensorName[] = {
"acceleration",
"gyroscope",
"magnetic-field",
"orientation",
"temperature",
"proximity",
"light",
"pressure",
"humidity",
"magnetic-field-uncalibrated",
"gyroscope-uncalibrated",
"hinge-angle0",
"hinge-angle1",
"hinge-angle2",
"heart-rate",
"rgbc-light",
"wrist-tilt",
"acceleration-uncalibrated",
"heading",
"low‑latency‑off‑body‑detect",
};
合计 20 个虚拟传感器,包含加速度计、陀螺仪、磁场、方向、温度、接近光、亮度、气压、湿度、铰链角度、心率、手腕倾斜姿态等。
通信协议 :传感器 HAL 通过 QEMU 管道使用简单文本协议通信。multihal_sensors_qemu.cpp节选:
cpp
bool MultihalSensors::setSensorsReportingImpl(SensorsTransport& st,
const int sensorHandle,
const bool enabled) {
char buffer[64];
int len = snprintf(buffer, sizeof(buffer),
"set:%s:%d",
getQemuSensorNameByHandle(sensorHandle),
(enabled ? 1 : 0));
if (st.Send(buffer, len) < 0) {
ALOGE("%s:%d: send for %s failed", __func__, __LINE__, st.Name());
return false;
} else {
return true;
}
}
协议指令:
list‑sensors:查询宿主机支持的传感器,返回位掩码set:<sensor_name>:<0|1>:启用 / 关闭指定传感器set‑delay:<ms>:设置上报周期,单位毫秒time:<ns>:客户机时钟同步
传感器事件解析 :宿主机下发传感器文本消息,例如acceleration:9.8:0.0:0.1,由parseQemuSensorEventLocked完成解析。
cpp
void MultihalSensors::parseQemuSensorEventLocked(QemuSensorsProtocolState* state) {
char buf[256];
const int len = m_sensorsTransport->Receive(buf, sizeof(buf) - 1);
// ...
if (const char* values = testPrefix(buf, end, "acceleration", ':')) {
if (sscanf(values, "%f:%f:%f",
&vec3->x, &vec3->y, &vec3->z) == 3) {
vec3->status = SensorStatus::ACCURACY_MEDIUM;
event.timestamp = nowNs + state->timeBiasNs;
event.sensorHandle = kSensorHandleAccelerometer;
event.sensorType = SensorType::ACCELEROMETER;
postSensorEventLocked(event);
parsed = true;
}
}
// ...陀螺仪、磁场、接近光、亮度等同类处理逻辑
}
架构上使用专用监听线程qemuSensorListenerThread与批处理线程batchThread,专门处理连续上报模式传感器。

60.2.3.4 GNSS HAL
路径:device/generic/goldfish/hals/gnss/
GNSS 全球导航卫星系统 HAL,提供虚拟 GPS 数据。核心类GnssHwConn打开指向gps服务的 QEMU 管道。GnssHwConn.cpp节选:
cpp
GnssHwConn::GnssHwConn(IDataSink& sink) {
mDevFd.reset(qemu_pipe_open_ns("qemud", "gps", O_RDWR));
if (!mDevFd.ok()) {
ALOGE("%s:%d: qemu_pipe_open_ns failed", __func__, __LINE__);
return;
}
unique_fd threadsFd;
if (!::android::base::Socketpair(AF_LOCAL, SOCK_STREAM, 0,
&mCallersFd, &threadsFd)) {
ALOGE("%s:%d: Socketpair failed", __func__, __LINE__);
mDevFd.reset();
return;
}
std::promise<void> isReadyPromise;
const int devFd = mDevFd.get();
mThread = std::thread([devFd, threadsFd = std::move(threadsFd), &sink,
&isReadyPromise]() {
GnssHwListener listener(sink);
isReadyPromise.set_value();
workerThread(devFd, threadsFd.get(), listener);
});
isReadyPromise.get_future().wait();
}
工作线程借助 epoll 同时监听 QEMU 设备文件描述符(接收宿主机 GPS 数据)与命令 fd(接收关闭信号)。当模拟器扩展控制面板下发 GPS 定位点,数据依次流经 QEMU 的 gps 服务、管道、GnssHwListener解析 NMEA 语句,最终送入 Android LocationManager。
GNSS 设备节点由 init 脚本创建软链接:
cpp
on property:vendor.qemu.vport.gnss=*
symlink ${vendor.qemu.vport.gnss} /dev/gnss0
对应的 SELinux 策略赋予 GNSS HAL 访问 vsock 套接字权限:
vndbinder_use(hal_gnss_default);
allow hal_gnss_default self:vsock_socket create_socket_perms_no_ioctl;
60.2.3.5 无线通信(电话)HAL
路径:device/generic/goldfish/hals/radio/
无线通信 HAL 实现全套电话 AIDL 接口:
RadioModem:调制解调器控制(开关机、IMEI、无线能力)RadioSim:SIM 卡管理RadioNetwork:网络注册、信号强度、小区信息RadioData:数据通话与链路建立RadioVoice:语音通话RadioMessaging:短信RadioIms:IP 多媒体子系统 IMS
无线通信 HAL 通过通道向调制解调器仿真器发送 AT 指令。RadioModem.cpp节选:
cpp
constexpr char kBasebandversion[] = "1.0.0.0";
constexpr char kModemUuid[] = "com.android.modem.simulator";
ScopedAStatus RadioModem::getBasebandVersion(const int32_t serial) {
NOT_NULL(mRadioModemResponse)->getBasebandVersionResponse(
makeRadioResponseInfo(serial), kBasebandversion);
return ScopedAStatus::ok();
}
AT 指令接口基于AtChannel抽象,采用请求‑应答模式:
cpp
ScopedAStatus RadioModem::getImei(const int32_t serial) {
mAtChannel->queueRequester([this, serial](
const AtChannel::RequestPipe requestPipe) -> bool {
const AtResponsePtr response =
mAtConversation(requestPipe, atCmds::getIMEI,
[](const AtResponse& response) -> bool {
return response.holds<std::string>();
});
if (!response) {
NOT_NULL(mRadioModemResponse)->getImeiResponse(
makeRadioResponseInfo(serial,
FAILURE(RadioError::INTERNAL_ERR)), {});
return false;
} else if (const std::string* imeiSvn =
response->get_if<std::string>()) {
modem::ImeiInfo imeiInfo = {
.type = modem::ImeiInfo::ImeiType::PRIMARY,
.imei = imeiSvn->substr(0, 15),
.svn = imeiSvn->substr(15, 2),
};
NOT_NULL(mRadioModemResponse)->getImeiResponse(
makeRadioResponseInfo(serial), std::move(imeiInfo));
return true;
}
// ...
});
return ScopedAStatus::ok();
}
产品 Makefile 配置支持 5G NR、LTE、TD‑SCDMA、CDMA、EVDO、GSM、WCDMA 多种网络制式:
cpp
# NR 5G, LTE, TD‑SCDMA, CDMA, EVDO, GSM and WCDMA
PRODUCT_VENDOR_PROPERTIES += ro.telephony.default_network=33
60.2.3.6 指纹 HAL
路径:device/generic/goldfish/hals/fingerprint/
指纹 HAL 实现 AIDL IFingerprint服务,实现相对简单。hal.cpp节选:
cpp
constexpr char HW_COMPONENT_ID[] = "FingerprintSensor";
constexpr char XW_VERSION[] = "ranchu/fingerprint/aidl";
constexpr char FW_VERSION[] = "1";
constexpr char SERIAL_NUMBER[] = "00000001";
constexpr char SW_COMPONENT_ID[] = "matchingAlgorithm";
ndk::ScopedAStatus Hal::getSensorProps(std::vector<SensorProps>* out) {
// ...
SensorProps props;
props.commonProps.sensorId = 0;
props.commonProps.sensorStrength = common::SensorStrength::STRONG;
props.commonProps.maxEnrollmentsPerUser =
Storage::getMaxEnrollmentsPerUser();
props.sensorType = FingerprintSensorType::REAR;
props.supportsNavigationGestures = false;
props.supportsDetectInteraction = true;
// ...
}
模拟器扩展控制面板提供虚拟指纹扫描器,经由该 HAL 触发认证事件。
60.2.3.7 硬件合成器 HWC3 HAL
路径:device/generic/goldfish/hals/hwc3/
硬件合成器 HAL 是模拟器所有 HAL 中实现最复杂的模块,提供两种合成模式:
- HostFrameComposer(宿主机帧合成器):把合成工作交给宿主机 GPU,实现硬件加速渲染;
- GuestFrameComposer(客户机帧合成器):客户机侧基于 DRM 与 libyuv 完成合成,作为宿主机渲染不可用时的回退方案。
宿主机帧合成器使用gfxstream协议向模拟器进程传递合成指令。HostFrameComposer.cpp节选:
cpp
#include "gfxstream/guest/goldfish_sync.h"
#include "virtgpu_drm.h"
namespace aidl::android::hardware::graphics::composer3::impl {
// ...
static bool isMinigbmFromProperty() {
static constexpr const auto kGrallocProp = "ro.hardware.gralloc";
const auto grallocProp =
::android::base::GetProperty(kGrallocProp, "");
if (grallocProp == "minigbm") {
return true;
} else {
return false;
}
}
客户机帧合成器回退实现,GuestFrameComposer.cpp节选:
cpp
#include "Drm.h"
#include "Layer.h"
#include "DisplayFinder.h"
std::array<std::int8_t, 16> ToLibyuvColorMatrix(
const std::array<float, 16>& in) {
// 将HAL色彩矩阵转换为libyuv格式
std::array<std::int8_t, 16> out;
for (int r = 0; r < 4; r++) {
for (int c = 0; c < 4; c++) {
int indexIn = (4 * r) + c;
int indexOut = (4 * c) + r;
float clampedValue = std::max(-128.0f,
std::min(127.0f, in[indexIn] * 66.0f + 0.5f));
out[indexOut] = static_cast<std::int8_t>(clampedValue);
}
}
return out;
}
HWC3 完整实现了基于 DRM 的显示管理,封装 plane、CRTC、connector 抽象;相关源码包含Drm.cpp、DrmClient.cpp、DrmConnector.cpp、DrmCrtc.cpp、DrmDisplay.cpp、DrmPlane.cpp、DrmSwapchain.cpp、DrmAtomicRequest.cpp、DrmBuffer.cpp、DrmEventListener.cpp、DrmMode.cpp。
60.2.3.8 Gralloc 图形内存分配器 HAL
路径:device/generic/goldfish/hals/gralloc/
图形内存分配器负责分配可供 CPU、GPU 访问的缓冲区。allocator.cpp节选:
cpp
struct GoldfishAllocator : public BnAllocator {
GoldfishAllocator()
: mHostConn(HostConnection::createUnique(kCapsetNone))
, mDebugLevel(getDebugLevel()) {}
ndk::ScopedAStatus allocate2(const BufferDescriptorInfo& desc,
const int32_t count,
AllocationResult* const outResult) override {
// ...
const uint64_t usage = toUsage64(desc.usage);
if (needCpuBuffer(usage)) {
req.needImageAllocation = true;
// ...
} else {
req.needImageAllocation = false;
// ...
}
// ...
}
};
核心设计:CPU 缓冲区借助GoldfishAddressSpaceBlock在客户机内存分配;GPU 缓冲区在宿主机侧表示为颜色缓冲区。缓冲区需要 GPU 访问时,分配器通过渲染控制编码器,在宿主机创建颜色缓冲区。
cpp
if (needGpuBuffer(req.usage)) {
hostHandleRefCountFd.reset(qemu_pipe_open("refcount"));
hostHandle = rcEnc.rcCreateColorBufferDMA(
&rcEnc, req.width, req.height,
req.glFormat, static_cast<int>(req.emuFwkFormat));
if (qemu_pipe_write(hostHandleRefCountFd.get(),
&hostHandle,
sizeof(hostHandle)) != sizeof(hostHandle)) {
rcEnc.rcCloseColorBuffer(&rcEnc, hostHandle);
return FAILURE(nullptr);
}
}
分配器支持大量像素格式:RGBA_8888、RGB_565、RGBA_FP16、RGBA_1010102、YV12、YCBCR_420_888、YCBCR_P010。Mapper 库后缀为ranchu:
cpp
ndk::ScopedAStatus getIMapperLibrarySuffix(std::string* outResult) override {
*outResult = "ranchu";
return ndk::ScopedAStatus::ok();
}
60.2.4 Init 初始化脚本
模拟器启动流程由device/generic/goldfish/init/目录下 init 脚本控制,主脚本为init.ranchu.rc,关键片段:
cpp
on early-init
mount proc proc /proc remount hidepid=2,gid=3009
setprop ro.cpuvulkan.version ${ro.boot.qemu.cpuvulkan.version}
setprop ro.hardware.egl ${ro.boot.hardwareegl:-emulation}
setprop ro.hardware.vulkan ${ro.boot.hardware.vulkan}
setprop ro.opengles.version ${ro.boot.opengles.version}
setprop dalvik.vm.heapsize ${ro.boot.dalvik.vm.heapsize:-192m}
setprop debug.hwui.renderer ${ro.boot.debug.hwui.renderer:-skiagl}
setprop vendor.qemu.dev.bootcomplete 0
start vendor.dlkm_loader
on init
write /sys/block/zram0/comp_algorithm lz4
write /proc/sys/vm/page‑cluster 0
start qemu‑props
on post‑fs‑data
mkdir /data/vendor/var 0755 root root
mkdir /data/vendor/var/run 0755 root root
start ranchu‑device‑state
start ranchu‑adb‑setup
模拟器专属功能服务:
qemu‑props:读取模拟器宿主机的启动属性,并设置为 Android 系统属性ranchu‑adb‑setup:配置模拟器 ADBranchu‑net:配置网络(VirtIO WiFi、模拟器间互通)ranchu‑setup:系统启动完成后执行后置配置goldfish‑logcat:将 logcat 输出通过 virtio 控制台/dev/hvc1转发到宿主机bt_vhci_forwarder:转发蓝牙 HCI 流量
渲染子系统默认参数在early‑init阶段配置:
setprop ro.hardware.egl ${ro.boot.hardwareegl:-emulation}
# 默认skiagl:skia使用GLES完成渲染
setprop debug.hwui.renderer ${ro.boot.debug.hwui.renderer:-skiagl}
# 默认skiaglthreaded
setprop debug.renderengine.backend \
${ro.boot.debug.renderengine.backend:-skiaglthreaded}
60.2.5 SELinux 策略
模拟器在device/generic/goldfish/sepolicy/定义自定义 SELinux 策略。vendor 策略目录包含约 60 个策略文件,覆盖全部模拟器专属域与服务。
关键策略文件:
| 文件 | 用途 |
|---|---|
qemu_props.te |
qemu‑props属性设置服务策略 |
hal_sensors_default.te |
传感器 HAL 访问 vsock 套接字权限 |
hal_gnss_default.te |
GNSS HAL 访问 vsock 与 binder 节点权限 |
hal_radio_default.te |
无线通信 HAL 访问调制解调器仿真器权限 |
hal_camera_default.te |
摄像头 HAL 访问 QEMU 管道权限 |
hal_graphics_composer_default.te |
HWC3 访问 DRM、GPU 权限 |
hal_graphics_allocator_default.te |
Gralloc 缓冲区分配策略 |
goldfish_setup.te |
模拟器初始化脚本策略 |
goldfish_ip.te |
网络配置策略 |
qemu_props.te节选:
type qemu_props, domain;
type qemu_props_exec, vendor_file_type, exec_type, file_type;
init_daemon_domain(qemu_props)
set_prop(qemu_props, qemu_hw_prop)
set_prop(qemu_props, qemu_sf_lcd_density_prop)
set_prop(qemu_props, vendor_qemu_prop)
set_prop(qemu_props, vendor_net_share_prop)
allow qemu_props self:vsock_socket create_socket_perms_no_ioctl;
allow qemu_props sysfs:dir read;
allow qemu_props sysfs:dir open;
allow qemu_props sysfs:file getattr;
allow qemu_props sysfs:file read;
allow qemu_props sysfs:file open;
qemu_props域被授予设置特定分类属性,以及通过 vsock(VirtIO socket)通信的权限;vsock 是客户机内核与 QEMU 宿主机最主要的通信通道。
60.2.6 完整软件包清单
模拟器产品配置会引入大量软件包,device/generic/goldfish/product/generic.mk中分类如下:
核心图形栈
PRODUCT_PACKAGES += \
vulkan.ranchu \
libandroidemu \
libOpenglCodecCommon \
libOpenglSystemCommon \
android.hardware.graphics.composer3‑service.ranchu
vulkan.ranchu提供模拟器 Vulkan 可安装客户端驱动 ICD;libandroidemu与 OpenGL 编解码 / 系统库实现 GPU 仿真流水线的客户机侧逻辑。
OpenGL ES 仿真库
PRODUCT_PACKAGES += \
libGLESv1_CM_emulation \
lib_renderControl_enc \
libEGL_emulation \
libGLESv2_enc \
libvulkan_enc \
libGLESv2_emulation \
libGLESv1_enc \
libEGL_angle \
libGLESv1_CM_angle \
libGLESv2_angle
库成对分工:
lib*_emulation:客户机侧 EGL/GLES 实现,拦截 API 调用lib*_enc:编码器,将 GLES/Vulkan 命令序列化为二进制流,传输到宿主机lib*_angle:基于 ANGLE、由 Vulkan 后端驱动的 GLES 实现
媒体编解码器
PRODUCT_PACKAGES += \
android.hardware.media.c2@1.0‑service‑goldfish \
libcodec2_goldfish_vp8dec \
libcodec2_goldfish_vp9dec \
libcodec2_goldfish_avcdec \
libcodec2_goldfish_hevcdec
Goldfish 媒体编解码器基于 Codec2 框架,视频解码交由 QEMU 宿主机完成,让模拟器内部也可以硬件加速视频播放。
合规 HAL(最简 Hello‑World 实现)
PRODUCT_PACKAGES += \
com.android.hardware.authsecret \
com.android.hardware.contexthub \
com.android.hardware.dumpstate \
android.hardware.health‑service.example \
android.hardware.health.storage‑service.default \
android.hardware.lights‑service.example \
com.android.hardware.neuralnetworks \
com.android.hardware.power \
com.android.hardware.thermal \
com.android.hardware.vibrator
这部分是最小实现,仅满足 CTS 兼容性测试套件要求,不会执行真实硬件操作,只提供框架需要的 AIDL 服务接口。
条件编译包选择
产品 Makefile 通过编译标志条件引入组件:
| 编译标志 | 默认值 | 置为 true 效果 |
|---|---|---|
EMULATOR_DISABLE_RADIO |
false | 禁用电话 HAL |
EMULATOR_VENDOR_NO_BIOMETRICS |
false | 禁用指纹 HAL |
EMULATOR_VENDOR_NO_GNSS |
false | 禁用 GNSS HAL |
EMULATOR_VENDOR_NO_SENSORS |
false | 禁用传感器 HAL |
EMULATOR_VENDOR_NO_CAMERA |
false | 禁用摄像头 HAL |
EMULATOR_VENDOR_NO_SOUND |
false | 禁用音频 HAL |
EMULATOR_VENDOR_NO_UWB |
false | 禁用 UWB 超宽带 HAL |
EMULATOR_VENDOR_NO_THREADNETWORK |
false | 禁用 Thread 网络 |
EMULATOR_VENDOR_NO_REBOOT_ESCROW |
false | 禁用重启托管功能 |
借助这些标志,可以编译出裁剪后的极简模拟器镜像,用于特定专项测试。
60.3 虚拟硬件
60.3.1 Goldfish‑Pipe:宿主机‑客户机通信
goldfish‑pipe 是 Android 客户机与 QEMU 宿主机之间的核心通信机制。它属于虚拟设备,提供双向字节流接口,类似 Unix 管道,但跨越虚拟机边界。

客户机侧 API :通过libqemu_pipe库调用接口:
qemu_pipe_open_ns(namespace, name, flags):打开指向特定宿主机服务的命名管道qemu_pipe_write_fully(fd, data, size):向管道写入完整数据qemu_pipe_read_fully(fd, data, size):从管道读取完整数据
qemud层在原始管道之上实现多路复用,单条管道连接之上可以打开多条逻辑通道。qemud.cpp节选:
cpp
int qemud_channel_open(const char* name) {
return qemu_pipe_open_ns("qemud", name, O_RDWR);
}
int qemud_channel_send(int pipe, const void* msg, int size) {
char header[5];
if (size < 0)
size = strlen((const char*)msg);
if (size == 0)
return 0;
if (size >= 64 * 1024) { // 使用二进制编码
uint32_t length32be = htonl(size | (1U << 31));
memcpy(header, &length32be, 4);
} else { // 使用十六进制字符编码
snprintf(header, sizeof(header), "%04x", size);
}
if (qemu_pipe_write_fully(pipe, header, 4)) {
return -1;
}
if (qemu_pipe_write_fully(pipe, msg, size)) {
return -1;
}
return 0;
}
int qemud_channel_recv(int pipe, void* msg, int maxsize) {
char header[5];
int size;
if (qemu_pipe_read_fully(pipe, header, 4)) {
return -1;
}
header[4] = 0;
if (sscanf(header, "%04x", &size) != 1) {
return -1;
}
if (size > maxsize) {
return -1;
}
if (qemu_pipe_read_fully(pipe, msg, size)) {
return -1;
}
return size;
}
协议采用长度前缀帧格式:
- 消息小于 64KB:4 位十六进制字符作为长度前缀,例如
001a; - 消息大于等于 64KB:4 字节大端二进制长度,最高比特置 1。
60.3.2 传感器 HAL 线程模型
传感器 HAL 拥有一套复杂多线程架构。头文件multihal_sensors.h暴露内部结构:
cpp
struct MultihalSensors : public ahs21::implementation::ISensorsSubHal {
using SensorsTransportFactory =
std::function<std::unique_ptr<SensorsTransport>()>;
MultihalSensors(SensorsTransportFactory);
~MultihalSensors();
private:
struct QemuSensorsProtocolState {
int64_t timeBiasNs = -500000000;
int32_t sensorsUpdateIntervalMs = 200;
static constexpr float kSensorNoValue = -1e+30;
// 变化上报型传感器(宿主机不维护状态)
float lastAmbientTemperatureValue = kSensorNoValue;
float lastProximityValue = kSensorNoValue;
float lastLightValue = kSensorNoValue;
float lastRelativeHumidityValue = kSensorNoValue;
float lastHingeAngle0Value = kSensorNoValue;
float lastHingeAngle1Value = kSensorNoValue;
float lastHingeAngle2Value = kSensorNoValue;
float lastHeartRateValue = kSensorNoValue;
float lastWristTiltMeasurement = -1;
};
// 批处理事件
struct BatchEventRef {
int64_t timestamp = -1;
int sensorHandle = -1;
int generation = 0;
bool operator<(const BatchEventRef &rhs) const {
// 注意:让top()返回时间戳最小元素
return timestamp > rhs.timestamp;
}
};
struct BatchInfo {
Event event;
int64_t samplingPeriodNs = 0;
int generation = 0;
};
QemuSensorsProtocolState m_protocolState;
std::priority_queue<BatchEventRef> m_batchQueue;
std::vector<BatchInfo> m_batchInfo;
std::condition_variable m_batchUpdated;
std::thread m_batchThread;
std::atomic<bool> m_batchRunning = true;
mutable std::mutex m_mtx;
};
一共三类线程:
- 主线程:处理 SensorService 发起的 HIDL/AIDL 调用(activate、batch、flush、injectSensorData_2_1);
- 传感器监听线程 qemuSensorListenerThread:从 QEMU 传输通道读取传感器数据,分发事件;使用 epoll 多路复用传输 fd 与命令 fd;
- 批处理线程 batchThread:实现连续模式传感器批上报;基于时间戳优先队列,决定下一条传感器事件的投递时机。
epoll 监听线程实现节选multihal_sensors_epoll.cpp:
cpp
bool MultihalSensors::qemuSensorListenerThreadImpl(
const int transportFd) {
const unique_fd epollFd(epoll_create1(0));
epollCtlAdd(epollFd.get(), transportFd);
epollCtlAdd(epollFd.get(), m_sensorThreadFd.get());
while (true) {
struct epoll_event events[2];
const int kTimeoutMs = 60000;
const int n = TEMP_FAILURE_RETRY(epoll_wait(
epollFd.get(), events, 2, kTimeoutMs));
for (int i = 0; i < n; ++i) {
const struct epoll_event* ev = &events[i];
const int fd = ev->data.fd;
if (fd == transportFd) {
if (ev->events & EPOLLIN) {
std::unique_lock<std::mutex> lock(m_mtx);
parseQemuSensorEventLocked(&m_protocolState);
}
} else if (fd == m_sensorThreadFd.get()) {
const int cmd = qemuSensortThreadRcvCommand(fd);
switch (cmd) {
case kCMD_QUIT: return false;
case kCMD_RESTART: return true;
}
}
}
}
}
kCMD_RESTART:批上报周期变更,需要重新配置传输通道时发送; kCMD_QUIT:HAL 关闭阶段发送。该设计支持监听线程重启,不需要销毁整个 HAL 实例。

60.3.3 显示设备发现与 VSync 垂直同步
HWC3 HAL 通过渲染控制编码器查询 QEMU 宿主机,完成显示设备发现。DisplayFinder.cpp节选:
cpp
static uint32_t getVsyncHzFromProperty() {
static constexpr const auto kVsyncProp = "ro.boot.qemu.vsync";
const auto vsyncProp =
::android::base::GetProperty(kVsyncProp, "");
uint64_t vsyncPeriod;
if (!::android::base::ParseUint(vsyncProp, &vsyncPeriod)) {
return 60; // 默认60Hz
}
return static_cast<uint32_t>(vsyncPeriod);
}
HWC3::Error findGoldfishPrimaryDisplay(
std::vector<DisplayMultiConfigs>* outDisplays) {
DEFINE_AND_VALIDATE_HOST_CONNECTION
hostCon->lock();
const int32_t vsyncPeriodNanos =
HertzToPeriodNanos(getVsyncHzFromProperty());
DisplayMultiConfigs display;
display.displayId = 0;
if (rcEnc->hasHWCMultiConfigs()) {
int count = rcEnc->rcGetFBDisplayConfigsCount(rcEnc);
display.activeConfigId =
rcEnc->rcGetFBDisplayActiveConfig(rcEnc);
for (int configId = 0; configId < count; configId++) {
display.configs.push_back(DisplayConfig(
configId,
rcEnc->rcGetFBDisplayConfigsParam(
rcEnc, configId, FB_WIDTH),
rcEnc->rcGetFBDisplayConfigsParam(
rcEnc, configId, FB_HEIGHT),
rcEnc->rcGetFBDisplayConfigsParam(
rcEnc, configId, FB_XDPI),
rcEnc->rcGetFBDisplayConfigsParam(
rcEnc, configId, FB_YDPI),
vsyncPeriodNanos));
}
}
// ...
}
显示发现逻辑向宿主机查询:
- 分辨率宽高:
FB_WIDTH、FB_HEIGHT; - DPI 每英寸点数:
FB_XDPI、FB_YDPI; - 刷新率:来自 boot 属性
ro.boot.qemu.vsync。
当宿主机支持多显示配置模式,会枚举全部可用配置,通过 HWC3 接口上报给 SurfaceFlinger。
60.3.4 音频写线程
音频 HAL 输出流使用独立写线程,搭配 FMQ 快速消息队列,实现与 AudioFlinger 低延迟通信。stream_out.cpp节选:
cpp
class WriteThread : public IOThread {
typedef MessageQueue<IStreamOut::WriteCommand,
kSynchronizedReadWrite> CommandMQ;
typedef MessageQueue<IStreamOut::WriteStatus,
kSynchronizedReadWrite> StatusMQ;
typedef MessageQueue<uint8_t,
kSynchronizedReadWrite> DataMQ;
public:
WriteThread(StreamOut *stream, const size_t mqBufferSize)
: mStream(stream)
, mCommandMQ(1)
, mStatusMQ(1)
, mDataMQ(mqBufferSize, true /* EventFlag */) {
// ...
EventFlag* rawEfGroup = nullptr;
status_t status = EventFlag::createEventFlag(
mDataMQ.getEventFlagWord(), &rawEfGroup);
mEfGroup.reset(rawEfGroup);
mThread = std::thread(&WriteThread::threadLoop, this);
}
};
FMQ 机制允许 AudioFlinger 写入音频数据,无需 Binder 往返;EventFlag借助共享内存,在 AudioFlinger 进程与 HAL 服务进程之间完成轻量信号通知。
60.3.5 唤醒锁管理
模拟器初始化脚本通过唤醒锁管理电源状态。init.setup.ranchu.sh节选:
cpp
allowsuspend=`getprop ro.boot.qemu.allowsuspend`
case "$allowsuspend" in
"") echo "emulator_wake_lock" > /sys/power/wake_lock
;;
1) echo "emulator_wake_lock" > /sys/power/wake_unlock
;;
*) echo "emulator_wake_lock" > /sys/power/wake_lock
;;
esac
默认情况下,模拟器持有永久唤醒锁emulator_wake_lock,阻止客户机进入深度休眠。对开发调试十分关键:休眠后的模拟器将失去响应。设置ro.boot.qemu.allowsuspend=1可以放开休眠,用于电源管理行为专项测试。
60.3.6 QEMU 属性服务
qemu‑props服务源码device/generic/goldfish/qemu‑props/qemu‑props.cpp,模拟器启动早期就会运行。作用是读取宿主机侧属性,设置为 Android 系统属性。
cpp
// Source: device/generic/goldfish/qemu-props/qemu-props.cpp
constexpr char kBootPropertiesService[] = "boot-properties";
constexpr char kHeartbeatService[] = "QemuMiscPipe";
int setBootProperties() {
unique_fd qemud;
for (int tries = 5; tries > 0; --tries) {
qemud = unique_fd(qemud_channel_open(kBootPropertiesService));
if (qemud.ok()) break;
else if (tries > 1) sleep(1);
else return FAILURE(1);
}
if (qemud_channel_send(qemud.get(), "list", -1) < 0) {
return FAILURE(1);
}
while (true) {
char temp[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2];
const int len = qemud_channel_recv(qemud.get(), temp, sizeof(temp) - 1);
if (len < 0 || len > (sizeof(temp) - 1) || !temp[0]) break;
temp[len] = '\0';
char* prop_value = strchr(temp, '=');
if (!prop_value) continue;
*prop_value = 0;
++prop_value;
// Properties are prefixed with "vendor." unless already prefixed
// or in the system properties list
if (need_prepend_prefix(temp, "vendor.")) {
snprintf(renamed_property, sizeof(renamed_property),
"vendor.%s", temp);
final_prop_name = renamed_property;
}
property_set(final_prop_name, prop_value);
}
return 0;
}
设置属性完成后,服务进入心跳循环,周期性向 QemuMiscPipe 服务发送 "heartbeat" 心跳消息。以此让模拟器主机检测虚拟机客户机是否存活且响应正常:
cpp
int main(const int argc, const char* argv[]) {
if ((argc == 2) && !strcmp(argv[1], "bootcomplete")) {
sendMessage("bootcomplete");
return 0;
}
int r = setBootProperties();
parse_virtio_serial();
sendHeartBeat();
while (s_QemuMiscPipe >= 0) {
if (android::base::WaitForProperty(
"vendor.qemu.dev.bootcomplete", "1",
std::chrono::seconds(5))) {
break;
}
sendHeartBeat();
}
while (s_QemuMiscPipe >= 0) {
usleep(30 * 1000000); // 30 seconds
sendHeartBeat();
}
// ...
}
源码路径:device/generic/goldfish/qemu‑props/qemu‑props.cpp
60.3.7 虚拟传感器
虚拟传感器(详见 60.2.3.3 节)由模拟器扩展控制界面驱动。当用户操作传感器控件(倾斜虚拟设备、修改接近传感器数值、调节光照等级),模拟器主机通过 QEMU 管道发送文本格式传感器事件。
传感器数据流:

传感器 HAL 会给未校准传感器数据增加校准噪声,以此通过 CTS 兼容性测试:
cpp
} else if (const char* values = testPrefix(buf, end,
"acceleration-uncalibrated", ':')) {
if (sscanf(values, "%f:%f:%f",
&uncal->x, &uncal->y, &uncal->z) == 3) {
// A little bias noise to pass CTS
uncal->x_bias = randomError(-0.003f, 0.003f);
uncal->y_bias = randomError(-0.003f, 0.003f);
uncal->z_bias = randomError(-0.003f, 0.003f);
// ...
}
}
源码路径:device/generic/goldfish/hals/sensors/multihal_sensors_qemu.cpp
60.3.8 虚拟 GPS
GPS 仿真基于 GNSS HAL 实现(60.2.3.4 节)。模拟器支持如下能力:
- 固定 GPS 坐标(通过扩展控制面板配置)
- GPS 路线回放(GPX/KML 文件)
- NMEA 语句注入
GPS 服务在 QEMU 主机注册为gps qemud 服务。客户机侧GnssHwListener类解析收到的 NMEA 数据,并分发至 Android 位置框架。
60.3.9 虚拟相机
相机子系统支持多种虚拟相机后端:
- 主机摄像头透传 :模拟器采集主机摄像头帧,通过 QEMU
camera服务发送给客户机。 - 虚拟场景:3D 渲染环境,跟随虚拟设备姿态传感器输出画面。
- 伪旋转相机 :合成测试图案,对应源码类
FakeRotatingCamera,位于device/generic/goldfish/hals/camera/。
相机数据传输复用 qemud 协议,采用查询‑应答交互模式:
客户机 → 主机: "list" (列举可用相机)
主机 → 客户机: "ok:<camera_list>"
客户机 → 主机: "connect:<id>" (连接指定相机)
主机 → 客户机: "ok"
客户机 → 主机: "start:<params>" (开启图像采集)
主机 → 客户机: "ok"
主机 → 客户机: <frame_data> (原始帧数据)
cpp
Guest -> Host: "list" (on the "camera" factory channel)
Host -> Guest: "ok:<camera_list>"
Guest opens qemud channel "camera:name=<camera>"
Guest -> Host: "connect" (connect to the camera)
Host -> Guest: "ok"
Guest -> Host: "start" (start capture)
Host -> Guest: "ok"
Host -> Guest: <frame_data> (raw frame data)
Guest -> Host: "stop", then "disconnect" when done
60.3.10 虚拟电话
电话子系统内置完整调制解调器模拟器,通过 AT 命令与无线 HAL 通信。模拟器支持:
- 语音通话(仿真通话状态机)
- 短信收发
- 数据连接
- SIM 卡仿真(ICC 配置文件存放在
data/misc/modem_simulator/) - 多种无线接入技术(5G NR、LTE、GSM 等)
SIM 卡配置文件预编译拷贝:
# Source: device/generic/goldfish/product/generic.mk
PRODUCT_COPY_FILES += \
device/generic/goldfish/hals/radio/data/apns-conf.xml:$(TARGET_COPY_OUT_VENDOR)/etc/apns/apns-conf.xml \
device/generic/goldfish/hals/radio/data/iccprofile_for_sim0.xml:data/misc/modem_simulator/iccprofile_for_sim0.xml \
device/generic/goldfish/hals/radio/data/numeric_operator.xml:data/misc/modem_simulator/etc/modem_simulator/files/numeric_operator.xml \
60.3.11 GPU 仿真
GPU 仿真属于模拟器内部架构最复杂模块之一。系统支持三类渲染主体:主机侧渲染、客户机侧渲染、goldfish‑pipe 通道。

客户机镜像内置相关库:
# Source: device/generic/goldfish/product/generic.mk
PRODUCT_PACKAGES += \
libGLESv1_CM_emulation \
lib_renderControl_enc \
libEGL_emulation \
libGLESv2_enc \
libvulkan_enc \
libGLESv2_emulation \
libGLESv1_enc \
libEGL_angle \
libGLESv1_CM_angle \
libGLESv2_angle
客户机侧 EGL/GLES 库会将 OpenGL ES 指令序列化为二进制数据流,经由 goldfish‑pipe 发送至主机。模拟器主机解码指令,调用本机 GPU 驱动重放绘图命令。
当主机 GPU 不可用时(无头 CI 服务器、SSH 远程会话),SwiftShader 提供完全运行于 CPU 的 Vulkan 软件实现。
ANGLE(Almost Native Graphics Layer Engine)在 Vulkan 接口之上封装 OpenGL ES。适合主机支持 Vulkan,但缺少原生 OpenGL 驱动的场景,新版 macOS 就属于这类平台。
图形渲染模式通过启动属性配置:
# Source: device/generic/goldfish/init/init.ranchu.rc
setprop ro.hardware.egl ${ro.boot.hardwareegl:-emulation}
setprop ro.hardware.vulkan ${ro.boot.hardware.vulkan}
setprop ro.opengles.version ${ro.boot.opengles.version}
gralloc HAL 借助 render control 编码器创建主机端 GPU 资源(颜色缓冲区,见 60.2.3.8),实现高效零拷贝渲染:客户机完成帧合成后,直接由模拟器窗口进行显示输出。
60.4 模拟器网络
60.4.1 网络架构
模拟器实现一套虚拟网络,给客户机提供互联网访问,同时将虚拟机与主机物理网络隔离。默认使用 QEMU 用户态网络协议栈 SLIRP;高级场景可选用 TAP 网络模式。

60.4.2 默认 IP 地址分配
每个模拟器实例分配独立 IP 网段:
| 组件 | 地址 |
|---|---|
| 虚拟路由器 / 网关 | 10.0.2.1 |
| 主机回环别名 | 10.0.2.2 |
| DNS 服务器 | 10.0.2.3 |
| 客户机 eth0 | 10.0.2.15(DHCP 分配) |
60.4.3 VirtIO WiFi
新版模拟器使用 VirtIO WiFi 替代传统 eth0 网卡。网络脚本device/generic/goldfish/init/init.net.ranchu.sh完成相关处理:
# Source: device/generic/goldfish/init/init.net.ranchu.sh
wifi_virtio=`getprop ro.boot.qemu.virtiowifi`
case "$wifi_virtio" in
1) wifi_mac_prefix=`getprop vendor.net.wifi_mac_prefix`
if [ -n "$wifi_mac_prefix" ]; then
/vendor/bin/mac80211_create_radios 1 $wifi_mac_prefix || exit 1
fi
;;
esac
开启 VirtIO WiFi 后,mac80211_hwsim内核模块创建仿真 WiFi 射频。wpa_supplicant服务管理该虚拟网卡:
# Source: device/generic/goldfish/init/init.ranchu.rc
service wpa_supplicant /vendor/bin/hw/wpa_supplicant \
-Dnl80211 -iwlan0 \
-c/vendor/etc/wifi/wpa_supplicant.conf \
-g@android:wpa_wlan0
interface aidl android.hardware.wifi.supplicant.ISupplicant/default
socket wpa_wlan0 dgram 660 wifi wifi
group system wifi inet
VirtIO WiFi 条件触发配置:
# Source: device/generic/goldfish/init/init.ranchu.rc
on post-fs-data && property:ro.boot.qemu.virtiowifi=1
start ranchu-net
60.4.4 端口转发与 ADB 连接
模拟器支持主机与客户机之间 TCP、UDP 端口转发。ADB 依靠端口转发完成通信:
- 控制台端口:实例 1 使用 5554,实例 2 使用 5556,以此类推
- ADB 端口:实例 1 使用 5555,实例 2 使用 5557,以此类推
端口转发在模拟器控制台配置:
# 将主机8080端口转发到客户机80端口
redir add tcp:8080:80
# 将主机5000端口转发到客户机5000端口
redir add tcp:5000:5000
客户机内部 ADB 守护进程监听固定端口;模拟器自动配置转发规则,adb devices即可识别模拟器设备。
60.4.5 多模拟器实例互通网络
网络脚本提供第二块网卡eth1,用于模拟器之间通信:
# Source: device/generic/goldfish/init/init.net.ranchu.sh
# set up the second interface (for inter‑emulator connections)
my_ip=`getprop vendor.net.shared_net_ip`
case "$my_ip" in
"")
;;
*) ifconfig eth1 "$my_ip" netmask 255.255.255.0 up
;;
esac
多模拟器需要互相通信(多设备场景测试)时,可以配置共享网络,每个实例在 eth1 上分配独立 IP。
60.4.6 蓝牙网络
蓝牙基于 VirtIO 控制台设备仿真。init 脚本创建蓝牙设备符号链接:
# Source: device/generic/goldfish/init/init.ranchu.rc
on property:vendor.qemu.vport.bluetooth=*
symlink ${vendor.qemu.vport.bluetooth} /dev/bluetooth0
service bt_vhci_forwarder \
/vendor/bin/bt_vhci_forwarder \
-virtio_console_dev=/dev/bluetooth0
class main
user bluetooth
group root bluetooth
bt_vhci_forwarder服务打通 VirtIO 控制台设备与蓝牙 VHCI(虚拟主机控制器接口)驱动,客户机就可以使用模拟器蓝牙协议栈。
60.5 Ranchu 与 Goldfish 内核
60.5.1 历史背景
模拟器经历两代主要内核:
- Goldfish 内核(遗留版本):经过定制修改的 Linux 内核,包含专门适配早期模拟器虚拟硬件的驱动(goldfish_timer、goldfish_fb、goldfish_audio、goldfish_battery 等)。
- Ranchu 内核(现代版本):标准 GKI 通用内核镜像,使用标准 VirtIO 设备,不再使用定制 Goldfish 硬件。Ranchu 本身是金鱼品种,命名体现演进继承关系。
60.5.2 VirtIO 设备迁移
从定制 Goldfish 硬件迁移到标准 VirtIO 设备是一次重大架构升级。

goldfish‑pipe予以保留:它承担 VirtIO 无法覆盖的能力,提供高带宽低延迟通道,用于客户机 HAL 与主机服务之间传输序列化 GPU 指令以及其他大块数据。
60.5.3 内核模块配置
现代 Ranchu 内核采用可加载 VirtIO 内核模块。Cuttlefish 板级配置使用同一套内核,下面列出 ramdisk 阶段所需模块:
# Source: device/google/cuttlefish/shared/BoardConfig.mk
RAMDISK_KERNEL_MODULES ?= \
failover.ko \
nd_virtio.ko \
net_failover.ko \
virtio_dma_buf.ko \
virtio‑gpu.ko \
virtio_input.ko \
virtio_net.ko \
virtio‑rng.ko \
以上模块必须在第一阶段 init 加载,保证系统可以正常启动。后续加载模块列表:
virtio_blk.ko:块设备仿真virtio_console.ko:串口控制台、虚拟端口virtio_pci.ko:VirtIO 的 PCI 传输后端vmw_vsock_virtio_transport.ko:客户机‑主机 vsock 通信mac80211_hwsim.ko:WiFi 仿真cfg80211.ko、mac80211.ko:无线网络协议栈
60.5.4 内核版本选择
Android17 中,Cuttlefish 内核版本不再写死固定值。device/google/cuttlefish/shared/BoardConfig.mk定义默认版本,各产品可以单独选择;部分目标从 release‑config 变量读取内核版本。
# Source: device/google/cuttlefish/shared/BoardConfig.mk
DEFAULT_TARGET_KERNEL_USE := 6.12
ifneq (,$(findstring cf_gwear_arm,$(PRODUCT_NAME)))
TARGET_KERNEL_USE ?= 6.6
else ifeq (true,$(CLOCKWORK_EMULATOR_PRODUCT))
TARGET_KERNEL_USE ?= 6.1
else ifneq (,$(findstring x86_tv,$(PRODUCT_NAME)))
TARGET_KERNEL_USE ?= 6.1
else ifneq (,$(filter cf_x86_64_desktop,$(PRODUCT_NAME)))
TARGET_KERNEL_USE ?= $(RELEASE_KERNEL_CUTTLEFISH_X86_64_VERSION)
TARGET_KERNEL_DIR ?= $(RELEASE_KERNEL_CUTTLEFISH_X86_64_DIR)
else ifneq (,$(filter cf_arm64_desktop,$(PRODUCT_NAME)))
TARGET_KERNEL_USE ?= $(RELEASE_KERNEL_CUTTLEFISH_ARM64_VERSION)
TARGET_KERNEL_DIR ?= $(RELEASE_KERNEL_CUTTLEFISH_ARM64_DIR)
else
TARGET_KERNEL_USE ?= $(DEFAULT_TARGET_KERNEL_USE)
endif
通用手机目标默认内核版本 6.12;部分形态锁定长期支持内核:Wear OS 使用 6.6,clockwork 模拟器、x86 TV 使用 6.1。桌面目标比较特殊,内核版本、目录取自RELEASE_KERNEL_CUTTLEFISH_*变量,内核与模块来自独立桌面专用代码树,不再使用公共预编译包。
# Source: device/google/cuttlefish/shared/BoardConfig.mk
ifneq (,$(filter cf_x86_64_desktop cf_arm64_desktop,$(PRODUCT_NAME)))
SYSTEM_DLKM_SRC ?= device/google/desktop/cuttlefish‑$(TARGET_KERNEL_ARCH)‑kernels/$(TARGET_KERNEL_USE)/$(TARGET_KERNEL_DIR)/system_dlkm
KERNEL_MODULES_PATH ?= device/google/desktop/cuttlefish‑$(TARGET_KERNEL_ARCH)‑kernels/$(TARGET_KERNEL_USE)/$(TARGET_KERNEL_DIR)/vendor_dlkm
else
SYSTEM_DLKM_SRC ?= kernel/prebuilts/$(TARGET_KERNEL_USE)/$(TARGET_KERNEL_ARCH)
KERNEL_MODULES_PATH ?= \
kernel/prebuilts/common‑modules/virtual‑device/$(TARGET_KERNEL_USE)/$(subst _,-,$(TARGET_KERNEL_ARCH))
endif
TARGET_KERNEL_PATH ?= $(SYSTEM_DLKM_SRC)/kernel‑$(TARGET_KERNEL_USE)
除桌面目标之外,预编译内核存放在kernel/prebuilts/;common‑modules/virtual‑device/目录存放专门为虚拟设备编译的内核模块。
60.5.5 ZRAM 与内存配置
Ranchu 内核开启 zram 内存压缩:
# Source: device/generic/goldfish/init/init.ranchu.rc
on early‑init
exec u:r:modprobe:s0 -- /system/bin/modprobe -a -d \
/system/lib/modules zram.ko
on init
write /sys/block/zram0/comp_algorithm lz4
write /proc/sys/vm/page‑cluster 0
on sys‑boot‑completed‑set && property:persist.sys.zram_enabled=1
swapon_all /vendor/etc/fstab.${ro.hardware}
zram 压缩选用 LZ4,压缩解压速度快。page‑cluster=0设置内核每次读取一个 swap 页,zram 没有磁盘寻道开销,该参数为最优配置。
60.6 Cuttlefish:面向云环境的替代虚拟设备
60.6.1 什么是 Cuttlefish
Cuttlefish 是一套可配置 Android 虚拟设备,运行于云环境,不需要物理显示器、音频硬件或者任何硬件专属基础设施。Goldfish/Ranchu 面向 Android Studio 模拟器(GUI 桌面程序);Cuttlefish 面向服务器侧场景:CI/CD 持续集成、自动化测试、云游戏、远程机器开发。
源码路径:device/google/cuttlefish/
60.6.2 架构对比

| 特性 | Goldfish/Ranchu | Cuttlefish |
|---|---|---|
| 主要使用场景 | 桌面开发 | 云环境 / CI 自动化 |
| 显示输出 | 桌面窗口 | WebRTC 或者 VNC |
| 音频 | 主机音频输出 | 虚拟音频 |
| GPU | 主机 GPU 透传 | virtio‑gpu / SwiftShader |
| 网络 | 用户态 SLIRP | TAP / 网桥模式 |
| 多实例 | 多进程运行 | launch_cvd --num_instances |
| OTA 更新 | 不支持 | 支持 A/B 更新 |
| 快照 | QEMU 快照 | 非主打能力 |
| 设备形态 | 手机、平板、折叠、Wear、TV | 手机、折叠、平板 PC、TV、车载、Wear、桌面 |
| 支持架构 | x86_64、ARM64、RISC‑V | x86_64、ARM64、RISC‑V |
60.6.3 Cuttlefish 设备编译目标
device/google/cuttlefish/AndroidProducts.mk枚举编译目标。产品命名格式:aosp_cf_<arch>_<formfactor>,每个产品指向对应vsoc_*设备目录下精简aosp_cf.mk。vsoc含义:Virtual System on Chip 虚拟片上系统。
Android17 源码中设备目录:
| 目录 | 架构 / 变体 |
|---|---|
| vsoc_x86_64/ | x86_64(兼容 32 位) |
| vsoc_x86_64_only/ | 纯 x86_64,仅 64 位 |
| vsoc_x86_64_pgagnostic/ | x86_64,页大小无关(4KB/16KB) |
| vsoc_x86_64_minidroid/ | 极简 x86_64 版本 |
| vsoc_x86_64_host/ | x86_64 主机侧编译 |
| vsoc_arm64/ | ARM64(兼容 32 位) |
| vsoc_arm64_only/ | 纯 ARM64 |
| vsoc_arm64_pgagnostic/ | ARM64,页大小无关 |
| vsoc_arm64_minidroid/ | 极简 ARM64 |
| vsoc_arm/ vsoc_arm_minidroid/ | 32 位 ARM |
| vsoc_riscv64/ | RISC‑V 64 位 |
| vsoc_riscv64_minidroid/ | 极简 RISC‑V |
设备形态在以上目录基础上扩展。Android17 已经远超手机平板,产品列表覆盖手机、折叠、平板 PC、TV、Wear、车载、新增桌面目标。
| 产品名 | 设备目录 | 说明 |
|---|---|---|
| aosp_cf_x86_64_phone | vsoc_x86_64/phone/ | CI 标准参考目标 |
| aosp_cf_x86_64_foldable | vsoc_x86_64_only/phone/ | 叠加 aosp_cf_foldable.mk 配置 |
| aosp_cf_x86_64_pc | vsoc_x86_64_only/pc/ | 大屏平板布局 |
| aosp_cf_x86_64_tv | vsoc_x86_64_only/tv/ | Android TV |
| aosp_cf_x86_64_wear | vsoc_x86_64_only/wear/ | Wear OS |
| aosp_cf_x86_64_auto (+ auto_md, auto_mdnd, auto_dd, auto_portrait...) | vsoc_x86_64_only/auto*/ | 车载,多显示变体 |
| aosp_cf_x86_64_desktop | vsoc_x86_64_only/desktop/ | Android17 新增桌面目标 |
| aosp_cf_arm64_phone / aosp_cf_arm64_auto | vsoc_arm64* | ARM 平台对应版本 |
| aosp_cf_riscv64_phone / _wear / _slim | vsoc_riscv64* | RISC‑V 平台 |
Android17 桌面目标
aosp_cf_x86_64_desktop是 Android17 新增重要目标。产品配置文件device/google/cuttlefish/vsoc_x86_64_only/desktop/aosp_cf.mk继承桌面专属厂商配置device/google/cuttlefish/shared/desktop/common_x86.mk与aosp_device_vendor.mk;设置PRODUCT_MODEL := Cuttlefish AOSP x86_64 Desktop。两点区别于手持设备:
# Source: device/google/cuttlefish/vsoc_x86_64_only/desktop/aosp_cf.mk
PRODUCT_NAME := aosp_cf_x86_64_desktop
PRODUCT_DEVICE := vsoc_x86_64_only
# Ika uses ndk‑translation only.
AL_BINARY_TRANSLATION_MODE := ndk_translation_only
# ARC/Auto/Desktop - don't use compressed apks.
UNCOMPRESS_CHROME_WEBVIEW = true
桌面目标内核取自独立路径,不再使用公共kernel/prebuilts/,桌面 Android 维护独立内核分支。
60.6.4 主机侧工具集
Cuttlefish 大量主机工具存放于device/google/cuttlefish/host/commands/,编译产出cvd‑host_package.tar.gz,与客户机镜像配合运行。
| 工具 | 用途 |
|---|---|
| launch_cvd | 启动虚拟设备,编译输出cvd_internal_start,建立符号链接 |
| stop_cvd | 停止虚拟设备 |
| run_cvd | 核心虚拟机运行时,管理 crosvm 与后台守护进程 |
| assemble_cvd | 组装磁盘镜像,生成 VMM 虚拟机监控器配置 |
| status_cvd / restart_cvd | 查询、重启运行实例 |
| cvd_env | gRPC 环境管理 |
| process_sandboxer | 使用 seccomp 沙箱隔离主机守护进程(Android17 新增) |
| console_forwarder | 串口控制台转发 |
| kernel_log_monitor | 内核日志监控 |
| log_tee | 日志复制转发 |
| logcat_receiver | 接收来自客户机 logcat 日志 |
| modem_simulator | 电话调制解调器仿真 |
| gnss_grpc_proxy | gRPC 方式 GNSS 位置数据代理 |
| display | 显示管理 |
| screen_recording_server | 录屏服务 |
| record_cvd | 录屏工具 |
| secure_env | 安全环境(KeyMint、Gatekeeper、TPM) |
| sensors_simulator | 传感器仿真 |
| vhost_user_input | vhost‑user 输入设备后端 |
| casimir_control_server | NFC 控制 |
| jcardsim | Java Card 仿真,用于安全元件 /eSIM |
| health | 设备健康监控 |
| host_bugreport | 抓取 bugreport |
| metrics | 指标采集统计 |
| snapshot_util_cvd | 快照管理 |
| powerbtn_cvd | 模拟电源按键 |
| powerwash_cvd | 模拟恢复出厂设置 |
| cvd_send_sms | 注入短信 |
| cvd_update_location / cvd_import_locations | 注入位置信息 |
注意:主机工具发生重大迁移:编排前端 cvd、Debian 软件包不再维护在 AOSP
device/google/cuttlefish目录,迁移至独立仓库github.com/google/android‑cuttlefish。device/google/cuttlefish/README.md给出指引。Android17 不再包含旧版 acloud 启动器;本地启动使用 host 包内launch_cvd或者外部仓库 cvd 命令。
60.6.5 板级配置差异
Cuttlefish 板级配置device/google/cuttlefish/shared/BoardConfig.mk相比 Goldfish 有多处关键改动:
支持 A/B OTA 升级
# Source: device/google/cuttlefish/shared/BoardConfig.mk
AB_OTA_UPDATER := true
启用更多动态分区
# Source: device/google/cuttlefish/shared/BoardConfig.mk
BOARD_SUPER_PARTITION_SIZE := 8589934592 # 8GB
BOARD_SUPER_PARTITION_GROUPS := \
google_system_dynamic_partitions \
google_vendor_dynamic_partitions
BOARD_GOOGLE_SYSTEM_DYNAMIC_PARTITIONS_PARTITION_LIST := \
product system system_ext system_dlkm
BOARD_GOOGLE_VENDOR_DYNAMIC_PARTITIONS_PARTITION_LIST := \
odm vendor vendor_dlkm odm_dlkm
独立 ODM、vendor_dlkm 分区
# Source: device/google/cuttlefish/shared/BoardConfig.mk
BOARD_USES_ODMIMAGE := true
BOARD_USES_VENDOR_DLKMIMAGE := true
BOARD_USES_ODM_DLKMIMAGE := true
BOARD_USES_SYSTEM_DLKMIMAGE := true
内核命令行自定义
# Source: device/google/cuttlefish/shared/BoardConfig.mk
BOARD_KERNEL_CMDLINE += printk.devkmsg=on
BOARD_KERNEL_CMDLINE += audit=1
BOARD_KERNEL_CMDLINE += panic=-1
BOARD_KERNEL_CMDLINE += 8250.nr_uarts=1
BOARD_KERNEL_CMDLINE += binder.impl=rust
BOARD_KERNEL_CMDLINE += cma=0
BOARD_KERNEL_CMDLINE += firmware_class.path=/vendor/etc/
BOARD_KERNEL_CMDLINE += loop.max_part=7
BOARD_KERNEL_CMDLINE += init=/init
BOARD_BOOTCONFIG += androidboot.hardware=cutf_cvm
Cuttlefish 特有内核参数说明:
binder.impl=rust:使用 Rust 实现 binder 驱动cma=0:关闭连续内存分配器,虚拟机环境不需要panic=-1:内核 panic 后立刻重启
60.6.6 Cuttlefish 快速上手
来自官方device/google/cuttlefish/README.md:
# 1. 确认CPU支持KVM虚拟化
grep -c -w "vmx\|svm" /proc/cpuinfo
# 2. 安装主机依赖包
sudo apt install -y git devscripts config‑package‑dev \
debhelper‑compat golang curl
git clone https://github.com/google/android‑cuttlefish
cd android‑cuttlefish
./tools/buildutils/build_packages.sh
sudo dpkg -i ./cuttlefish‑base_*_*64.deb || sudo apt‑get install -f
sudo dpkg -i ./cuttlefish‑user_*_*64.deb || sudo apt‑get install -f
sudo usermod -aG kvm,cvdnetwork,render $USER
sudo reboot
# 3. 从ci.android.com下载镜像
# 4. 启动实例
mkdir cf && cd cf
tar xvf /path/to/cvd‑host_package.tar.gz
unzip /path/to/aosp_cf_x86_64_phone‑img‑xxxxxx.zip
HOME=$PWD ./bin/launch_cvd
# 5. 浏览器WebRTC访问 https://localhost:8443
# 6. ADB调试
./bin/adb -e shell
# 7. 停止虚拟机
HOME=$PWD ./bin/stop_cvd
60.6.7 Cuttlefish VirtIO 模块依赖
Cuttlefish 板级配置完整展示虚拟设备所需 VirtIO 软件栈。模块分为 ramdisk(第一阶段 init)、vendor 分区(第二阶段 init)。
ramdisk 模块(启动必须):
# Source: device/google/cuttlefish/shared/BoardConfig.mk
RAMDISK_KERNEL_MODULES ?= \
failover.ko \
nd_virtio.ko \
net_failover.ko \
virtio_dma_buf.ko \
virtio‑gpu.ko \
virtio_input.ko \
virtio_net.ko \
virtio‑rng.ko \
必须第一阶段 init 加载的原因:
virtio‑gpu.ko:显示输出依赖virtio_net.ko:初始化阶段网络访问virtio_input.ko:输入事件nd_virtio.ko:VirtIO NUMA 距离支持virtio‑rng.ko:随机数生成,密码组件初始化依赖
传输层模块:
# Source: device/google/cuttlefish/shared/BoardConfig.mk
BOARD_VENDOR_RAMDISK_KERNEL_MODULES += \
$(SYSTEM_VIRTIO_PREBUILTS_PATH)/virtio_blk.ko \
$(SYSTEM_VIRTIO_PREBUILTS_PATH)/virtio_console.ko \
$(SYSTEM_VIRTIO_PREBUILTS_PATH)/virtio_pci.ko \
$(SYSTEM_VIRTIO_PREBUILTS_PATH)/vmw_vsock_virtio_transport.ko
VirtIO PCI 传输模块是 x86 平台 QEMU 环境所有 VirtIO 设备基础。ARM 平台替换为virtio_mmio.ko。
WiFi 相关模块(mac80211 协议栈)
# Source: device/google/cuttlefish/shared/BoardConfig.mk
BOARD_VENDOR_RAMDISK_KERNEL_MODULES += \
$(wildcard $(SYSTEM_DLKM_SRC)/cfg80211.ko) \
$(wildcard $(SYSTEM_DLKM_SRC)/libarc4.ko) \
$(wildcard $(SYSTEM_DLKM_SRC)/mac80211.ko) \
$(wildcard $(SYSTEM_DLKM_SRC)/rfkill.ko) \
$(wildcard $(KERNEL_MODULES_PATH)/mac80211_hwsim.ko)
mac80211_hwsim软件模拟 WiFi 射频。第一阶段 init 加载该模块时参数mac80211_hwsim.radios=0,不会立刻创建射频;射频实例后续由mac80211_create_radios工具生成。
60.6.8 Cuttlefish 对比 Goldfish 架构差异

核心差异:Goldfish 整体是单一 QEMU 进程,虚拟机、显示、设备仿真全部在内部完成。Cuttlefish 采用微服务架构,虚拟机管理、显示、调制解调器、GNSS、日志等功能各自独立进程。模块化强,调试友好,但部署复杂度更高。
60.6.9 选型参考
| 场景 | 推荐方案 |
|---|---|
| Android Studio 开发 | Goldfish/Ranchu 模拟器 |
| 需要 UI 本地调试 | Goldfish/Ranchu 模拟器 |
| CI/CD 自动化测试 | Cuttlefish |
| 云端开发 | Cuttlefish |
| 性能测试 | Cuttlefish(行为更确定) |
| CTS/VTS 兼容性测试 | Cuttlefish(官方主要参考) |
| 多实例并发测试 | Cuttlefish |
| 大量快照工作流 | Goldfish/Ranchu 模拟器 |
| 折叠设备 UI 交互测试 | 两者均可,Goldfish UI 更完善 |
| 车载 / TV / Wear OS | Cuttlefish,设备形态覆盖更全 |
Cuttlefish 逐步成为 AOSP 首要虚拟参考设备。谷歌内部持续使用它做自动化测试。平台开发人员如果不需要 GUI 交互界面,优先选用 Cuttlefish。
60.6.10 Crosvm 设备架构
Cuttlefish 默认 VMM 虚拟机监控器为crosvm ,使用 Rust 语言开发,最初为 Chrome OS 开发。虚拟机管理代码device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp(共 1076 行)组装 crosvm 命令行,填入全部 VirtIO 设备参数。
VirtIO 设备映射
客户机所有 IO 设备均基于 PCI 总线 VirtIO:

PCI 槽位分配
cpp
// Source: device/google/cuttlefish/host/libs/vm_manager/vm_manager.h:79‑91
static constexpr int kMaxDisks = 3;
static const int kDefaultNumBootDevices = 2;
static constexpr const int kNetPciDeviceNum = 1; // Network on PCI slot 1
static constexpr const int kGpuPciSlotNum = 2; // GPU on PCI slot 2
网卡占用 PCI 槽位 1 下面子地址:
| 接口 | PCI 地址 | TAP 设备 | 用途 |
|---|---|---|---|
| Mobile | 00:01.1 | cvd‑mtap‑NN | 蜂窝数据仿真 |
| Ethernet | 00:01.2 | cvd‑etap‑NN | 有线网络 |
| WiFi | 00:01.3 | cvd‑wtap‑NN | 无线网络(可选) |
60.6.11 Vhost‑User 设备模型
Cuttlefish 使用 vhost‑user 协议,设备后端运行在独立主机进程,不在 crosvm 进程内部。隔离性更好,可以单独重启设备后端;后端可以使用不同语言实现(输入设备 Rust、音频服务 C++)。

cpp
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_builder.h:71‑72
void AddVhostUser(const std::string& type, const std::string& socket_path,
int max_queue_size = 256);
支持 vhost‑user 设备:
| 类型 | 后端进程 | 套接字路径 | 用途 |
|---|---|---|---|
| gpu | vhost‑user‑gpu | gpu_socket_path() | 图形渲染 |
| input | vhost_user_input(Rust) | keyboard_socket_path () 等 | 输入事件 |
| vsock | vhost‑device‑vsock | vhost_user_vsock_path() | 主机‑客户机通信 |
| block | vhost‑user‑block | disk socket | 存储磁盘(仅 disk2) |
| mac80211‑hwsim | WiFi simulator | hwsim socket | WiFi 射频仿真 |
virtqueue 默认队列大小 256 项,数值必须是 2 的整数次幂。
60.6.12 HVC 端口映射
Cuttlefish 使用 Hypervisor Virtual Console (HVC) 端口打通客户机 HAL 与主机守护进程。客户机内设备节点为/dev/hvcN。Android17 一共有 20 个端口/dev/hvc0 ~ /dev/hvc19。端口编号在crosvm_manager.cpp固定分配;即使功能关闭也会配置空 sink 设备,保证 PCI 设备 ID 稳定不变。
| 客户机设备 | 主机端点 | 用途 |
|---|---|---|
| /dev/hvc0 | kernel_log_pipe | 内核控制台输出 |
| /dev/hvc1 | console_pipe | Android 串口控制台 |
| /dev/hvc2 | logcat_pipe | 系统日志转发 logcat |
| /dev/hvc3 | secure_env daemon | C++ KeyMaster HAL |
| /dev/hvc4 | secure_env daemon | 锁屏 Gatekeeper 校验 |
| /dev/hvc5 | root_canal simulator | 蓝牙 HCI 通道 |
| /dev/hvc6 | gnss_grpc_proxy | GPS/GNSS 位置数据 |
| /dev/hvc7 | Location daemon | 注入位置修正数据 |
| /dev/hvc8 | Trusty integration | 安全确认弹窗 |
| /dev/hvc9 | UWB daemon | 超宽带测距 |
| /dev/hvc10 | OEMLock daemon | OEM bootloader 解锁 |
| /dev/hvc11 | secure_env daemon | Rust KeyMint HAL |
| /dev/hvc12 | NFC daemon | NFC 仿真 |
| /dev/hvc13 | sink | 预留未使用 |
| /dev/hvc14 | MCU daemon | 微控制器控制 |
| /dev/hvc15 | MCU daemon | 微控制器串口 |
| /dev/hvc16 | TPM daemon | Ti50 TPM FIFO 命令通道 |
| /dev/hvc17 | Java Card simulator | eSIM / 安全元件 |
| /dev/hvc18 | sensors_simulator | 传感器控制命令通道 |
| /dev/hvc19 | sensors_simulator | 传感器采样数据流通道 |
对比旧版本重要变更:原先单一传感器端口拆分,控制通道/dev/hvc18,数据通道/dev/hvc19;/dev/hvc13空置保留。
每个 HVC 端口主机侧后端为管道或者 Unix 套接字。builder 提供 4 个辅助接口,全部接收 FIFO / 套接字路径字符串:
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_builder.h:42‑45
void AddHvcSink(); // null device (unused port)
void AddHvcReadOnly(const std::string& output, bool console = false); // one‑way (kernel logs)
void AddHvcReadWrite(const std::string& output, const std::string& input); // bidirectional
void AddHvcSocket(const std::string& socket); // Unix socket
60.6.13 GPU 管线与显示模式
Cuttlefish 支持多种 GPU 渲染模式,通过--gpu_mode参数配置。Android17 assemble_cvd 全部可选值集合:{auto, custom, drm_virgl, gfxstream, gfxstream_guest_angle, gfxstream_guest_angle_host_swiftshader, gfxstream_guest_angle_host_lavapipe, guest_swiftshader}。
| 模式 | 说明 |
|---|---|
| auto | 自动检测主机 GPU,选择最优模式 |
| gfxstream | gfxstream 协议实现主机 GPU 透传 |
| gfxstream_guest_angle | 客户机侧 ANGLE,gfxstream 传输调用主机 GPU |
| gfxstream_guest_angle_host_swiftshader | 客户机 ANGLE,主机 SwiftShader 软件渲染 |
| gfxstream_guest_angle_host_lavapipe | 客户机 ANGLE,主机 Mesa lavapipe |
| drm_virgl | Virgl3D;OpenGL 指令经由 virtio‑gpu DRM 转发 |
| guest_swiftshader | 完全客户机内部 SwiftShader Vulkan 软件渲染 |
| custom | 调用方提供完整 GPU 设备配置 |
Virtio‑GPU 工作线程运行在进程内还是独立vhost‑user‑gpu后端是另一个独立开关,由--gpu_vhost_user_mode={auto, on, off}控制。
显示架构

Wayland 合成器接收渲染帧,两个输出流向:
- WebRTC:浏览器流媒体,云场景使用
- 本地显示:直接输出主机屏幕
cpp
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp:474‑495
// Display configuration with width, height, DPI, and refresh rate
// Frames sent via Wayland socket to compositor
60.6.14 网络架构
TAP 设备与网桥配置
Cuttlefish 在主机创建 TAP 网络设备,把客户机 virtio‑网卡桥接到主机网络。

cpp
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp:707‑727
// Mobile TAP: PCI 00:01:01
// Ethernet TAP: PCI 00:01:02
// WiFi TAP: auto‑assigned PCI (optional)
WiFi 仿真
Cuttlefish 支持两种 WiFi 仿真模式:
-
TAP 网桥:简单网络桥接,不实现 WiFi 协议行为
-
mac80211_hwsim:内核模块仿真 802.11 射频;虚拟机内部完整支持 WiFi 扫描、关联、WPA 鉴权。
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp
// WiFi via mac80211_hwsim when config.virtio_mac80211_hwsim() is true
vhost‑net 加速
开启后网络包处理从 crosvm 用户态下移到主机内核,大幅提升网络吞吐。
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp:596‑598
if (instance.vhost_net()) {
crosvm_cmd.Cmd().AddParameter("--vhost‑net");
}
60.6.15 客户机 HAL
客户机 HAL 层位于device/google/cuttlefish/guest/hals/,对接 Android 上层 HAL 接口,底层通过 virtio 设备、vsock、HVC 串口和主机守护进程通信。Android17 目录结构:
device/google/cuttlefish/guest/hals/
├── audio/ # virtio‑snd / audio server
├── bluetooth/ # HVC -> root_canal simulator
├── camera/ # vsock -> host camera streaming
├── confirmationui/ # HVC -> Trusty integration
├── gatekeeper/ # HVC -> secure_env daemon
├── gralloc/ # Graphics buffer allocation
├── health/ # Battery/charge monitoring
├── hostapd/ # WiFi access‑point daemon
├── identity/ # Identity credential HAL
├── ir/ # Consumer IR
├── keymint/ # HVC -> secure_env (KeyMint)
├── light/ # vsock -> light control (Rust)
├── nfc/ # HVC -> NFC daemon
├── npu/ # NPU scheduling HAL (Rust, new in 17)
├── oemlock/ # HVC -> OEM unlock
├── secure_element/ # eSIM / secure chip access
├── vehicle/ # vsock -> automotive VHAL
├── virtio_media/ # virtio‑media V4L2 camera/codec provider
└── vulkan/ # Graphics support
移除模块:不再有独立ril/目录,电话功能走 HVC 端口对接主机modem_simulator;不再有sensors/目录,传感器桥接通过主机sensors_simulator使用/dev/hvc18、/dev/hvc19。Android17 新增 NPU 调度 HAL、virtio_media 组件。
客户机 HAL 一般读写/dev/hvcN virtio‑console,或者建立 vsock 连接访问主机对应服务。向上给 Framework 提供的 HAL 接口与真实硬件完全一致;上层无感知虚拟化。
示例:Android17 Rust 实现 NPU 调度 HAL NPU HAL 是 Android17 新增组件,Rust 语言实现android.hardware.npu调度接口,注册服务IScheduling/default,Cuttlefish 对外暴露 NPU 能力,用于 NPU 框架路径测试。
// Source: device/google/cuttlefish/guest/hals/npu/main.rs
//! This implements the NPU Scheduling Service for Cuttlefish.
use android_hardware_npu::aidl::android::hardware::npu::IScheduling::{
BnScheduling, IScheduling};
const LOG_TAG: &str = "android.hardware.npu";
xml 服务配置:
<!-- Source: device/google/cuttlefish/guest/hals/npu/android.hardware.npu‑service.xml -->
<fqname>IScheduling/default</fqname>
示例:Vsock 实现 Camera HAL Camera HAL 通过 vsock 接收主机 MJPEG/H264 视频帧,向 CameraService 输出标准 Camera2 HAL 接口。
// Source: device/google/cuttlefish/guest/hals/camera/vsock_camera_server.cpp
// Receives MJPEG/H264 frames from host over vsock
// Exposes standard Camera2 HAL interface to CameraService
示例:Rust 实现 Light HAL 注册ILightsbinder 服务,实现通知 LED、背光等指示灯控制接口。
// Source: device/google/cuttlefish/guest/hals/light/main.rs
//! This implements the Lights Service for Cuttlefish.
use android_hardware_light::aidl::android::hardware::light::ILights::{
BnLights, ILights};
mod lights;
use lights::LightsService;
60.6.16 主机微服务编排
Cuttlefish 由launch_cvd与run_cvd协调一组主机进程。device/google/cuttlefish/host/commands/包含约 45 个子工具目录。运行实例按需启动组件:VMM 虚拟机管理器、显示、调制解调器、GNSS、传感器、安全、日志、输入守护进程。

assemble_cvd 把 system、vendor、userdata、boot 分区镜像组装合成磁盘镜像,生成 crosvm 全部配置。run_cvd 启动 crosvm 与所有后台守护进程,监控进程健康,守护进程异常崩溃会自动重启。
60.6.17 Vsock:打通主机‑客户机的核心通道
Vsock (Virtual Sockets) 是 Cuttlefish 主机‑客户机之间通用通信通道。对比 HVC 点对点串口,vsock 支持多路类似 TCP 的连接,可以复用多个端口。
cpp
// Source: device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp:756‑766
if (instance.vsock_guest_cid() >= 2) {
if (instance.vhost_user_vsock()) {
// vhost‑user vsock (separate process)
crosvm_cmd.AddVhostUser("vsock", socket_path);
} else {
// Built‑in crosvm vsock
crosvm_cmd.Cmd().AddParameter("--vsock=cid=",
instance.vsock_guest_cid());
}
}
使用 vsock 的虚拟机组件包括:
- Camera HAL:从宿主机摄像头传输画面帧流
- Light HAL:接收光线状态变更事件
- Vehicle HAL:车载传感器数据
- V4L2 流处理器:视频帧数据传输
- Socket 代理:通用 socket 转 vsock 隧道转发(代码路径:
common/frontend/socket_vsock_proxy/)
60.6.18 多实例支持
Cuttlefish 支持在同一台宿主机上同时运行多台虚拟设备,每个实例拥有独立的 TAP 网卡设备、vsock CID、HVC 端口以及显示输出。
# 启动3个并行的Cuttlefish实例
launch_cvd --num_instances=3
各实例分配资源示例:
- 实例 1:CID=3,TAP 网卡
cvd‑mtap‑01,端口 6520 - 实例 2:CID=4,TAP 网卡
cvd‑mtap‑02,端口 6521 - 实例 3:CID=5,TAP 网卡
cvd‑mtap‑03,端口 6522
实例专属路径由 CuttlefishConfig::InstanceSpecific 管理,它会为每一个实例生成独立的 socket 路径、FIFO 管道路径与日志目录,以此支撑 CI/CD 环境下的大规模并行测试。
60.7 模拟器功能
60.7.1 快照(Snapshots)
快照是 Android 模拟器最核心的能力之一。它完整捕获虚拟机全部运行状态:CPU 寄存器、内存数据、外设状态、磁盘状态,并保存为文件,后续可以一键恢复运行现场。

快照分类
- QuickBoot(快速启动快照) 模拟器关闭时自动保存,下次启动自动恢复。开机耗时可缩短至 2‑5 秒,省去冷启动 60 秒以上的开机时间。
- 命名快照(Named snapshots) 用户通过扩展控制面板或者命令行手动创建,用于保存特定测试状态,例如 "已登录账号"、"预装待测应用"、"固定测试界面"。
快照文件存放在 AVD(Android 虚拟设备)目录下,默认路径: ~/.android/avd/<设备名>.avd/snapshots/
快照内部文件构成
snapshot.pb:Protobuf 格式元数据(虚拟机硬件配置、时间戳)ram.bin:完整虚拟机内存镜像textures.bin:GPU 纹理与显存缓冲区数据<disk>-snapshot.img:写时复制(Copy‑on‑Write)磁盘差分镜像
60.7.2 屏幕录制
模拟器支持多种格式录屏:
- WebM (VP8/VP9 video, Vorbis/Opus audio)
- GIF (animated, for quick sharing)
录屏可通过扩展控制界面或 gRPC 控制接口开启。Cuttlefish 侧提供主机命令 screen_recording_server 实现同类能力。
60.7.3 位置模拟
模拟器提供完善的位置模拟能力:
- Single point -- Set a specific latitude/longitude
- Route playback -- Play back a GPX or KML file along a route
- Speed control -- Adjust playback speed
- Altitude -- Set custom altitude values
控制指令经由 QEMU GPS 服务下发到 GNSS HAL。
60.7.4 电池模拟
模拟器可模拟虚拟电池,可配置项:
- Charge level (0-100%)
- Charging state (charging, discharging, full, not charging)
- AC/USB power connection status
- Battery health status
- Battery temperature
60.7.5 多显示支持
模拟器支持多块虚拟显示屏,方便开发者做多屏场景测试。客户机侧由 MultiDisplayProvider 包管理显示配置:
# 来源:device/generic/goldfish/product/multidisplay.mk
PRODUCT_PACKAGES += MultiDisplayProvider
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST += \
system/lib/libemulator_multidisplay_jni.so \
system/lib64/libemulator_multidisplay_jni.so \
system/priv-app/MultiDisplayProvider/MultiDisplayProvider.apk
输入设备配置最多支持 11 路多点触控输入设备,对应 11 块虚拟显示屏:
# 来源:device/generic/goldfish/product/generic.mk
PRODUCT_COPY_FILES += \
device/generic/goldfish/input/virtio_input_multi_touch_1.idc:... \
device/generic/goldfish/input/virtio_input_multi_touch_2.idc:... \
...
device/generic/goldfish/input/virtio_input_multi_touch_11.idc:...
60.7.6 折叠屏设备模拟
模拟器借助传感器 HAL 定义的铰链角度传感器实现折叠设备模拟。goldfish 源码树包含折叠形态专用配置。
Pixel Fold 配置位于 device/generic/goldfish/pixel_fold/,包含:
device_state_configuration.xml-- defines physical states (folded, unfolded)display_layout_configuration.xml-- display layout for each statedisplay_settings.xml-- display parameterssensor_hinge_angle.xml-- hinge angle sensor mapping
传感器 HAL 支持三路铰链角度传感器(hinge‑angle0、hinge‑angle1、hinge‑angle2),可模拟多铰链设备。
// 来源:device/generic/goldfish/hals/sensors/sensor_list.cpp
{
.sensorHandle = kSensorHandleHingeAngle0,
.name = "Goldfish hinge sensor0 (in degrees)",
.type = SensorType::HINGE_ANGLE,
.maxRange = 360,
.resolution = 1.0,
.flags = SensorFlagBits::DATA_INJECTION |
SensorFlagBits::ON_CHANGE_MODE |
SensorFlagBits::WAKE_UP
},
折叠屏模拟复用现有设备状态框架。用户在模拟器界面修改铰链角度,数据流: 
60.7.7 Wear OS 与旋转输入
模拟器支持 Wear OS 设备形态,可模拟旋转输入。旋转输入设备配置文件:
# 在 generic.mk 中被引用
device/generic/goldfish/input/virtio_input_rotary.idc
开发者可用来测试响应旋转表圈 / 表冠的 Wear OS 应用。
60.7.8 虚拟设备属性配置
模拟器使用分层属性系统配置虚拟硬件参数。属性分为多层:
启动属性(内核命令行 /androidboot) 由模拟器程序设置并传递给内核,在 early‑init 阶段即可以 ro.boot.* 系统属性的形式读取。
**QEMU 属性(qemu‑props 服务)**设备启动完成后,通过 goldfish‑pipe 通道从模拟器宿主机拉取。用于配置屏幕密度、硬件特性以及模拟器专属行为。
产品属性 编译阶段直接固化在系统镜像中,定义路径示例:device/generic/goldfish/product/generic.mk
# 来源:device/generic/goldfish/product/generic.mk
PRODUCT_VENDOR_PROPERTIES += \
ro.control_privapp_permissions=enforce \
ro.crypto.dm_default_key.options_format.version=2 \
ro.crypto.volume.filenames_mode=aes‑256‑cts \
ro.hardware.power=ranchu \
ro.incremental.enable=yes \
ro.logd.size=1M \
ro.kernel.qemu=1 \
ro.soc.manufacturer=AOSP \
ro.soc.model=ranchu \
ro.surface_flinger.has_HDR_display=false \
ro.surface_flinger.has_wide_color_display=false \
ro.surface_flinger.protected_contents=false \
ro.surface_flinger.supports_background_blur=1 \
ro.surface_flinger.use_color_management=false \
ro.zygote.disable_gl_preload=1 \
debug.sf.vsync_reactor_ignore_present_fences=true \
debug.stagefright.c2inputsurface=-1 \
debug.stagefright.ccodec=4 \
graphics.gpu.profiler.support=false \
persist.sys.zram_enabled=1 \
wifi.direct.interface=p2p‑dev‑wlan0 \
wifi.interface=wlan0
关键属性说明:
| 属性 | 值 | 用途 |
|---|---|---|
| ro.kernel.qemu | 1 | 框架标识:运行于模拟器 |
| ro.soc.model | ranchu | 标识虚拟 SoC |
| ro.hardware.power | ranchu | 选定 Power HAL 实现 |
| ro.surface_flinger.has_HDR_display | false | 虚拟显示器不支持 HDR |
| ro.surface_flinger.protected_contents | false | 不支持 DRM 受保护内容 |
| ro.zygote.disable_gl_preload | 1 | 关闭 Zygote 阶段 GL 预加载,避免 GPU 未就绪 |
| debug.sf.vsync_reactor_ignore_present_fences | true | 简化虚拟显示器 VSync 处理逻辑 |
| debug.stagefright.ccodec | 4 | 使用 Codec2 做媒体解码 |
| persist.sys.zram_enabled | 1 | 启用 zram 交换分区 |
60.7.9 模拟器配置文件
模拟器使用 INI 格式配置文件,存放于 AVD 目录以及设备源码树。来自 device/generic/goldfish/data/etc/:
| 文件 | 作用 |
|---|---|
| advancedFeatures.ini | 开启 / 关闭模拟器各项功能 |
| config.ini | 默认硬件配置 |
| config.ini.nexus5 | Nexus5 模拟器配置 |
| config.ini.foldable | 折叠屏设备配置 |
| config.ini.freeform | 自由窗口模式配置 |
| config.ini.desktop | 桌面模式配置 |
| config.ini.nexus7tab | 平板配置 |
| config.ini.pixeltablet | Pixel 平板配置 |
| config.ini.tv | Android TV 配置 |
phone 产品配置将这些文件复制到编译输出:
# 来源:device/generic/goldfish/product/phone.mk
PRODUCT_COPY_FILES += \
device/generic/goldfish/data/etc/advancedFeatures.ini:advancedFeatures.ini \
device/generic/goldfish/data/etc/config.ini.nexus5:config.ini
60.7.10 显示配置文件
模拟器针对不同设备形态提供多套显示布局配置:
# 来源:device/generic/goldfish/product/generic.mk
PRODUCT_COPY_FILES += \
device/generic/goldfish/display_settings_app_compat.xml:\
$(TARGET_COPY_OUT_VENDOR)/etc/display_settings_app_compat.xml \
device/generic/goldfish/display_settings_freeform.xml:\
$(TARGET_COPY_OUT_VENDOR)/etc/display_settings_freeform.xml
XML 文件配置内容包括:
- 显示分辨率与像素密度
- 窗口管理模式(标准模式、自由窗体模式)
- 应用兼容覆盖配置(用于适配无法正常支持多窗口 / 折叠屏的应用)
60.7.11 UWB(超宽带)模拟
模拟器通过 VirtIO console 提供 UWB HAL 支持:
# 来源:device/generic/goldfish/init/init.ranchu.rc
on property:vendor.qemu.vport.uwb=*
symlink ${vendor.qemu.vport.uwb} /dev/hvc2
start vendor.uwb_hal
service vendor.uwb_hal \
/vendor/bin/hw/android.hardware.uwb‑service /dev/hvc2
class hal
user uwb
disabled
60.7.12 Thread 网络
Thread 网络能力由模拟 RCP(无线协处理器)提供:
# 来源:device/generic/goldfish/product/generic.mk
ifneq ($(EMULATOR_VENDOR_NO_THREADNETWORK), true)
PRODUCT_PACKAGES += \
com.android.hardware.threadnetwork‑simulation‑rcp
endif
60.8 Android 17 Cuttlefish 变更
每个版本大部分虚拟设备改动落在 Cuttlefish,Android17 也不例外。本节整理平台开发者需要关注的变更:新增桌面产品目标、客户机侧 VKMS 显示控制器、沙盒化宿主机进程模型、全新 NPU HAL,宿主机启动工具链移出 AOSP 源码树。
60.8.1 桌面产品目标
Android17 在 Cuttlefish 产品目录新增 aosp_cf_x86_64_desktop(配套 ARM64 版本)。和手持设备目标不同,桌面产品继承桌面专属厂商栈,内核取自独立内核树。它作为 Android 桌面形态的虚拟参考设备,验证大屏窗口管理、ndk_translation_only 模式二进制翻译、未压缩 Chrome WebView。该产品在 device/google/cuttlefish/AndroidProducts.mk 注册,和已有的手机、折叠屏、TV、Wear,以及多套车载目标并列。
60.8.2 vkms_controller:客户机侧虚拟显示管理
旧版 Cuttlefish 将虚拟显示配置逻辑分散在宿主机命令与零散客户机脚本。Android17 将逻辑收敛到独立客户机二进制程序 vkms_controller,直接操作内核 VKMS(Virtual Kernel Mode Setting)ConfigFS 接口。宿主机命令行变为无状态薄代理,等价执行 adb shell vkms_controller ...。
cpp
// 来源:device/google/cuttlefish/guest/commands/vkms_controller/main.cpp
namespace cuttlefish {
namespace vkms_controller {
constexpr std::string_view kUsage = R"(
Usage: vkms_controller <command> [options]
A guest‑side utility for Virtual Kernel Mode Setting (VKMS).
It manages virtual displays by interacting directly with the kernel's VKMS
ConfigFS interface.
Commands:
setup
hotplug
reset
list‑presets
list‑displays
)";
该程序负责映射 VKMS ConfigFS 连接器编号到 Android SurfaceFlinger 显示 ID,状态持久化路径 /data/vendor/vkms。支持指定 EDID、图层定义显示屏(setup)、热插拔连接器(hotplug)、列举内置显示器预设(list‑presets)、查询当前显示拓扑(list‑displays)。通过 device/google/cuttlefish/shared/device.mk 安装:
# 来源:device/google/cuttlefish/shared/device.mk
PRODUCT_PACKAGES += \
checkpoint_gc \
vkms_controller
测试脚本或宿主机命令行修改显示配置数据流: 
60.8.3 process_sandboxer:宿主机守护进程沙箱
Cuttlefish 长期存在一个问题:宿主机运行大量辅助守护进程(虚拟机管理器、调制解调器模拟器、GNSS 代理、secure_env 等),权限宽泛。Android17 新增 device/google/cuttlefish/host/commands/process_sandboxer/,借助 sandboxed‑api /sandbox2 库 seccomp 沙箱封装宿主机进程。
cpp
// 来源:device/google/cuttlefish/host/commands/process_sandboxer/main.cpp
#include <sandboxed_api/util/fileops.h>
#include "host/commands/process_sandboxer/policies.h"
#include "host/commands/process_sandboxer/sandbox_manager.h"
namespace cuttlefish::process_sandboxer {
absl::Status ProcessSandboxerMain(int argc, char** argv) {
沙箱为每个可执行程序维护独立策略;policies 目录为每个被沙箱的宿主机工具(run_cvd.cpp、assemble_cvd.cpp、gnss_grpc_proxy.cpp、secure_env.cpp、logcat_receiver.cpp、modem_simulator.cpp、socket_vsock_proxy.cpp 等)提供策略源码,同时包含通用基线策略 baseline.cpp 和逃逸出口 no_policy.cpp。每条策略声明该守护进程允许调用的系统调用与访问文件路径;即便辅助进程被攻破,也无法超出声明访问范围。配套工具 sandboxer_proxy,允许沙箱内进程向管理器申请特权操作。
这是平台内进程隔离在宿主机侧的对应实现:不再把 launcher 完整权限赋予每一个 Cuttlefish 辅助程序,每个程序运行在最小权限策略约束之下。
60.8.4 NPU 调度 HAL
Android17 的 Cuttlefish 新增使用 Rust 编写的客户机 NPU(神经网络处理单元)HAL,路径 device/google/cuttlefish/guest/hals/npu/。注册 android.hardware.npu 调度服务,平台 NPU 业务流程拥有虚拟硬件可供测试。该 HAL 打包为独立 APEX 服务,配套 VINTF 片段声明 IScheduling/default。本版本两大新增客户机 HAL 目录:NPU HAL 与 virtio_media。
60.8.5 宿主机启动工具链迁移
Android17 开发者获取、运行 Cuttlefish 宿主机工具的方式发生变更。总控 cvd 前端程序以及 Debian 软件包不再保留在 AOSP 的 device/google/cuttlefish,迁移至独立仓库 github.com/google/android‑cuttlefish。README 指引开发者跳转外部仓库查阅文档。
实际本地启动分为两条路线: 本源码树编译出来宿主机包依旧提供 launch_cvd、stop_cvd;launch_cvd 软链接指向 cvd_internal_start,编译来源 device/google/cuttlefish/host/commands/start/,对应 README 快速上手流程。
mkdir cf && cd cf
tar xvf /path/to/cvd‑host_package.tar.gz
unzip /path/to/aosp_cf_x86_64_phone‑img‑xxxxxx.zip
HOME=$PWD ./bin/launch_cvd
# ......
HOME=$PWD ./bin/stop_cvd
完整生命周期管理器 cvd、可安装 Debian 包(cuttlefish‑base、cuttlefish‑user)来自外部仓库。Android17 源码树不再包含旧文档提到的 acloud launcher。
60.9 实操:编译并启动自定义模拟器镜像
60.9.1 编译模拟器系统镜像
# 步骤1:初始化编译环境
cd /path/to/aosp
source build/envsetup.sh
# 步骤2:选择编译目标
# x86_64模拟器(x86宿主机性能最好)
lunch sdk_phone64_x86_64‑userdebug
# ARM64模拟器
# lunch sdk_phone64_arm64‑userdebug
# 步骤3:编译系统镜像
m -j$(nproc)
编译产物输出在 $ANDROID_PRODUCT_OUT/
| 镜像 | 说明 |
|---|---|
| system.img | system 分区 |
| vendor.img | vendor 分区 |
| super.img | super 分区,承载动态分区 |
| userdata.img | 用户数据分区 |
| kernel‑ranchu | 内核二进制 |
| ramdisk.img | 初始 ramdisk |
| vendor_boot.img | vendor boot 镜像 |
60.9.2 使用模拟器启动镜像
# 使用编译好镜像直接启动模拟器
emulator
# 带参数启动示例
emulator \
-no‑snapshot \ # 冷启动,跳过快速启动快照
-gpu host \ # 使用宿主机GPU加速
-memory 4096 \ # 内存4GB
-cores 4 \ # 4核CPU
-no‑audio \ # 关闭音频,加快启动
-verbose # 输出详细日志
60.9.3 编译并运行 Cuttlefish
# 步骤1:选择Cuttlefish编译目标
lunch aosp_cf_x86_64_phone‑userdebug
# 步骤2:编译
m -j$(nproc)
# 步骤3:启动(需要预先安装 cuttlefish‑base / cuttlefish‑user 软件包)
launch_cvd
# 步骤4:进入设备shell
adb shell
# WebRTC访问:浏览器打开 https://localhost:8443
60.9.4 定制模拟器镜像
添加自定义 HAL
在自定义产品 mk 文件:
# 自定义产品 .mk
$(call inherit‑product, device/generic/goldfish/product/phone.mk)
# 添加自定义包
PRODUCT_PACKAGES += \
my.custom.hal‑service
# 覆盖属性
PRODUCT_VENDOR_PROPERTIES += \
ro.my.custom.property=value
修改 init 行为
新建自定义 init rc,加入产品拷贝规则:
PRODUCT_COPY_FILES += \
my/custom/init.custom.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/init.custom.rc
修改 SELinux 策略
BOARD_VENDOR_SEPOLICY_DIRS += my/custom/sepolicy
60.9.5 模拟器调试
内核日志
# 查看模拟器内核日志
adb shell dmesg
# 或者读取kernel缓冲区logcat
adb logcat -b kernel
HAL 调试
# 打开传感器HAL详细日志
adb shell setprop log.tag.SensorsHAL VERBOSE
# 查看HAL服务日志
adb logcat -s SensorsHAL:V
# 查看HAL服务运行状态
adb shell dumpsys hwservicemanager
GPU 调试
# 查询当前渲染后端
adb shell getprop ro.hardware.egl
# host GPU返回 emulation;软件渲染返回 swiftshader
# 查询OpenGL ES版本
adb shell getprop ro.opengles.version
# 196610 = OpenGL ES 3.2
# 开启ANGLE调试
adb shell setprop debug.angle.feature_overrides_enabled ...
网络调试
# 查看客户机网络配置
adb shell ip addr show
adb shell ip route show
# 连通性测试
adb shell ping -c 3 google.com
# 查看WiFi状态
adb shell dumpsys wifi
# adb端口转发
adb forward tcp:8080 tcp:8080
60.9.6 性能调优
CPU 与内存
# 启动时指定更大资源
emulator -memory 8192 -cores 8
# 或者修改AVD配置 config.ini
hw.ramSize=8192
hw.cpu.ncore=8
GPU 加速
# host GPU(速度最快,要求宿主机GPU兼容)
emulator -gpu host
# ANGLE Vulkan模式,兼容性好
emulator -gpu angle_indirect
# SwiftShader纯软件渲染,兼容性最好,速度最慢
emulator -gpu swiftshader_indirect
# 客户机渲染,基于DRM,不依赖宿主机GPU
emulator -gpu guest
磁盘性能
cpp
# Use SSD-backed storage for the AVD directory
# The emulator heavily uses random I/O for disk images
# Increase ZRAM to reduce I/O
# (configured automatically via init.ranchu.rc)
60.9.7 进阶:运行多实例
标准模拟器
# 实例1使用默认端口
emulator -avd Phone1 &
# 实例2自动分配端口
emulator -avd Phone2 &
# 查看全部设备
adb devices
# emulator‑5554 device
# emulator‑5556 device
Cuttlefish
# 一次性启动3个实例
launch_cvd --num_instances=3
# 每个实例分配独立资源:
# - ADB端口
# - WebRTC端口
# - Console端口
60.9.8 进阶:自定义内核
# 步骤1:拉取内核源码
repo init -u https://android.googlesource.com/kernel/manifest \
-b common‑android‑mainline
repo sync
# 步骤2:编译内核
BUILD_CONFIG=common/build.config.gki.x86_64 build/build.sh
# 步骤3:模拟器加载自定义内核启动
emulator -kernel /path/to/bzImage \
-system $ANDROID_PRODUCT_OUT/system.img \
-vendor $ANDROID_PRODUCT_OUT/vendor.img
60.9.9 理解产品配置继承链
编译模拟器镜像时产品配置存在明确继承链。以 x86_64 phone 目标举例:
cpp
sdk_phone64_x86_64.mk
-> phone.mk
-> handheld.mk
-> base_handheld.mk
-> multidisplay.mk
-> generic_system.mk
-> handheld_system_ext.mk
-> aosp_product.mk
-> base_phone.mk
-> generic.mk
-> versions.mk
-> phone_overlays.mk
各层职责:
- versions.mk ------ 设定版本号与 API 等级
- generic.mk ------ 模拟器设备核心配置:HAL、软件包、系统属性
- base_handheld.mk ------ 手持设备专属配置(Dalvik 堆内存等)
- handheld.mk ------ 完整手持设备产品配置,包含 system、system_ext、product 分区
- base_phone.mk ------ 手机专属资源覆盖包
- phone.mk ------ 整合全部配置,补充 config.ini 文件
分层设计:新增模拟器产品形态,只需要编写薄薄一层顶层 mk,继承对应基础配置即可。
60.9.10 HAL 实现测试
平台开发者非常适合在模拟器调试 HAL 实现。以修改传感器 HAL 流程为例:
# 步骤1:修改传感器HAL源码
# device/generic/goldfish/hals/sensors/multihal_sensors.cpp
# 步骤2:单独编译传感器模块
m android.hardware.sensors@2.1‑impl.ranchu
# 步骤3:推送更新库文件
adb root
adb remount
adb push $ANDROID_PRODUCT_OUT/vendor/lib64/hw/\
android.hardware.sensors@2.1‑impl.ranchu.so \
/vendor/lib64/hw/
# 步骤4:重启HAL服务
adb shell stop
adb shell start
# 步骤5:验证
adb shell dumpsys sensorservice
Camera HAL 示例:
# 重新编译camera provider
m android.hardware.camera.provider.ranchu
# 推送重启
adb root && adb remount
adb push $ANDROID_PRODUCT_OUT/vendor/bin/hw/\
android.hardware.camera.provider.ranchu \
/vendor/bin/hw/
adb shell stop
adb shell start
# 验证摄像头
adb shell dumpsys media.camera
60.9.11 追踪模拟器通信
调试客户机 HAL 与 QEMU 宿主机交互,可用下面几种手段:
-
logcat 日志过滤
传感器HAL日志
adb logcat -s goldfish:V MultihalSensors:V
Camera HAL日志
adb logcat -s CameraProvider:V QemuCamera:V
GNSS HAL日志
adb logcat -s GnssHwConn:V GnssHwListener:V
Radio HAL日志
adb logcat -s RadioModem:V AtChannel:V
-
对 HAL 服务使用 strace 跟踪系统调用
查找HAL进程PID
adb shell ps -A | grep sensors
挂载strace跟踪read write ioctl
adb shell strace -p
-e trace=read,write,ioctl -s 256 -
QEMU 监控命令
通过模拟器控制台(telnet 连接控制台端口)查看虚拟设备状态:
info qtree # 设备树
info mtree # 内存布局
info ioports # IO端口
60.9.12 编译精简模拟器镜像
CI/CD 场景对启动时间、镜像大小敏感,可以构建 slim 变体,裁剪非必要组件。
lunch sdk_slim_x86_64‑userdebug
m -j$(nproc)
slim 变体来自 device/generic/goldfish/product/slim_handheld.mk,直接继承 generic.mk,不引入完整手持产品继承链,镜像更小、启动更快。
60.9.13 在模拟器上运行 CTS
模拟器是官方支持的 CTS(兼容性测试套件)运行目标。
# 步骤1:启动满足CTS要求的模拟器
emulator -gpu host -memory 4096 -cores 4
# 步骤2:等待开机完成
adb wait‑for‑device
adb shell getprop sys.boot_completed # 返回1代表开机完成
# 步骤3:执行CTS
cd /path/to/cts
./android‑cts/tools/cts‑tradefed
> run cts --plan CTS
# 也可以运行指定测试模块
> run cts -m CtsMediaTestCases
> run cts -m CtsSensorTestCases
部分 CTS 用例依赖特定传感器数值与硬件能力;模拟器传感器 HAL 全部开启 DATA_INJECTION 标记,专门用于满足 CTS 兼容性测试。
60.9.14 模拟器控制台命令
模拟器提供 telnet 控制台直接下发控制指令。
# 连接控制台
telnet localhost 5554
# 电源模拟
power capacity 50 # 电量设置50%
power status charging # 设置充电状态
# 网络模拟
network speed gsm # GSM速率模拟
network delay gprs # GPRS网络时延模拟
# 短信模拟
sms send 5551234567 Hello from the console!
# GPS定位
geo fix -122.084 37.422 # 设置GPS到谷歌总部坐标
# 传感器模拟
sensor set acceleration 0:9.8:0 # 设置加速度计
# 指纹模拟
finger touch 1 # 模拟指纹按压
# 快照管理
avd snapshot save mysnap
avd snapshot load mysnap
avd snapshot list
小结
Android 模拟器是一套复杂的虚拟化平台,可在虚拟硬件上运行真实的 Android 系统镜像。本章梳理了它的分层架构:
- QEMU 核心 ------ 依托 KVM(硬件虚拟化)或 TCG(软件指令翻译)实现 CPU 虚拟化,同时提供内存管理与设备模拟能力。
- Goldfish/Ranchu 虚拟平台 ------ 由一系列虚拟设备构成,包含 VirtIO 设备(显卡、网卡、块设备、输入设备、控制台、随机数发生器),以及用于宿主机‑虚拟机间高带宽通信的 goldfish‑pipe 通道。
- HAL 实现层 ------ 共九个 HAL 模块(音频、相机、传感器、GNSS、射频、指纹、HWC3、图形内存分配器,以及配套支撑库),作为 Android 硬件接口与模拟器虚拟设备之间的适配桥接层。
- GPU 模拟 ------ 采用命令流架构:虚拟机侧的 GLES/Vulkan 调用被序列化,经由 goldfish‑pipe 发送至宿主机,最终在宿主机真实 GPU 上执行回放。
- 网络子系统 ------ 包含虚拟路由、VirtIO 无线网卡、端口转发、多模拟器互通能力。
- Cuttlefish ------ 面向云端的替代方案,复用同一内核与 VirtIO 设备,无需桌面图形界面运行,适合 CI/CD 与服务器自动化测试场景。
- 开发者功能 ------ 支持快照快速回滚、多显示器、折叠屏仿真、定位 / 电池 / 电话模拟,以及丰富的控制台调试指令。
- Android 17 版本 Cuttlefish 变更点 ------ 新增
aosp_cf_x86_64_desktop产品配置;虚拟机端提供vkms_controller显示控制工具;通过process_sandboxer对宿主机守护进程扩充独立可执行文件级别的 seccomp 沙箱;新增 Rust 实现的 NPU 调度 HAL;提供 20 端口 HVC 映射(传感器控制通道与数据通道分离);cvd启动器与 Debian 软件包迁移至外部仓库github.com/google/android‑cuttlefish。
整套架构的核心设计原则:模拟器运行原生真实 Android 系统------ 内核、框架、系统镜像格式与实体设备完全一致。虚拟硬件层对上层软件做到透明无感,保证应用与平台代码在真机和模拟器上行为完全相同。
核心架构原则:模拟器运行真实 Android------ 内核、框架、系统镜像格式与真机完全一致。虚拟硬件层对上层软件透明,应用、平台代码行为在模拟器和物理设备保持一致。
关键源码参考
| 文件 | 用途 |
|---|---|
| device/generic/goldfish/AndroidProducts.mk | 产品目标定义 |
| device/generic/goldfish/board/BoardConfigCommon.mk | 板级通用配置 |
| device/generic/goldfish/product/generic.mk | 模拟器核心产品配置 |
| device/generic/goldfish/product/handheld.mk | 手持设备产品配置 |
| device/generic/goldfish/init/init.ranchu.rc | 初始化脚本,开机流程 |
| device/generic/goldfish/hals/sensors/multihal_sensors.cpp | 传感器 HAL 主体逻辑 |
| device/generic/goldfish/hals/sensors/multihal_sensors_qemu.cpp | QEMU 传感器协议 |
| device/generic/goldfish/hals/sensors/sensor_list.cpp | 传感器清单定义 |
| device/generic/goldfish/hals/camera/CameraProvider.cpp | Camera Provider |
| device/generic/goldfish/hals/camera/qemu_channel.cpp | Camera QEMU pipe 通信 |
| device/generic/goldfish/hals/gnss/GnssHwConn.cpp | GNSS 硬件连接 |
| device/generic/goldfish/hals/radio/RadioModem.cpp | Radio Modem HAL |
| device/generic/goldfish/hals/fingerprint/hal.cpp | 指纹 HAL |
| device/generic/goldfish/hals/hwc3/HostFrameComposer.cpp | 宿主机端 GPU 合成 |
| device/generic/goldfish/hals/hwc3/GuestFrameComposer.cpp | 客户机 DRM 合成 |
| device/generic/goldfish/hals/gralloc/allocator.cpp | 图形缓冲区分配器 |
| device/generic/goldfish/hals/lib/qemud/qemud.cpp | QEMU 多路复用 pipe 库 |
| device/generic/goldfish/qemu‑props/qemu‑props.cpp | qemu‑props 属性服务 |
| device/generic/goldfish/init/init.net.ranchu.sh | 网络初始化脚本 |
| device/generic/goldfish/sepolicy/vendor/qemu_props.te | qemu‑props SELinux 策略 |
| device/generic/goldfish/sepolicy/vendor/hal_gnss_default.te | GNSS HAL SELinux 策略 |
| device/google/cuttlefish/shared/BoardConfig.mk | Cuttlefish 板级配置、内核选择 |
| device/google/cuttlefish/AndroidProducts.mk | Cuttlefish 产品清单,包含桌面 |
| device/google/cuttlefish/vsoc_x86_64_only/desktop/aosp_cf.mk | Android17 新增桌面产品 |
| device/google/cuttlefish/host/libs/vm_manager/crosvm_manager.cpp | crosvm 命令组装、HVC 端口映射 |
| device/google/cuttlefish/host/commands/process_sandboxer/main.cpp | Android17 新增宿主机进程沙箱 |
| device/google/cuttlefish/guest/commands/vkms_controller/main.cpp | Android17 客户机 VKMS 显示控制器 |
| device/google/cuttlefish/guest/hals/npu/main.rs | Android17 Rust 实现 NPU 调度 HAL |
| device/google/cuttlefish/shared/device.mk | Cuttlefish 公共设备配置,安装 vkms_controller |
| device/google/cuttlefish/README.md | Cuttlefish 快速上手,宿主机工具迁移说明 |