在上一篇文章中,我们系统性地梳理了单个应用从View到最终在屏幕显示的整体链路。但在真实的车载HMI场景里,事情要复杂得多——我们面对的是多个物理屏幕(中控屏、仪表盘、HUD)以及需要高优先级显示的安全图层。本文将深入解析Android系统如何驾驭“真假”两种多屏互动场景,打通从硬件绑定到画面合成的完整流程。
所谓“真多屏”,指的是系统同时管理多个物理屏幕,实现硬件级的空间分工,例如导航显示在中控,车速信息显示在仪表盘。而“假多屏”则是指在同一个物理屏幕上,通过软件虚拟出独立的显示图层,实现高优先级内容(如虚拟人、紧急告警)的置顶显示,解决“时间抢占”问题。
无论真假,其核心链路都遵循同一套Android框架逻辑。本文将沿着以下脉络展开:
- 硬件层:多Display显存的创建,以及如何通过VHAL和Linux驱动与物理或虚拟屏幕绑定。
- DMS (DisplayManagerService):作为中枢,如何通过LogicalDisplay统一管理所有屏幕并分配核心ID。
- WMS (WindowManagerService):如何通过DisplayContent将Activity和View的窗口内容,精准路由到目标屏幕。
- SurfaceFlinger:这个合成引擎如何依据LayerStack ID,将不同的图层组正确合成到各自的显示设备。
- VSYNC机制:如何协同管理多个屏幕各不相同的刷新节奏。
理解了这条链路,你就能明白一个Android系统是如何实现“不同内容在正确位置、以正确优先级呈现”这一复杂目标的。
一、阶段1:多 Display 显存创建 + VHAL/Linux 驱动与屏幕的绑定
这是多屏互动的“硬件底座”,决定了“真 / 假多屏”的底层形态,也是 Android 的 Display 抽象与物理 / 虚拟屏幕的首次绑定。
1. 真多屏(物理多屏:中控 / 仪表盘 / HUD)
车载场景下的物理多屏,核心是“硬件级隔离”:
- 显存创建:Linux 内核为每个物理屏幕分配独立的帧缓冲区(FrameBuffer,如
/dev/fb0 对应中控屏、/dev/fb1 对应仪表盘),每块帧缓冲区对应专属显存,用于存储该屏幕的像素数据,互不占用;
- 驱动层绑定:车载 SOC 的 Display Controller(显示控制器)驱动(如 MIPI-DSI/LVDS/HDBaseT 驱动)负责将帧缓冲区与物理屏幕的硬件接口绑定,管控像素数据从显存到物理屏的传输;
- VHAL 桥接:Android 车载专属的 Vehicle HAL(VHAL)封装车载硬件抽象,将物理屏幕的核心属性(分辨率、刷新率、屏幕类型(中控 / 仪表盘 / HUD)、接口协议)上报给 Framework 层的 DMS,完成“物理硬件屏 → Android Display 抽象”的映射。
// 通过VHAL注册物理屏(车载特有路径)
VehicleHal vhal = VehicleHal.getInstance();
vhal.registerDisplay("instrument_cluster", DISPLAY_TYPE_INSTRUMENT); // 仪表盘
vhal.registerDisplay("center_console", DISPLAY_TYPE_MAIN); // 中控屏
// Linux驱动层:DRM/KMS框架初始化
// /sys/class/drm/card0-HDMI-A-1/ // 仪表屏节点
// /sys/class/drm/card0-eDP-1/ // 中控屏节点
2. 假多屏(虚拟图层:虚拟人 / 语音识别)
车载高优先级虚拟图层,核心是“软件级复用”:
- 显存创建:无独立物理显存,通过
DisplayManager.createVirtualDisplay() 创建虚拟 Display,其显存直接复用主屏幕(中控屏)的帧缓冲区,仅在内存中划分独立的图层区域;
- 驱动层绑定:无额外硬件驱动绑定,虚拟 Display 不占用独立 FrameBuffer,仅通过软件层标记“高优先级图层”;
- VHAL 赋能:通过 VHAL 为虚拟 Display 打上“车载高优先级”标签(如虚拟人、紧急告警),确保其 Z 序优先级高于状态栏、导航栏等系统 UI。
VirtualDisplay vd = mediaProjectin.createVirtualDisplay(
"SafetyAlertLayer", 1920, 720, 320,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
surface, null, null);
二、阶段2:DMS——多屏中枢调度
DMS 是 Display 的“总管家”,统一管理所有物理 / 虚拟 Display,为上层提供标准化的 Display 抽象,是连接硬件层和窗口层的核心节点。
- Display 识别与 LogicalDisplay 创建:
- DMS 通过不同的 DisplayAdapter(LocalDisplayAdapter 管物理屏、VirtualDisplayAdapter 管虚拟屏)监听屏幕的连接 / 创建事件;
- 为每个物理 / 虚拟 Display 创建
LogicalDisplay 对象(车载场景典型映射:中控屏→LogicalDisplay0、仪表盘→LogicalDisplay1、虚拟人图层→LogicalDisplay2),封装该 Display 的所有硬件 / 软件属性;
- 核心 ID 分配(多屏绑定的“身份证”):
- Display ID:分配全局唯一的 64 位 ID(车载场景会固化物理屏 ID,如中控屏固定为 0,仪表盘固定为 1),用于上层精准识别目标 Display;
- LayerStack ID:为每个 LogicalDisplay 分配唯一的 LayerStack ID(1:1 映射),这是后续 WMS/SurfaceFlinger 判断“图层归属”的核心标识;
- 信息分发:DMS 将
LogicalDisplay 的完整信息(Display ID、LayerStack ID、分辨率、刷新率、是否为虚拟高优先级屏)打包,主动同步给 WMS 和 SurfaceFlinger,让两者感知所有 Display 的存在。
// LogicalDisplay核心管理逻辑
class DisplayManagerService {
void addDisplayDevice(DisplayDevice device) {
int displayId = allocateDisplayId(); // 全局唯一ID(如200=仪表盘)
int layerStackId = allocateLayerStackId(); // 图层栈ID(仪表盘=1,中控=0)
LogicalDisplay ld = new LogicalDisplay(displayId, layerStackId, device);
mLogicalDisplays.put(displayId, ld);
// 通知WMS与SurfaceFlinger
mWindowManagerInternal.onDisplayAdded(displayId, layerStackId);
mSurfaceFlingerProxy.setDisplayInfo(displayId, device.getPhysicalInfo());
}
}
三、阶段3:WMS——窗口精准路由
WMS 负责将应用的 Activity/View 与目标 Display 绑定,核心是为每个 Display 创建 DisplayContent 容器,让所有窗口都有明确的 LayerStack ID。
- DisplayContent 创建:WMS 从 DMS 获取所有 Display 信息后,为每个 Display 创建
DisplayContent 对象(1 个 Display = 1 个 DisplayContent),并绑定对应的 LayerStack ID—— 这是窗口与 Display 绑定的“专属容器”;
- 两种绑定形态(车载场景适配):
- 形态 1:Activity 绑定:车载应用(如导航 APP、车辆设置 APP)通过
ActivityOptions.setLaunchDisplayId(displayId)(Android 12+)或 Presentation(低版本兼容),将 Activity 绑定到目标 Display;WMS 将 Activity 的 DecorView(底层是 Window)归属到对应 DisplayContent,自动继承其 LayerStack ID;示例:导航 APP 绑定 Display ID=0(中控屏),则其所有 View 的 LayerStack ID=0;
- 形态 2:悬浮窗 View 绑定:真多屏:仪表盘的车速控件通过
WindowManager.LayoutParams.display = 1(仪表盘 Display ID)绑定到仪表盘,LayerStack ID 自动继承为 1;假多屏:虚拟人 View 通过 LayoutParams.display = 2(虚拟 Display ID)绑定,同时设置 TYPE_APPLICATION_OVERLAY+ 最高 Z 序,确保置顶显示;最终效果:所有窗口 / View 都关联到唯一的 LayerStack ID,明确“该显示到哪个 Display”。
// 将Activity绑定至指定Display
void launchActivityOnDisplay(Intent intent, int targetDisplayId) {
ActivityRecord r = new ActivityRecord(intent);
DisplayContent dc = mDisplayContents.get(targetDisplayId); // 获取目标屏上下文
r.setDisplayContent(dc);
r.setLayerStackId(dc.getLayerStackId()); // 关键:窗口携带LayerStack标识
// 悬浮窗特殊处理(假多屏场景)
if (isSafetyAlertWindow) {
r.setLayerStackId(SAFETY_LAYER_STACK_ID); // 强制路由至高优先级图层
r.setWindowType(TYPE_APPLICATION_OVERLAY);
}
}
四、阶段4:SurfaceFlinger——分层合成引擎
SurfaceFlinger 是多屏显示的“最终执行者”,核心是按 LayerStack ID 将图层合成到对应 Display,实现内容的精准输出。
- 图层归属判断:SurfaceFlinger 遍历所有 Layer(每个 Window/View 对应一个 Layer),根据 Layer 的 LayerStack ID,将其归类到对应 Display 的图层集合;
- 硬件加速:车载 SOC 的 HWC(HWComposer)硬件级合成,减少 CPU/GPU 开销,保证中控 + 仪表盘双屏合成的流畅性。
class SurfaceFlinger : public MessageQueue::Handler {
private:
// 显示设备管理
std::unordered_map<int32_t, sp<DisplayDevice>> mDisplays;
// Layer按Display分组
std::unordered_map<int32_t, LayerVector> mLayersByDisplay;
public:
// 合成主循环
void handleMessageRefresh() {
// 1. 准备帧
preComposition();
// 2. 为每个Display进行合成
for (auto& [displayId, display] : mDisplays) {
// 获取该Display的所有Layer
const LayerVector& layers = getLayersForDisplay(displayId);
// 合成该Display
rebuildLayerStacks(display, layers);
doDisplayComposition(display);
}
// 3. 后处理
postComposition();
}
// 获取指定Display的所有Layer
const LayerVector& getLayersForDisplay(int32_t displayId) {
auto it = mLayersByDisplay.find(displayId);
if (it == mLayersByDisplay.end()) {
// 按LayerStack ID过滤
LayerVector layers;
for (const auto& layer : mLayersPendingUpdate) {
if (layer->getLayerStack() == getLayerStackForDisplay(displayId)) {
layers.add(layer);
}
}
mLayersByDisplay[displayId] = layers;
return mLayersByDisplay[displayId];
}
return it->second;
}
// 获取Display对应的LayerStack ID
int32_t getLayerStackForDisplay(int32_t displayId) {
sp<DisplayDevice> display = getDisplayDevice(displayId);
if (display != nullptr) {
return display->getLayerStack();
}
return 0;
}
// 重建Layer堆栈(按Z-order排序)
void rebuildLayerStacks(const sp<DisplayDevice>& display,
const LayerVector& layers) {
// 清空当前显示列表
display->clearVisibleLayers();
// 按Z-order排序
LayerVector sortedLayers = layers;
std::sort(sortedLayers.begin(), sortedLayers.end(),
[](const sp<Layer>& a, const sp<Layer>& b) {
return a->getZ() < b->getZ();
});
// 过滤可见Layer
for (const auto& layer : sortedLayers) {
if (layer->isVisible()) {
display->addVisibleLayer(layer);
}
}
}
// 执行显示合成
void doDisplayComposition(const sp<DisplayDevice>& display) {
// 1. 开始帧
display->beginFrame();
// 2. latch缓冲区
const LayerVector& layers = display->getVisibleLayers();
for (const auto& layer : layers) {
layer->latchBuffer(display->getVsyncTime());
}
// 3. 准备合成
display->prepareFrame();
// 4. 合成图层
std::vector<Layer*> layersToComposite;
for (const auto& layer : layers) {
if (layer->hasReadyFrame()) {
layersToComposite.push_back(layer.get());
}
}
// 5. 调用HWC合成或GPU合成
if (display->getHwcDisplayId() >= 0) {
// 尝试硬件合成
if (!doHwcComposition(display, layersToComposite)) {
// 回退到GPU合成
doGpuComposition(display, layersToComposite);
}
} else {
// 虚拟显示使用GPU合成
doGpuComposition(display, layersToComposite);
}
// 6. 提交帧
display->swapBuffers();
// 7. 回收缓冲区
for (const auto& layer : layers) {
layer->onPostComposition();
}
}
};
五、阶段5:多VSync协同机制
VSYNC 是“显示更新的节拍器”,串联起多屏的刷新率 / 分辨率适配,保证多屏更新的稳定性和同步性。
- 真多屏 VSYNC 管控:
- 每个物理屏幕由 HWC 生成独立的硬件 VSYNC 信号(如中控 120Hz、仪表盘 60Hz、HUD 30Hz);
- SurfaceFlinger 为每个 DisplayDevice 绑定独立的 VSYNC 监听器,仅在对应 VSYNC 到来时触发合成,适配不同屏幕的刷新率;
- 车载优化:仪表盘 / HUD 无需高帧率,通过
WindowManager.LayoutParams.preferredRefreshRate 将其帧率限制为 30Hz,降低车载 SOC 功耗;
- 假多屏 VSYNC 管控:
- 虚拟 Display 共享中控屏的 VSYNC 信号,通过
Choreographer.getInstance(虚拟Display) 监听专属 VSYNC;
- 无交互时暂停 VSYNC 监听,仅在虚拟人 / 语音识别激活时更新图层,减少资源消耗;
// 为不同Display注册独立VSync监听
Choreographer.getInstance(DISPLAY_ID_INSTRUMENT).postFrameCallback(...);
Choreographer.getInstance(DISPLAY_ID_MAIN).postFrameCallback(...);
// 虚拟显示合成
class VirtualDisplaySurface : public ConsumerBase,
public VirtualDisplaySurface {
private:
int32_t mDisplayId;
int32_t mLayerStackId;
sp<IGraphicBufferProducer> mOutputProducer;
sp<IGraphicBufferConsumer> mOutputConsumer;
public:
VirtualDisplaySurface(int32_t displayId, int32_t layerStackId,
const String8& name, uint32_t width, uint32_t height)
: mDisplayId(displayId), mLayerStackId(layerStackId) {
// 创建BufferQueue用于输出
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> consumer;
BufferQueue::createBufferQueue(&producer, &consumer);
mOutputProducer = producer;
mOutputConsumer = consumer;
// 配置BufferQueue
mOutputConsumer->setConsumerName(name);
mOutputConsumer->setDefaultBufferSize(width, height);
mOutputConsumer->setDefaultBufferFormat(HAL_PIXEL_FORMAT_RGBA_8888);
mOutputConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
// 设置LayerStack
native_window_set_layer_stack(mOutputProducer.get(), layerStackId);
}
// 当有新的帧可用时
void onFrameAvailable(const BufferItem& item) override {
// 1. 获取缓冲区
status_t err = acquireBuffer(&item);
if (err != NO_ERROR) return;
// 2. 更新显示
sp<GraphicBuffer> buf = mSlots[item.mSlot].mGraphicBuffer;
// 3. 合成到虚拟显示
if (mOutputProducer != nullptr) {
// 将缓冲区推送到输出
int slot;
sp<Fence> fence;
err = mOutputProducer->dequeueBuffer(&slot, &fence,
buf->getWidth(),
buf->getHeight(),
buf->getFormat(),
GRALLOC_USAGE_HW_COMPOSER);
if (err == NO_ERROR) {
// 队列缓冲区到输出
IGraphicBufferProducer::QueueBufferInput input(
item.mTimestamp, false/* isAutoTimestamp */,
buf->getWidth(), buf->getHeight(),
item.mTransform, fence);
IGraphicBufferProducer::QueueBufferOutput output;
mOutputProducer->queueBuffer(slot, input, &output);
}
}
// 4. 释放缓冲区
releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, fence);
}
// 合成虚拟显示内容到主显示(假多屏)
void compositeToMainDisplay(const sp<DisplayDevice>& mainDisplay) {
// 获取虚拟显示的Surface
sp<Surface> surface = getSurface();
// 创建一个Overlay Layer
sp<Layer> overlayLayer = new Layer(mFlinger, nullptr);
overlayLayer->setLayerStack(mLayerStackId);
overlayLayer->setZOrderTop(VIRTUAL_DISPLAY_Z_ORDER); // 最高Z-order
// 设置Surface内容
overlayLayer->setSurface(surface);
// 添加到主显示的合成列表
mainDisplay->addVisibleLayer(overlayLayer);
}
};
结语
- 全链路核心脉络:硬件层(显存 / 驱动 / VHAL)→DMS(LogicalDisplay/ID 分配)→WMS(DisplayContent / 窗口绑定)→SurfaceFlinger(LayerStack ID 合成)→VSYNC 管控,LayerStack ID 是贯穿全链路的核心标识;
- 真假多屏的核心差异:真多屏是“多物理屏 + 独立显存 / LayerStack/VSYNC”,假多屏是“单物理屏 + 虚拟 Display + 共享显存 + 置顶 Z 序”,均基于同一套 Android 框架实现;
在车载HMI这一高安全、高体验要求的场景中:
- 真多屏解决“空间分工”问题(仪表专注安全,中控专注交互)
- 假多屏解决“时间抢占”问题(关键信息穿透干扰)
二者通过DMS-WMS-SurfaceFlinger铁三角协同,将硬件多样性封装为统一的Display抽象。这不仅是Android系统的技术实现,更是人机工程学在系统架构层面的深刻体现,最终达成了“不同内容在正确位置、以正确优先级呈现”的HMI终极目标。如果你对移动开发或系统底层技术有更多兴趣,欢迎到云栈社区与其他开发者交流探讨。