Android 系统服务DisplayManagerService和DisplayDevice生命周期解读
一、引言
DisplayManagerService(以下简称DMS)是 Android 系统中用于管理显示设备的核心服务。Android 早期版本中显示管理主要由SurfaceFlinger和WindowManagerService(以下简称WMS)处理 ,DMS只负责管理基本的显示设备和加载相关配置。Android 4.2中引入了多用户支持功能,每个用户可以拥有独立的显示配置,并且支持多个显示设备(如HDMI外接显示器)。到了Android 6中为了方便开发者调试,增加了对虚拟屏和投屏的支持。Android 7和Android 8增加了对分屏与多窗口的支持,DMS负责管理这些小窗口的显示和交互。Android 10中引入了对折叠屏设备的支持,这类设备可以在展开和折叠之间切换,DMS需要处理这些显示形态的变化,将物理屏映射到正确的逻辑显示。Android 13增加了对Ultra HDR资源的显示,使得Android设备能够更好地处理和显示高动态范围内容,DMS负责一些HDR提亮逻辑和策略。
二、DMS详细剖析
1.DMS在显示系统中作用
(1)检测、添加和移除显示设备:监听并检测新显示设备的连接,例如插入新屏幕时可自动识别和适配。
(2)创建和管理逻辑显示:通过抽象出逻辑显示,DMS提供了一个灵活的中间层用来管理一个或多个物理显示设备。
(3)调整显示设备参数:调整显示设备的各种参数,比如屏幕状态、亮度、分辨率、刷新率、显示方向,显示区域等。
(4)管理多显示设备状态切换:多显示设备的连接、断开及切换需要根据当前连接的物理显示设备切换对应的逻辑显示。
(5)事件通知:当显示设备状态变化时(连接、断开、状态变化、配置改变等),及时通知系统的其他组件如 WMS和应用程序。
2.关键组件
图1 DMS中的关键组件UML类图
在DMS模块中,对显示屏幕的描述分为物理显示屏(physical display)和逻辑显示屏(logical display),物理屏主要从SurfaceFlinger中读取参数创建,代表实实在在的物理屏,描述其物理特性,不同物理屏有不同的属性。逻辑屏则是相对于对物理屏,侧重于同一个物理屏的不同逻辑设置,受应用和WMS模块影响,如显示区域、显示位置坐标、显示方向等。每一个物理屏幕都对应一个逻辑屏幕,而一个逻辑屏幕可以对应一个或者多个物理屏幕(多屏设备当中)。因此我们可以通过修改逻辑屏幕参数,做到同一个物理屏的不同显示方式。下面我们就来看下DMS中主要类的作用:
●DisplayManagerService:包括显示设备管理的主要类和方法,是显示管理的核心。
●DisplayManagerInternal:为系统其他组件提供的内部API。
●DisplayManager:为app等其他上层组件提供的外部API,内部通过DisplayManagerGlobal和DisplayManagerService进行交互。
●DisplayManagerGlobal:单例,DisplayManager中方法的具体实现,最终通过binder调用到DMS。
●DisplayDevice:表示具体的物理显示设备(physical display),它包含了与物理显示相关的具体信息。
●DisplayDeviceRepository:管理所有的DisplayDevice,监听所有物理屏的变化。
●LogicalDisplay:上层抽象出来的逻辑显示,负责管理一个或多个物理显示设备,LogicalDisplay提供了一个灵活的中间层,使得系统可以统一处理多个物理设备并动态调整显示配置,并为上层应用和系统服务提供一致的接口。这种架构设计大大简化了显示管理的复杂性,提高了系统的灵活性和可扩展性。
●LogicalDisplayMapper:负责管理所有的LogicalDisplay,并在多屏设备中负责物理显示和逻辑限制之间的映射。
●DisplayAdapter:屏幕适配器,由于不同的物理显示屏有不同的属性和处理方式,因此DMS中通过一系列的屏幕适配器来和分别对各种物理显示屏进行连接。
●DisplayPowerController:管理显示设备的状态和亮度。
3.DMS的启动流程
图2 DMS启动关键流程
在Android系统中SystemServer进程负责DisplayManagerService的启动,SystemServiceManager 在startService中将调用DisplayManagerService的构造方法创建对象,并调用其onStart方法启动服务。
在构造方法中DisplayManagerService会创建UI handle 和display handle,用于处理display事件。以及实例化两个重要的对象mDisplayDeviceRepo和mLogicalDisplayMapper ,mDisplayDeviceRepo管理所有的物理显示屏,而mLogicalDisplayMapper 中管理了所有的逻辑显示。另外在构造函数中还会加载一些默认配置,原生亮度曲线、色彩模式等。
在onStart方法中DisplayManagerService会实现binder service接口和local service接口,用于外部通信,并注册显示器监听并尝试通过SurfaceControl连接默认显示器。
在DisplayManagerService 启动完成后,SystemServer会通知所有的services当前处于PHASE_WAIT_FOR_DEFAULT_DISPLAY阶段,DisplayManagerService 收到这一通知后,会尝试在LogicalDisplayMapper中获取默认display对应的逻辑显示和虚拟显示器适配器。如果都获取不到则使用同步锁的 wait 方法使当前线程等待指定的时间 delay,如果delay时间后还获取不到则会抛出运行时异常,确保了在系统启动过程中,默认显示器和虚拟显示器适配器能够正确初始化。
SystemServer在WMS和IMS启动完成后会通知DMS获取相关服务,并请求WMS进行窗口刷新,确保UI得到更新和正确显示。
SystemServer在启动完所有系统服务后会调用DMS的systemReady方法,完成一些初始化的设置,如更新用户的HDR设置,注册显示模式变化的回调,注册sensor等。
三、DisplayDevice生命周期管理
对 DisplayDevice(显示设备) 的生命周期进行管理是DMS的核心任务,包括设备的添加、移除、配置及状态变更等。以下总结了核心的管理流程:
1.DisplayDevice的检测
在上一节中我们可以看到DMS在启动过程中会创建对应的显示适配器、检测显示设备以及注册显示设备监听。从SurfaceFlinger获取到默认显示设备后,显示适配器会创建对应的DisplayDevice对象,用于记录和管理显示设备的物理属性,并向DisplayDeviceRepository 发送DISPLAY_DEVICE_EVENT_ADDED消息。
2.DisplayDevice的添加
DisplayDeviceRepository 在收到DISPLAY_DEVICE_EVENT_ADDED消息后只是将DisplayDevice加到list当中,然后继续通知LogicalDisplayMapper处理设备添加的流程。LogicalDisplayMapper会通过createNewLogicalDisplayLocked为DisplayDevice创建对应的逻辑显示器(Logical Display),并加载默认的布局文件。
在createNewLogicalDisplayLocked方法中,首先通过displayID获取到对应的layerStack。在DMS和SurfaceFlinger中layerStack是一个重要的概念,主要用于管理不同显示设备上显示内容的层级和排布,每个 layerStack 代表一个逻辑显示层的集合,这些层在一起构成了屏幕的显示内容。另外,在支持多显示设备的时,layerStack 可用于区分和管理各个显示设备的内容,不同的显示设备可以分配不同的 layerStack,从而管理各自的显示内容独立性。通过配置 layerStack,可以动态调整显示内容的布局和组合,适应各种显示需求。接下来,创建新的LogicalDisplay并与displayID、layerStack和DisplayDevice绑定。
LogicalDisplay创建完成后,LogicalDisplayMapper会通过updateLogicalDisplaysLocked按顺序通知DMS两次,分别是LOGICAL_DISPLAY_EVENT_CONNECTED和LOGICAL_DISPLAY_EVENT_ADDED。DMS收到消息后会对LogicalDisplay进行的一些初始化工作,例如创建用于显示设备状态管理的DisplayPowerController对象更新屏幕状态和亮度、加载和配置屏幕的色彩模式、配置屏幕的分辨率和刷新率等等。
在完成默认显示器的初始化后DMS还需要需要唤醒所有被sycnroot大锁阻塞的线程,并通知所有listener,显示设备已添加。
3.DisplayDevice的更新
DisplayDevice的更新主要有以下几个原因:屏幕状态变化、hdr亮度与sdr亮度的比值发生变化、刷新率和分辨率发生变化、色彩模式发生变化等。
这些display 属性发生变化时LocalDisplayAdapter会清空当前的DisplayDeviceInfo,并向上通知LogicalDisplayMapper 更新LogicalDisplay。
LogicalDisplayMapper收到一次更新通知后会对当前所有的LogicalDisplay进行遍历,并更新DisplayDeviceInfo,同时根据diff和前后info的差异识别特定的事件(如hdr亮度与sdr亮度的比值发生变化、刷新率和分辨率发生变化、折叠屏导致的物理显示和逻辑显示的swap等),最后按特定的顺序发送到DMS,再由DMS通知到所有的listener。
DMS在收到LOGICAL_DISPLAY_EVENT_CHANGED事件后会先通过异步消息通知IMS更新viewport,以及通知所有listener中非cache的进程(cache进程需要等到变成非cache才会通知)display已经发生了改变。最后请求WMS重新刷新窗口,确保UI的正常显示。至此,整个DisplayDevice的更新流程就算完成了。
4.DisplayDevice的移除
在DMS的启动过程中我们已经注册了显示设备的监听,在收到移除事件后,LocalDisplayAdapter会通过tryDisconnectDisplayLocked移除相应的DisplayDevice,然后通过LogicalDisplayMapper向DMS发送LOGICAL_DISPLAY_EVENT_REMOVED和LOGICAL_DISPLAY_EVENT_DISCONNECTED消息销毁对象。这里的流程与设备添加的流程基本一致,只是动作正好相反,就不展开赘述了。
四、总结
DMS 在 Android 显示系统中扮演着至关重要的角色, 与 SurfaceFlinger、WMS、IMS、AMS、PMS等系统组件紧密协作,确保显示系统整体功能完备,在各种场景下能够提供稳定、高质量、流畅的显示体验。
往
期
推
荐
WebRTC音视频同步原理与实现详解(下)
走进音频:器件与效果篇