如何为无头设备构建无显示屏/GUI的Android 10 AOSP
Android 10无头系统:添加虚拟显示适配器实现无屏运行
核心结论
完全可以在Android 10中通过添加虚拟显示适配器,实现无物理显示屏/触摸屏环境下的完整Android栈运行,替代原生DISPLAY模块的功能。
实现思路
- 定制虚拟显示HAL驱动:实现符合Android显示HAL规范的虚拟显示模块,让系统识别为合法的主显示设备
- 系统配置适配:禁用物理显示相关配置,强制系统加载虚拟显示模块
- 服务兼容性适配:确保WindowManager等核心服务能正确初始化并绑定虚拟显示
参考代码与配置示例
1. 虚拟显示HAL实现(hardware/libhardware/modules/virtualdisplay/VirtualDisplay.cpp)
#include <hardware/hardware.h> #include <hardware/display.h> #include <cutils/log.h> #include <string.h> static int virtual_display_close(hw_device_t* dev) { free(dev); return 0; } static int get_display_type(const display_device_t* dev) { return DISPLAY_TYPE_VIRTUAL; } static int get_display_size(const display_device_t* dev, uint32_t* width, uint32_t* height) { // 自定义虚拟显示分辨率 *width = 1920; *height = 1080; return 0; } static int get_display_dpi(const display_device_t* dev, uint32_t* xdpi, uint32_t* ydpi) { *xdpi = 320; *ydpi = 320; return 0; } static int set_power_mode(display_device_t* dev, int mode) { // 虚拟显示无需实际电源控制,直接返回成功 return 0; } static int virtual_display_open(const hw_module_t* module, const char* name, hw_device_t** device) { if (strcmp(name, DISPLAY_PRIMARY) != 0) { return -EINVAL; } display_device_t* dev = (display_device_t*)malloc(sizeof(display_device_t)); memset(dev, 0, sizeof(display_device_t)); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = DISPLAY_DEVICE_API_VERSION_1_0; dev->common.module = (hw_module_t*)module; dev->common.close = virtual_display_close; dev->get_display_type = get_display_type; dev->get_display_size = get_display_size; dev->get_display_dpi = get_display_dpi; dev->set_power_mode = set_power_mode; // 其他未实现的方法可留空,系统会处理默认逻辑 *device = &dev->common; return 0; } static struct hw_module_methods_t virtual_display_module_methods = { .open = virtual_display_open, }; struct display_module_t HAL_MODULE_INFO_SYM = { .common = { .tag = HARDWARE_MODULE_TAG, .module_api_version = DISPLAY_MODULE_API_VERSION_1_0, .hal_api_version = HARDWARE_HAL_API_VERSION, .id = DISPLAY_HARDWARE_MODULE_ID, .name = "Virtual Display HAL", .author = "Custom Vendor", .methods = &virtual_display_module_methods, }, };
2. 模块编译配置(hardware/libhardware/modules/virtualdisplay/Android.mk)
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_RELATIVE_PATH := hw LOCAL_PROPRIETARY_MODULE := true LOCAL_MODULE := virtualdisplay.default LOCAL_SRC_FILES := VirtualDisplay.cpp LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware LOCAL_MODULE_TAGS := optional include $(BUILD_SHARED_LIBRARY)
3. 设备配置修改(device/[vendor]/[device]/device.mk)
# 替换默认显示模块为虚拟显示 PRODUCT_PACKAGES += virtualdisplay.default # 强制系统使用虚拟显示 PRODUCT_PROPERTY_OVERRIDES += \ ro.hardware.display=virtualdisplay \ ro.boot.display=virtualdisplay \ ro.display.default_width=1920 \ ro.display.default_height=1080 # 禁用触摸屏相关模块(按需) PRODUCT_PACKAGES := $(filter-out touchscreen.% inputflinger,$(PRODUCT_PACKAGES))
验证方式
编译刷入系统后,通过adb命令确认虚拟显示状态:
adb shell dumpsys display
输出中应显示mDisplayType=VIRTUAL的主显示设备,且系统服务正常启动。
内容的提问来源于stack exchange,提问作者Bhaskar Naik
相关产品推荐
相关产品推荐

