DisplayManagerService知识分析

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信息。

DirectoryClass
frameworks/base/core/java/android/hardware/displayDisplayManager, DisplayMangaerGlobal, …
frameworks/base/core/java/android/viewDisplayInfo, DisplayViewport, …
frameworks/base/services/core/java/com/android/server/displayDMS,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

  • 24
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值