Android DisplayManagerService 是 Android 系统中的一个非常重要的服务,负责管理所有显示设备,包括屏幕、外部显示设备、虚拟屏,以及处理与显示相关的事件和请求。本文将对DisplayManagerService相关的知识做梳理和总结。
1、DMS功能概述
1.1 简介
DisplayManagerService 用来管理显示的生命周期,它决定如何根据当前连接的物理显示设备控制其逻辑显示,并且在状态更改时,向系统和应用程序发送通知,等等。
Android DisplayManagerService 的主要功能包括:
- 管理所有显示设备,包括屏幕和外部显示设备的连接和断开;
- 处理与显示相关的事件和请求,如屏幕旋转、分辨率调整、显示模式切换等;
- 提供对所有显示设备的状态和属性的查询和设置;
- 协调多个应用程序之间的显示资源的分配和释放;
- 提供与显示相关的系统服务,如截屏、录屏等。
目前有以下四种Display类型,同时对应着四种方式的适配器(DisplayAdapter )供使用:
- LocalDisplay:LocalDisplayAdapter,本地显示设备提供适配器;
- WifiDisplay:WifiDisplayAdapter,无线连接显示适配器,通过无线的投屏场景;
- VirtualDisplay:VirtualDisplayAdapter,虚拟显示适配器,录屏等场景常用;
- OverlayDisplay:OverlayDisplayAdapter,开发者提供的模拟显示适配器;
1.2 关键功能类
-
DisplayDevice: 表示一个显示设备,包括屏幕和外部显示设备,负责管理显示设备的连接和断开,以及显示属性的查询和设置等;;
-
LocalDisplayDevice:DisplayDevice的子类,代表内置物理屏幕,DMS启动后会通过SurfaceControl去读取内置屏幕数据,并创建该类对象;
-
WifiDisplayDevice:DisplayDevice的子类,代表通过Wifi连接显示的物理屏幕;
-
OverlayDisplayDevice:DisplayDevice的子类,开发者选项->模拟辅助显示开启后,创建的就是该类对象;
-
VirtualDisplayDevice:DisplayDevice的子类,表示虚拟显示屏幕,用于屏幕录制等;
-
LogicalDisplay:代表逻辑显示屏,每一个physical display都会对应一个logical display;
-
DisplayDeviceInfo: DisplayDevice信息封装类,在创建DisplayDevice时会进行创建,与之对应的是Logical display 的DisplayInfo;
-
DisplayInfo:LogicalDisplay信息的封装类,基本数据由DisplayDeviceInfo中获得,app可以通过WMS来修改自己的参数;
-
DisplayAdapter: 各物理屏和DMS进行连接的适配器;
-
LocalDisplayAdapter: 继承于DisplayAdapter, 用于LocalDisplayDevice和DMS的连接;
-
WifiDisplayAdapter: 继承于DisplayAdapter,用于WifiDisplayDevice的和DMS的连接;
-
OverlayDisplayAdapter:继承于DisplayAdapter,用于OverlayDisplayDevice和DMS的连接;
-
VirtualDisplayAdapter:继承于DisplayAdapter,用于VirtualDisplayDevice和DMS的连接;
-
DisplayAdapter.Listener:用于通知DisplayDevice发生变化的接口,DMS中对其进行了实现,会接收以下三个事件并根据事件作出全局反应
a.添加了新的DisplayDevice;
b.DisplayDevice状态发生变化;
c.移除DisplayDevice。 -
DisplayViewport:携带有physical display参数,用于通知IMS display信息。
Directory | Class |
---|---|
frameworks/base/core/java/android/hardware/display | DisplayManager, DisplayMangaerGlobal, … |
frameworks/base/core/java/android/view | DisplayInfo, DisplayViewport, … |
frameworks/base/services/core/java/com/android/server/display | DMS,DisplayDevice, … |
1.3 DisplayManagerService 的工作原理
DisplayManagerService的工作原理可以简单概括为以下几个步骤:
-
初始化:系统启动时,DisplayManagerService会被创建并初始化。它会扫描设备上的所有显示器,并建立相应的数据结构来管理它们。
-
显示器连接状态的监测:DisplayManagerService会定期检查设备上的显示器连接状态是否发生变化。如果有显示器连接或断开,它会发送广播通知应用程序。
-
显示器信息的获取:应用程序可以通过DisplayManagerService提供的接口来获取屏幕的相关信息。下面是一个使用DisplayManagerService获取主屏幕分辨率的示例代码:
DisplayManager dm = (DisplayManager) getSystemService(Context.DISPLAY_SERVICE);
Display defaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
Point size = new Point();
defaultDisplay.getRealSize(size);
int screenWidth = size.x;
int screenHeight = size.y;
- 屏幕旋转的处理:当设备发生旋转时,DisplayManagerService会相应地调整屏幕的显示方向,并发送广播通知应用程序。应用程序可以注册广播接收器来监听屏幕旋转的事件。
2, DMS架构
1.1 框图
最上层为API层,应用可以通过DisaplayManager调用到DMS服务的功能接口;FWK层DisplayManagerService为主要的Display管理服务;Hal层的SurfaceFlinger为DMS提供基础的服务,包括显示设备的参数信息、创建虚拟屏等;
1.2 类图
以系统built in display为例,整理类图关系,DMS向下通过LocalDisplayAdapter适配器与LocalDisplayDevice建立关系,然后LocalDisplayDevice对应相应的DisplayDevice。DMS向上通过DisplayManagerGlobal和DisplayManager绑定,暴露接口给到应用层使用。
3、DMS的启动流程
DisplayManagerService继承于SystemService,因此他的启动流程和其他SystemService一样,由SystemServer启动。在SytemServer中:
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
...
t.traceBegin("StartDisplayManager");
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);//启动DMS服务
t.traceEnd();
// We need the default display before we can initialize the package manager.
t.traceBegin("WaitForDisplay");
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);//启动默认的display
...
}
SystemServer中启动DMS后,并保留了DMS对象引用,因此除了执行正常启动方法之外,还进行了以下操作:
// frameworks/base/services/java/com/android/server/SystemServer.java
private void startBootstrapServices() {
...
// DisplayManagerService needs to setup android.display scheduling related policies
// since setSystemProcess() would have overridden policies due to setProcessGroup
mDisplayManagerService.setupSchedulerPolicies();//确保其为优先级最高的进程
}
private void startOtherServices() {
...
mDisplayManagerService.windowManagerAndInputReady();//获得WMS、IMS对象
...
mDisplayManagerService.systemReady(safeMode, mOnlyCore);//系统其他组件已准备完成,可以工作了
...
}
下面依次看这些方法。
3.1.执行DisplayManagerService()
DMS启动过程中,首先会执行其构造方法:
//frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
@VisibleForTesting
DisplayManagerService(Context context, Injector injector) {
super(context);
mInjector = injector;
mContext = context;
// android.display线程handler
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
// android.ui线程Handler
mUiHandler = UiThread.getHandler();
// 创建DisplayAdapter.Listener对象
mDisplayAdapterListener = new DisplayAdapterListener();
// 创建DisplayModeDirector对象
mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
…
mSystemReady = false;
}
创建了mHandler和mUiHandler用来自身和其他消息队列处理;
DisplayAdapterListener继承于DisplayAdapter.Listener,负责给DMS传递各个DisplayAdapter中发出的事件;DisplayModeDirector负责监听并选择系统中各类Display配置组合;
3.2.执行onStart()
接下来执行onStart()方法:
//frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
public void onStart() {
// 加载数据
synchronized (mSyncRoot) {
mPersistentDataStore.loadIfNeeded();
loadStableDisplayValuesLocked();
}
// android.display线程中创建默认DisplayAdapter
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
// 向ServiceManager注册Binder Service
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /allowIsolated/);
// 注册Local Service
publishLocalService(DisplayManagerInternal.class, new LocalService());
}
首先,利用PersistentDataStore加载display中的固定数据,这些数据都是以xml文件的形式,保存在/data/system/display-manager-state.xml中;
mt2712_saic_ec32:/data/system # cat display-manager-state.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<display-manager-state>
<remembered-wifi-displays />
<display-states />
<stable-device-values>
<stable-display-width>1280</stable-display-width>
<stable-display-height>768</stable-display-height>
</stable-device-values>
<brightness-configurations />
</display-manager-state>
然后,在android.display线程中开始注册默认DisplayAdapter;
最后,将内部BinderService对象注册到ServiceManager中,将LocalService发布到LocalServices中,进行system_server内外部的交互。
注册默认DisplayAdapter通过registerDefaultDisplayAdapters()方法进行:
private void registerDefaultDisplayAdapters() {
synchronized (mSyncRoot) {
registerDisplayAdapterLocked(new LocalDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
…
}
}
这里创建LocalDisplayAdapter对象,并将LocalDisplayAdapter对象添加到DisplayAdapter列表中:
private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
mDisplayAdapters.add(adapter); // 添加到DisplayAdapter列表
adapter.registerLocked(); // DisplayAdapter中进行注册
}
这里将执行各个DisplayAdapter.registerLocked()方法进行不同适配器的注册工作。在LocalDisplayAdapter中,会根据物理屏创建逻辑屏。这部分内容的省略,详细分析见下文DisplayAdapter和DisplayDevice的创建。
//frameworks/base/services/core/java/com/android/server/display/LocalDisplayAdapter.java
public void registerLocked() {
super.registerLocked();
mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper());
for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
tryConnectDisplayLocked(physicalDisplayId);
}
}
3.3.执行onBootPhase()
onStart()执行完毕之后,将执行onBootPhase()方法:
@Override
public void onBootPhase(int phase) {
if (phase == PHASE_WAIT_FOR_DEFAULT_DISPLAY) {
synchronized (mSyncRoot) {
long timeout = SystemClock.uptimeMillis()
mInjector.getDefaultDisplayDelayTimeout();
// 超过timeout之后,如果mLogicalDisplays列表中还没有添加逻辑显示,则抛出异常
while (mLogicalDisplays.get(Display.DEFAULT_DISPLAY) == null ||
mVirtualDisplayAdapter == null) {
long delay = timeout - SystemClock.uptimeMillis();
if (delay <= 0) {
throw new RuntimeException(“Timeout waiting …”);
}
try {
mSyncRoot.wait(delay);
} catch (InterruptedException ex) {
}
}
}
}
}
PHASE_WAIT_FOR_DEFAULT_DISPLAY阶段是最早的一个启动阶段,当一些引导服务启动完毕后,启动后续服务时,检查DMS是否已经创建默认逻辑屏,如果在10s内没有完成默认LogicalDisplay的创建,则抛出异常。
SystemService的生命周期方法全部执行完毕,下面继续看启动过程中SytemServer执行的其他方法。
3.4.setupSchedulerPolicies()
SystemServer里调用,给以上三个线程设置线程组和调度集,将线程组设为Process.THREAD_GROUP_TOP_APP,以确保更加高效的执行。
public void setupSchedulerPolicies() {
// android.display and android.anim is critical to user experience and we should make sure
// it is not in the default foregroup groups, add it to top-app to make sure it uses all
// the cores and scheduling settings for top-app when it runs.
Process.setThreadGroupAndCpuset(DisplayThread.get().getThreadId(),
Process.THREAD_GROUP_TOP_APP);
Process.setThreadGroupAndCpuset(AnimationThread.get().getThreadId(),
Process.THREAD_GROUP_TOP_APP);
Process.setThreadGroupAndCpuset(SurfaceAnimationThread.get().getThreadId(),
Process.THREAD_GROUP_TOP_APP);
}
3.5.windowManagerAndInputReady()
SystemServer里调用,当SystemServer中启动WindowManagerService和InputManagerService完成后,在DMS中获取这两个的对象;
// TODO: Use dependencies or a boot phase
public void windowManagerAndInputReady() {
synchronized (mSyncRoot) {
mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
scheduleTraversalLocked(false);
}
}
3.6.systemReady()
SystemServer里调用,所有准备条件满足后,开启正式工作,发送MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS来注册其他的adapter。
public void systemReady(boolean safeMode, boolean onlyCore) {
synchronized (mSyncRoot) {
mSafeMode = safeMode;
mOnlyCore = onlyCore;
}
mHandler.sendEmptyMessage(MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS);
}
4、创建DisplayDevice和LogicalDisplay
前面在onStart()中分析到,发送了MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS消息,跟随调用关系,会调用到registerDefaultDisplayAdapters()方法,一起看一下:
private void registerDefaultDisplayAdapters() {
// Register default display adapters.
synchronized (mSyncRoot) {
// main display adapter
registerDisplayAdapterLocked(new LocalDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
mHandler, mDisplayAdapterListener);
if (mVirtualDisplayAdapter != null) {
registerDisplayAdapterLocked(mVirtualDisplayAdapter);
}
}
}
在该方法内部执行registerDisplayAdapterLocked(),会先创建LocalDisplayAdapter实例作为参数传入,接下来创建了VirtualDisplayAdapter实例,然后执行registerDisplayAdapterLocked()进行注册,先看一下registerDisplayAdapterLocked()实现:
private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
mDisplayAdapters.add(adapter);
adapter.registerLocked();
}
先将adapter存入mDisplayAdapters进行管理,然后执行DisplayAdapter的registerLocked();
接下来看一下LocalDisplayAdapter类实现:
4.1.LocalDisplayAdapter
final class LocalDisplayAdapter extends DisplayAdapter {
... ...
private static final String UNIQUE_ID_PREFIX = "local:";
private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
};
... ...
public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener) {
super(syncRoot, context, handler, listener, TAG);
}
}
LocalDisplayAdapter继承DisplayAdapter,在构造方法内部执行调用父类的构造方法,一起看一下:
public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
Context context, Handler handler, Listener listener, String name) {
mSyncRoot = syncRoot;
mContext = context;
mHandler = handler;
mListener = listener;
mName = name;
}
进行一些赋值操作,后续相关逻辑会在父类里面进行调用处理;接下来看一下registerLocked()方法:
@Override
public void registerLocked() {
super.registerLocked();
mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
tryConnectDisplayLocked(builtInDisplayId);
}
}
当调用registerLocked()时,会遍历BUILT_IN_DISPLAY_IDS_TO_SCAN执行tryConnectDisplayLocked():
private void tryConnectDisplayLocked(int builtInDisplayId) {
IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
if (displayToken != null) {
SurfaceControl.PhysicalDisplayInfo[] configs = SurfaceControl.getDisplayConfigs(displayToken);
...............
int activeConfig = SurfaceControl.getActiveConfig(displayToken);
...............
int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
...................
int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
LocalDisplayDevice device = mDevices.get(builtInDisplayId);
if (device == null) {
// Display was added.
device = new LocalDisplayDevice(displayToken, builtInDisplayId,
configs, activeConfig, colorModes, activeColorMode);
mDevices.put(builtInDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
} else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig,
colorModes, activeColorMode)) {
// Display properties changed.
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
}
该方法主要做了以下几件事:
1.根据builtInDisplayId通过SurfaceControl的getBuiltInDisplay()从SurfaceFlinger获取到对应的displayToken;
2.如果是合法的displayToken,则进行一系列获取设备信息操作,接下来创建对象时会用到;
3.从mDevices获取对应的LocalDisplayDevice,首次创建时不存在,会进行创建,然后加入mDevices进行管理;
4.执行sendDisplayDeviceEventLocked()进行通知设备创建;
接下来看一下LocalDisplayDevice类实现:
4.2.LocalDisplayDevice
private final class LocalDisplayDevice extends DisplayDevice {
private final int mBuiltInDisplayId;
private final Light mBacklight;
....................
private DisplayDeviceInfo mInfo;
......................
private SurfaceControl.PhysicalDisplayInfo mDisplayInfos[];
public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
int[] colorModes, int activeColorMode) {
super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId,
builtInDisplayId);
mBuiltInDisplayId = builtInDisplayId;
updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
colorModes, activeColorMode);
updateColorModesLocked(colorModes, activeColorMode);
if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
LightsManager lights = LocalServices.getService(LightsManager.class);
mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
} else {
mBacklight = null;
}
mHdrCapabilities = SurfaceControl.getHdrCapabilities(displayToken);
}
..................
..................
}
LocalDisplayDevice是LocalDisplayAdapter类的内部类,继承DisplayDevice,在构造方法内部,主要执行逻辑如下:
1.调用父类的构造方法,LocalDisplayDevice设备mUniqueId为:local:0、local:1等;
2.将上述获取的信息进行赋值,包括PhysicalDisplayInfo等;
3.获取本地服务LightsManager,然后获取LightService对象mBacklight,用来屏幕亮度调节;相关流程可参考Android 电源管理相关逻辑之PMS;
4.3.事件通知
上面讲到,在创建完DisplayDevice后,先加入mDevices进行管理,然后执行sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED)来进行通知下一步操作:
protected final void sendDisplayDeviceEventLocked(final DisplayDevice device, final int event) {
mHandler.post(new Runnable() {
@Override
public void run() {
mListener.onDisplayDeviceEvent(device, event);
}
});
}
public interface Listener {
public void onDisplayDeviceEvent(DisplayDevice device, int event);
public void onTraversalRequested();
}
最终会执行mListener的onDisplayDeviceEvent()方法,前面讲到在DMS内部创建LocalDisplayAdapter时,会传入DisplayAdapterLister实例,DisplayAdapterLister实现了DisplayAdapter内部的Listener接口:
private final class DisplayAdapterListener implements DisplayAdapter.Listener {
@Override
public void onDisplayDeviceEvent(DisplayDevice device, int event) {
switch (event) {
case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED:
handleDisplayDeviceAdded(device);
break;
...........
}
}
@Override
public void onTraversalRequested() {
synchronized (mSyncRoot) {
scheduleTraversalLocked(false);
}
}
}
当收到DISPLAY_DEVICE_EVENT_ADDED时,执行handleDisplayDeviceAdded(device),device是刚才新创建的LocalDisplayDevice;
private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (mDisplayDevices.contains(device)) {
Slog.w(TAG, "Attempted to add already added display device: " + info);
return;
}
Slog.i(TAG, "Display device added: " + info);
device.mDebugLastLoggedDeviceInfo = info;
mDisplayDevices.add(device);
LogicalDisplay display = addLogicalDisplayLocked(device);
Runnable work = updateDisplayStateLocked(device);
if (work != null) {
work.run();
}
scheduleTraversalLocked(false);
}
1.先通过getDisplayDeviceInfoLocked()来获取到DisplayDevice对应的DisplayDeviceInfo信息;
2.将新创建的设备加入到mDisplayDevices进行管理;
3.执行addLogicalDisplayLocked()创建DisplayDevice对应的LogicalDisplay;
4.执行updateDisplayStateLocked创建Runnable,来执行一下屏幕状态操作,比如:屏幕亮度;
5.执行scheduleTraversalLocked()来进行刷新,主要用来更新LayerStack到SurfaceFlinger中;
接下来看一下addLogicalDisplayLocked()来创建LogicalDisplay:
4.4.LogicalDisplay
private LogicalDisplay addLogicalDisplayLocked(DisplayDevice device) {
DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
boolean isDefault = (deviceInfo.flags
& DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0;
if (isDefault && mLogicalDisplays.get(Display.DEFAULT_DISPLAY) != null) {
Slog.w(TAG, "Ignoring attempt to add a second default display: " + deviceInfo);
isDefault = false;
}
......................
final int displayId = assignDisplayIdLocked(isDefault, device.getPhysicalId());
final int layerStack = assignLayerStackLocked(displayId);
LogicalDisplay display = new LogicalDisplay(displayId, layerStack, device);
display.updateLocked(mDisplayDevices);
......................
configureColorModeLocked(display, device);
if (isDefault) {
recordStableDisplayStatsIfNeededLocked(display);
}
mLogicalDisplays.put(displayId, display);
// Wake up waitForDefaultDisplay.
if (isDefault) {
mSyncRoot.notifyAll();
}
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);
return display;
}
在该方法内部可以看到,主要逻辑为:
1.通过assignDisplayIdLocked()来分配displayId,默认为0,1递增,如下所示;
private int assignDisplayIdLocked(boolean isDefault, int physicalId) {
if (physicalId >= SurfaceControl.BUILT_IN_DISPLAY_ID_EXT_MIN &&
physicalId <= SurfaceControl.BUILT_IN_DISPLAY_ID_EXT_MAX) {
return mNextBuiltInDisplayId++;
}
return assignDisplayIdLocked(isDefault);
}
2.通过assignLayerStackLocked()为displayId分配layerStack,跟displayId保持一致,layerStack与SurfaceFlinger里面屏幕内容显示是一一对应关系;
private int assignLayerStackLocked(int displayId) {
return displayId;
}
3.将displayId,layerStack,device作为参数来创建LogicalDisplay对象,创建的LocalDisplayDevice对象赋值为LogicalDisplay的mPrimaryDisplayDevice变量;
public LogicalDisplay(int displayId, int layerStack, DisplayDevice primaryDisplayDevice) {
mDisplayId = displayId;
mLayerStack = layerStack;
mPrimaryDisplayDevice = primaryDisplayDevice;
}
4.调用display.updateLocked(mDisplayDevices)来将DisplayDevice对应的设备信息DisplayDeviceInfo封装为LogicalDisplay对应的设备信息DisplayInfo;
5.将创建的LogicalDisplay存入mLogicalDisplays进行管理;
6.执行mSyncRoot.notifyAll()进行唤醒操作;
7.执行sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED)来发送设备添加通知;
4.5.总结
1.在DMS的onStart()方法内部发送消息来创建LocalDisplayAdapter,然后执行registerDisplayAdapterLocked(),继而执行LocalDisplayAdapter的registerLocked()方法;
2.在LocakDisplayAdapter()内部执行tryConnectDisplayLocked()来创建BUILT_IN_DISPLAY_IDS_TO_SCAN对应的LocalDisplayDevice,最后发送DISPLAY_DEVICE_EVENT_ADDED事件通知;
3.DMS内部收到回调通知,执行handleDisplayDeviceAdded()来根据DisplayDevice创建对应的LogicalDisplay;
5、VirtualDisplay创建流程及原理
VirtualDisplay对应虚拟Display,主要用来进行屏幕录制等相关功能,特别是现在在车载android设备上,物理屏幕越来越大,显示的需求越来越多,虚拟display的使用场景也越来越多;
5.1 创建VirtualDisplay实例
DisplayManager中的方法原型如下。后两个Hide的API,只有平台的应用才可以使用。
// frameworks/base/core/java/android/hardware/display/DisplayManager.java
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
}
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
@Nullable String uniqueId) {
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
}
补充一点,很多录屏的功能里使用到MediaProjection,MediaProjection中也提供了 createVirtualDisplay这个接口,实际上也是通过调用DisplayManager实现的功能。
// frameworks/base/media/java/android/media/projection/MediaProjection.java
public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
DisplayManager dm = mContext.getSystemService(DisplayManager.class);
// 调用DisplayManager的接口
return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler);
}
创建VirtualDisplay时,需要传入Surface。VirtualDisplay上要绘制的内容,实际是通过传入的Surface显示出来的。比如在主屏(根据物理屏,分配逻辑Display)上创建了一个SurfaceView,通过把这个SurfaceView传给VirtualDisplay。那么VirtualDisplay的 内容,实际上是在主屏的SurfaceView上显示的。下面是一段Android原生的例子。
// frameworks/base/packages/SystemUI/tests/src/com/android/systemui/navigationbar/NavigationBarButtonTest.java
private Display createVirtualDisplay() {
final String displayName = "NavVirtualDisplay";
final DisplayInfo displayInfo = new DisplayInfo();
mContext.getDisplay().getDisplayInfo(displayInfo);
final DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
// 创建ImageReader,通过它得到一张Surface
mReader = ImageReader.newInstance(displayInfo.logicalWidth,
displayInfo.logicalHeight, PixelFormat.RGBA_8888, 2);
assertNotNull("ImageReader must not be null", mReader);
// 创建虚拟屏,传入Surface。
mVirtualDisplay = displayManager.createVirtualDisplay(displayName, displayInfo.logicalWidth,
displayInfo.logicalHeight, displayInfo.logicalDensityDpi, mReader.getSurface(),
0 /*flags*/);
assertNotNull("virtual display must not be null", mVirtualDisplay);
waitForDisplayReady(mVirtualDisplay.getDisplay().getDisplayId());
return mVirtualDisplay.getDisplay();
}
上面的例子中创建虚拟屏,返回Display(实际上是VirtualDislay)对象。有了Display对象,我们就可以将View绑定到这个虚拟的Display上了(绑定网上方法比较多可自行搜索)。关于Surface的创建,有很多种方法,比如通过SurfaceControl+Buffer这种方式也可以。
VituralDisplay创建时,需要提供flag。其值定义如下,可通过 “或”将flag组合。
public static final int VIRTUAL_DISPLAY_FLAG_PUBLIC = 1 << 0;
public static final int VIRTUAL_DISPLAY_FLAG_PRESENTATION = 1 << 1;
public static final int VIRTUAL_DISPLAY_FLAG_SECURE = 1 << 2;
public static final int VIRTUAL_DISPLAY_FLAG_OWN_CONTENT_ONLY = 1 << 3;
public static final int VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR = 1 << 4;
public static final int VIRTUAL_DISPLAY_FLAG_CAN_SHOW_WITH_INSECURE_KEYGUARD = 1 << 5;
public static final int VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH = 1 << 6;
public static final int VIRTUAL_DISPLAY_FLAG_ROTATES_WITH_CONTENT = 1 << 7;
public static final int VIRTUAL_DISPLAY_FLAG_DESTROY_CONTENT_ON_REMOVAL = 1 << 8;
public static final int VIRTUAL_DISPLAY_FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS = 1 << 9;
public static final int VIRTUAL_DISPLAY_FLAG_TRUSTED = 1 << 10;
public static final int VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP = 1 << 11;
DisplayManager公开的接口中,有VirtualDisplay.Callback ,提供了其状态的回调。
public static abstract class Callback {
/**
* Called when the virtual display video projection has been
* paused by the system or when the surface has been detached
* by the application by calling setSurface(null).
* The surface will not receive any more buffers while paused.
*/
public void onPaused() { }
/**
* Called when the virtual display video projection has been
* resumed after having been paused.
*/
public void onResumed() { }
/**
* Called when the virtual display video projection has been
* stopped by the system. It will no longer receive frames
* and it will never be resumed. It is still the responsibility
* of the application to release() the virtual display.
*/
public void onStopped() { }
}
5.2 VirtualDisplay创建原理
关于VirtualDisplay的实现原理,主要从AndroidFramework角度进行分析。
// frameworks/base/core/java/android/hardware/display/DisplayManager.java
// /frameworks/base/core/java/android/hardware/display/DisplayManager.java
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags) {
return createVirtualDisplay(name, width, height, densityDpi, surface, flags, null, null);
}
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int densityDpi, @Nullable Surface surface, int flags,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(null /* projection */, builder.build(), callback, handler);
}
// TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull String name, int width, int height, int densityDpi, @Nullable Surface surface,
int flags, @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
@Nullable String uniqueId) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, densityDpi);
builder.setFlags(flags);
if (uniqueId != null) {
builder.setUniqueId(uniqueId);
}
if (surface != null) {
builder.setSurface(surface);
}
return createVirtualDisplay(projection, builder.build(), callback, handler);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
// 走的这里,会调用到DisplayManagerGlobal中。
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
handler);
}
DisplayManagerGlobal调用DMS(DisplayManagerService)服务创建虚拟屏,得到DMS返回的DisplayID后,通过DisplayID在Client端创建了VirtualDisplay对象。
// frameworks/base/core/java/android/hardware/display/DisplayManager.java
// /frameworks/base/core/java/android/hardware/display/DisplayManager.java
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
Handler handler) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
// 从MediaProjection过来的调用,这个地方非空。
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
try {
// 告知DMS创建虚拟屏,并返回DisplayID
displayId = mDm.createVirtualDisplay(virtualDisplayConfig, callbackWrapper,
projectionToken, context.getPackageName());
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (displayId < 0) {
Log.e(TAG, "Could not create virtual display: " + virtualDisplayConfig.getName());
return null;
}
// 通过DisplayID,取得Display对象信息(也是调用DMS得到的)
Display display = getRealDisplay(displayId);
if (display == null) {
Log.wtf(TAG, "Could not obtain display info for newly created "
+ "virtual display: " + virtualDisplayConfig.getName());
try {
// 创建失败,需要释放
mDm.releaseVirtualDisplay(callbackWrapper);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
return null;
}
// 创建VirtualDisplay
return new VirtualDisplay(this, display, callbackWrapper,
virtualDisplayConfig.getSurface());
}
DisplayManagerService(DMS)中创建DisplayDevice并添加到Device列表中管理;
// /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
@Override // Binder call
public int createVirtualDisplay(VirtualDisplayConfig virtualDisplayConfig,
IVirtualDisplayCallback callback, IMediaProjection projection, String packageName) {
... ...
// 拿到client端传过来的surface对象
final Surface surface = virtualDisplayConfig.getSurface();
int flags = virtualDisplayConfig.getFlags();
... ...
final long token = Binder.clearCallingIdentity();
try {
// 调用内部实现
return createVirtualDisplayInternal(callback, projection, callingUid, packageName,
surface, flags, virtualDisplayConfig);
} finally {
Binder.restoreCallingIdentity(token);
}
}
// /frameworks/base/services/core/java/com/android/server/display/DisplayManagerService.java
private int createVirtualDisplayInternal(IVirtualDisplayCallback callback,
IMediaProjection projection, int callingUid, String packageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
synchronized (mSyncRoot) {
... ...
// 为虚拟屏创建Device(告知surfaceflinger创建Display)
DisplayDevice device = mVirtualDisplayAdapter.createVirtualDisplayLocked(
callback, projection, callingUid, packageName, surface, flags,
virtualDisplayConfig);
if (device == null) {
return -1;
}
// 发送添加Device通知,这里比较重要
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
// 检查Display是否创建成功
final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
if (display != null) {
return display.getDisplayIdLocked();
}
// Something weird happened and the logical display was not created.
Slog.w(TAG, "Rejecting request to create virtual display "
+ "because the logical display was not created.");
mVirtualDisplayAdapter.releaseVirtualDisplayLocked(callback.asBinder());
mDisplayDeviceRepo.onDisplayDeviceEvent(device,
DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED);
}
return -1;
}
接下来DMS开始调用SurfaceFlinger的接口,创建Display。并将Display放入自身的List中管理。
// /frameworks/base/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
public DisplayDevice createVirtualDisplayLocked(IVirtualDisplayCallback callback,
IMediaProjection projection, int ownerUid, String ownerPackageName, Surface surface,
int flags, VirtualDisplayConfig virtualDisplayConfig) {
String name = virtualDisplayConfig.getName();
// VIRTUAL_DISPLAY_FLAG_SECURE 的用途,是判断是否为安全的Display,这个参数会告知SurfaceFlinger
boolean secure = (flags & VIRTUAL_DISPLAY_FLAG_SECURE) != 0;
IBinder appToken = callback.asBinder();
// 调用SurfaceFligner创建Display(Display的type是virtual)
IBinder displayToken = mSurfaceControlDisplayFactory.createDisplay(name, secure);
final String baseUniqueId =
UNIQUE_ID_PREFIX + ownerPackageName + "," + ownerUid + "," + name + ",";
final int uniqueIndex = getNextUniqueIndex(baseUniqueId);
String uniqueId = virtualDisplayConfig.getUniqueId();
if (uniqueId == null) {
uniqueId = baseUniqueId + uniqueIndex;
} else {
uniqueId = UNIQUE_ID_PREFIX + ownerPackageName + ":" + uniqueId;
}
// 通过SurfaceFligner返回的displayToken,创建Device对象
VirtualDisplayDevice device = new VirtualDisplayDevice(displayToken, appToken,
ownerUid, ownerPackageName, surface, flags, new Callback(callback, mHandler),
uniqueId, uniqueIndex, virtualDisplayConfig);
// 放到虚拟屏的List中管理。
mVirtualDisplayDevices.put(appToken, device);
try {
if (projection != null) {
projection.registerCallback(new MediaProjectionCallback(appToken));
}
appToken.linkToDeath(device, 0);
} catch (RemoteException ex) {
mVirtualDisplayDevices.remove(appToken);
device.destroyLocked(false);
return null;
}
// Return the display device without actually sending the event indicating
// that it was added. The caller will handle it.
return device;
}
// /frameworks/base/services/core/java/com/android/server/display/DisplayDeviceRepository.java
// mDisplayDeviceRepo.onDisplayDeviceEvent(device,
// DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED);
// 这段代码,会调用到下面的函数中。
private void handleDisplayDeviceAdded(DisplayDevice device) {
synchronized (mSyncRoot) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
... ...
device.mDebugLastLoggedDeviceInfo = info;
// 需要是将Device(就是上面创建的虚拟屏幕Device)放入到DMS的管理list
mDisplayDevices.add(device);
// 通知Device添加,会调用到LogicalDisplayMappe的handleDisplayDeviceAddedLocked中。
sendEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
}
}
// /frameworks/base/services/core/java/com/android/server/display/LogicalDisplayMapper.java
private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
// Internal Displays need to have additional initialization.
// This initializes a default dynamic display layout for INTERNAL
// devices, which is used as a fallback in case no static layout definitions
// exist or cannot be loaded.
if (deviceInfo.type == Display.TYPE_INTERNAL) {
initializeInternalDisplayDeviceLocked(device);
}
// Create a logical display for the new display device
LogicalDisplay display = createNewLogicalDisplayLocked(
device, Layout.assignDisplayIdLocked(false /*isDefault*/));
// 刷新布局和display配置
applyLayoutLocked();
updateLogicalDisplaysLocked();
}
虚拟屏幕的创建,Client端通过Surface告知的DisplayID,创建VirtualDisplay对象。通过DisplayID,与DMS打交道。DMS服务端,通过SurfaceFlinger创建虚拟屏,拿到SurfaceFligner的DisplayToken,然后通过它创建VirtualDisplayDevice + LogicalDisplay来管理虚拟屏幕。
5.3 应用显示上屏?
创建虚拟屏幕的时候,会传入了一张Surface(比如绑定主屏的一张Buffer)。虚拟屏通过这张Surface拿到Surface对应的Buffer,将上屏内容绘制到这个Buffer上,然后提交到画面流水线上(SurfaceFlinger)。通过SurfaceFlinger将这个这个Buffer最终由SurfaceFlinger描画并显示到Surface所在那张Display上(根据VirtualDisplay位置去显示。)
参照:
https://www.jianshu.com/p/c2058c2dca95
https://blog.csdn.net/zxc024000/article/details/133841331