Android T 开机阶段逻辑屏的加载流程

1,342 阅读6分钟

背景:

Android从S版本开始,为了支持多屏设备,对Display相关的代码做了比较大的架构调整,添加了多个关键类来支持折叠屏和异型屏的功能,并且在T上对S上暴露出的一些问题做了调整,现在以T版本为例,对多屏设备逻辑屏的添加流程做一个梳理。

逻辑屏添加过程中的关键类:

DisplayManagerService: Display相关的核心服务,负责全局显示状态的更新,当Display状态发生变化是,向系统和应用发送通知。

LocalDisplayAdapter: 物理屏的适配器,负责发现和配置添加到系统的物理屏。

DisplayDeviceRepository:S上新增类,系统中所有物理屏的容器类,负责保存物理屏。

LogicalDisplayMapper:S上新增类,负责创建并关联物理屏,并响应设备的折叠状态变化对display做布局调整。

DevicestateToLayoutMap:S上新增类,负责保存设备状态到屏幕布局的映射,主要针对可折叠设备和多屏适配。

加载物理屏

DMS初始化在onStart阶段时,会向Display线程post一个消息注册默认的屏幕适配器LocalDisplayAdapter.

@Override
public void onStart() {
    mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);

    // If there was a runtime restart then we may have stale caches left around, so we need to
    // make sure to invalidate them upon every start.
    DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();

    publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
            true /*allowIsolated*/);
    publishLocalService(DisplayManagerInternal.class, new LocalService());
}

当执行该消息后会实例化一个LocalDisplayAdapter,并在DMS里对该LocalDisplayAdapter进行注册,之后会调用LocalDisplayAdapter的registerLocked方法进行物理屏的加载。

private void registerDefaultDisplayAdapters() {
    // Register default display adapters.
    synchronized (mSyncRoot) {
        // main display adapter
        registerDisplayAdapterLocked(new LocalDisplayAdapter(
                mSyncRoot, mContext, mHandler, mDisplayDeviceRepo));
    }
}

这里我们直接看registerLocked,此时会从SurfaceControl中获取物理屏的id,并尝试加载。

@Override
public void registerLocked() {
    super.registerLocked();

    mInjector.setDisplayEventListenerLocked(getHandler().getLooper(),
            new LocalDisplayEventListener());

    for (long physicalDisplayId : mSurfaceControlProxy.getPhysicalDisplayIds()) {
        tryConnectDisplayLocked(physicalDisplayId);
    }
}
private void tryConnectDisplayLocked(long physicalDisplayId) {
      ```
if (device == null) {
    // Display was added.
    final boolean isFirstDisplay = mDevices.size() == 0;
    device = new LocalDisplayDevice(displayToken, physicalDisplayId, staticInfo,
            dynamicInfo, modeSpecs, isFirstDisplay);
    mDevices.put(physicalDisplayId, device);
    sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
} else if (device.updateDisplayPropertiesLocked(staticInfo, dynamicInfo,
        modeSpecs)) {
    sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
```
}

以上方法中会根据物理屏的id从底层拿到物理屏的信息并创建物理屏信息的载体LocalDisplayDevice,然后执行sendDisplayDeviceEventLocked,告知对物理屏改变感兴趣的监听器,物理屏发生了变化。

// DisplayAdapter
protected final void sendDisplayDeviceEventLocked(
        final DisplayDevice device, final int event) {
    mHandler.post(() -> mListener.onDisplayDeviceEvent(device, event));
    // MIUI ADD:
    updateExternalDisplayStatus(device, event);
}

该方法中的mListener在实例化LocalDisplayAdapter时传入,但初始化是在DMS构造的的时候

// DisplayManagerService
DisplayManagerService(Context context, Injector injector) {
    mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
    mUiHandler = UiThread.getHandler();
    mDisplayDeviceRepo = new DisplayDeviceRepository(mSyncRoot, mPersistentDataStore);
    mLogicalDisplayMapper = new LogicalDisplayMapper(mContext, mDisplayDeviceRepo,
            new LogicalDisplayListener(), mSyncRoot, mHandler, new DeviceStateToLayoutMap());

从以上方法中我们能看到,mListener其实就是DisplayDeviceRepository,也就是说真正对物理屏感兴趣的是DisplayDeviceRepository,DisplayDeviceRepository实现了DisplayAdapter.Listener接口

// DisplayDeviceRepository
class DisplayDeviceRepository implements DisplayAdapter.Listener {

接下来我们看DisplayDeviceRepository的onDisplayDeviceEvent方法

// DisplayDeviceRepository
@Override
public void onDisplayDeviceEvent(DisplayDevice device, int event) {
    String tag = null;
    if (DEBUG) {
        tag = "DisplayDeviceRepository#onDisplayDeviceEvent (event=" + event + ")";
        Trace.beginAsyncSection(tag, 0);
    }
    switch (event) {
        case DISPLAY_DEVICE_EVENT_ADDED:
            handleDisplayDeviceAdded(device);
            break;

        case DISPLAY_DEVICE_EVENT_CHANGED:
            handleDisplayDeviceChanged(device);
            break;

        case DISPLAY_DEVICE_EVENT_REMOVED:
            handleDisplayDeviceRemoved(device);
            break;
    }
    if (DEBUG) {
        Trace.endAsyncSection(tag, 0);
    }
    
}

DisplayDeviceRepository会监听物理屏的添加,改变,和移除操作,并执行对应的回调方法,这里我们看handleDisplayDeviceAdded

// DisplayDeviceRepository
private void handleDisplayDeviceAdded(DisplayDevice device) {
    synchronized (mSyncRoot) {
        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);
        sendEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
        // MIUI ADD:
        disconnectWifiDisplayIfNeeded(device);
    }
}
```

DisplayDeviceRepository将新添加的物理屏保存在全局变量mDisplayDevices中,然后继续发送物理屏幕添加事件,我们看下sendEventLocked

// DisplayDeviceRepository
private void sendEventLocked(DisplayDevice device, int event) {
    final int size = mListeners.size();
    for (int i = 0; i < size; i++) {
        mListeners.get(i).onDisplayDeviceEventLocked(device, event);
    }
}
```

mListeners里保存了每一个向DisplayDeviceRepository注册过的监听器,目前来看,只有LogicalDisplayMapper在自身构造器里向DisplayDeviceRepository注册了监听,所以之后会走到LogicalDisplayMapper中进行逻辑屏的创建和与物理屏的绑定。

// LogicalDisplayMapper
LogicalDisplayMapper(@NonNull Context context, @NonNull DisplayDeviceRepository repo,
        @NonNull Listener listener, @NonNull DisplayManagerService.SyncRoot syncRoot,
        @NonNull Handler handler, @NonNull DeviceStateToLayoutMap deviceStateToLayoutMap) {

    mDisplayDeviceRepo.addListener(this);
}
```
// LogicalDisplayMapper
@Override
public void onDisplayDeviceEventLocked(DisplayDevice device, int event) {
    switch (event) {
        case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_ADDED:
            if (DEBUG) {
                Slog.d(TAG, "Display device added: " + device.getDisplayDeviceInfoLocked());
            }
            handleDisplayDeviceAddedLocked(device);
            break;

        case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_CHANGED:
            if (DEBUG) {
                Slog.d(TAG, "Display device changed: " + device.getDisplayDeviceInfoLocked());
            }
            finishStateTransitionLocked(false /*force*/);
            updateLogicalDisplaysLocked();
            break;

        case DisplayDeviceRepository.DISPLAY_DEVICE_EVENT_REMOVED:
            if (DEBUG) {
                Slog.d(TAG, "Display device removed: " + device.getDisplayDeviceInfoLocked());
            }
            handleDisplayDeviceRemovedLocked(device);
            updateLogicalDisplaysLocked();
            break;
    }
}
```

创建逻辑屏并绑定物理屏

// LogicalDisplayMapper
private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
    DisplayDeviceInfo deviceInfo = device.getDisplayDeviceInfoLocked();
    // The default Display needs to have additional initialization.
    // This initializes a default dynamic display layout for the default
    // device, which is used as a fallback in case no static layout definitions
    // exist or cannot be loaded.
    if ((deviceInfo.flags & DisplayDeviceInfo.FLAG_ALLOWED_TO_BE_DEFAULT_DISPLAY) != 0) {
        initializeDefaultDisplayDeviceLocked(device);
    }

    // Create a logical display for the new display device
    LogicalDisplay display = createNewLogicalDisplayLocked(
            device, Layout.assignDisplayIdLocked(false /*isDefault*/));

    applyLayoutLocked();
    updateLogicalDisplaysLocked();
}
```

在LogicalDisplayMapper的add方法中主要做了三件事:

  1. 初始化默认的DisplayDevice。
  2. 根据物理屏创建对应的逻辑屏。
  3. 应用默认的布局(该布局在步骤1中获取),然后进行逻辑屏与物理屏的绑定。
  4. 更新逻辑屏。 接下来我们一步步看。

初始化默认DisplayDevice并获取默认布局

// LogicalDisplayMapper
private void initializeDefaultDisplayDeviceLocked(DisplayDevice device) {
    // We always want to make sure that our default layout creates a logical
    // display for the default display device that is found.
    // To that end, when we are notified of a new default display, we add it to
    // the default layout definition if it is not already there.
    final Layout layout = mDeviceStateToLayoutMap.get(DeviceStateToLayoutMap.STATE_DEFAULT);
    if (layout.getById(DEFAULT_DISPLAY) != null) {
        // The layout should only have one default display
        return;
    }
    final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
    layout.createDisplayLocked(info.address, /* isDefault= */ true, /* isEnabled= */ true);
}
```

当系统尚未识别到设备当前的折叠展开状态时,此时没有一个默认的Layout是不行的,所以谷歌在初始阶段添加了一个默认的Layout,STATE_DEFAULT,id为-1.布局可以理解为当存在多个逻辑屏时,如何管理逻辑屏的点亮和熄灭。 默认布局当中是没有Display的,所以此时会根据传入的device,为layout创建一个Display,默认是enable状态。

创建逻辑屏

// LogicalDisplayMapper
private LogicalDisplay createNewLogicalDisplayLocked(DisplayDevice displayDevice,
        int displayId) {
    final int layerStack = assignLayerStackLocked(displayId);
    final LogicalDisplay display = new LogicalDisplay(displayId, layerStack, displayDevice);
    display.updateLocked(mDisplayDeviceRepo);
    mLogicalDisplays.put(displayId, display);
    setDisplayPhase(display, LogicalDisplay.DISPLAY_PHASE_ENABLED);
    return display;
}
```

这里会根据物理屏创建对应的逻辑屏,并将新创建的逻辑屏放在全局变量mLogicalDisplays当中。

应用默认布局

// LogicalDisplayMapper
private void applyLayoutLocked() {
    final Layout oldLayout = mCurrentLayout;
    // 获取默认布局
    mCurrentLayout = mDeviceStateToLayoutMap.get(mDeviceState);
    Slog.i(TAG, "Applying layout: " + mCurrentLayout + ", Previous layout: " + oldLayout);

    // Go through each of the displays in the current layout set.
    final int size = mCurrentLayout.size();
    for (int i = 0; i < size; i++) {
        // 拿到刚刚创建的Display
        final Layout.Display displayLayout = mCurrentLayout.getAt(i);

        // If the underlying display-device we want to use for this display
        // doesn't exist, then skip it. This can happen at startup as display-devices
        // trickle in one at a time. When the new display finally shows up, the layout is
        // recalculated so that the display is properly added to the current layout.
        // 根据display获取物理屏的地址,并拿到物理屏。
        final DisplayAddress address = displayLayout.getAddress();
        final DisplayDevice device = mDisplayDeviceRepo.getByAddressLocked(address);
        if (device == null) {
            Slog.w(TAG, "The display device (" + address + "), is not available"
                    + " for the display state " + mDeviceState);
            continue;
        }

        // Now that we have a display-device, we need a LogicalDisplay to map it to. Find the
        // right one, if it doesn't exist, create a new one.
        // 默认屏display的displayid为0,0此时没有对应逻辑屏,需要新建
        final int logicalDisplayId = displayLayout.getLogicalDisplayId();
        LogicalDisplay newDisplay =
                getDisplayLocked(logicalDisplayId, /* includeDisabled= */ true);
        if (newDisplay == null) {
            newDisplay = createNewLogicalDisplayLocked(
                    /* displayDevice= */ null, logicalDisplayId);
        }

        // Now swap the underlying display devices between the old display and the new display
        // 根据物理屏获得逻辑屏oldDisplay,该oldDisplay的displayid为2
        final LogicalDisplay oldDisplay = getDisplayLocked(device, /* includeDisabled= */ true);
        // 因为不相等,此时会做一次交换,将displayid为2的逻辑屏对应的物理屏绑定到displayid为0的逻辑屏上。
        if (newDisplay != oldDisplay) {
            newDisplay.swapDisplaysLocked(oldDisplay);
        }

        if (!displayLayout.isEnabled()) {
            setDisplayPhase(newDisplay, LogicalDisplay.DISPLAY_PHASE_DISABLED);
        }
    }

}
```

更新逻辑屏

该方法较长,主要逻辑是遍历逻辑屏列表,根据最新绑定的物理屏更新逻辑屏,并为逻辑屏添加displaygroup,这里主要关注add逻辑。

// LogicalDisplayMapper
private void updateLogicalDisplaysLocked() {
    // Go through all the displays and figure out if they need to be updated.
    // Loops in reverse so that displays can be removed during the loop without affecting the
    // rest of the loop.
    for (int i = mLogicalDisplays.size() - 1; i >= 0; i--) {
        final int displayId = mLogicalDisplays.keyAt(i);
        LogicalDisplay display = mLogicalDisplays.valueAt(i);

        mTempDisplayInfo.copyFrom(display.getDisplayInfoLocked());
        display.getNonOverrideDisplayInfoLocked(mTempNonOverrideDisplayInfo);

        display.updateLocked(mDisplayDeviceRepo);
        DisplayInfo newDisplayInfo = display.getDisplayInfoLocked();

        final int storedState = mUpdatedLogicalDisplays.get(displayId, UPDATE_STATE_NEW);
        final int updateState = storedState & UPDATE_STATE_MASK;
        final boolean isTransitioning = (storedState & UPDATE_STATE_FLAG_TRANSITION) != 0;
        final boolean wasPreviouslyUpdated = updateState == UPDATE_STATE_UPDATED;

        // The display is no longer valid and needs to be removed.
        if (!display.isValidLocked()) {
            mUpdatedLogicalDisplays.delete(displayId);

            // Remove from group
            final DisplayGroup displayGroup = getDisplayGroupLocked(
                    getDisplayGroupIdFromDisplayIdLocked(displayId));
            if (displayGroup != null) {
                displayGroup.removeDisplayLocked(display);
            }
            if (wasPreviouslyUpdated) {
                // The display isn't actually removed from our internal data structures until
                // after the notification is sent; see {@link #sendUpdatesForDisplaysLocked}.
                Slog.i(TAG, "Removing display: " + displayId);
                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
            } else {
                // This display never left this class, safe to remove without notification
                mLogicalDisplays.removeAt(i);
            }
            continue;

        // The display has been newly disabled, we report this as a removed display but
        // don't actually remove it from our internal list in LogicalDisplayMapper. The reason
        // is that LogicalDisplayMapper assumes and relies on the fact that every DisplayDevice
        // has a LogicalDisplay wrapper, but certain displays that are unusable (like the inner
        // display on a folded foldable device) are not available for use by the system and
        // we keep them hidden. To do this, we mark those LogicalDisplays as "disabled".
        // Also, if the display is in TRANSITION but was previously reported as disabled
        // then keep it unreported.
        } else if (!display.isEnabled()
                || (display.getPhase() == LogicalDisplay.DISPLAY_PHASE_LAYOUT_TRANSITION
                    && updateState == UPDATE_STATE_DISABLED)) {
            mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_DISABLED);

            // If we never told anyone about this display, nothing to do
            if (!wasPreviouslyUpdated) {
                continue;
            }

            // Remove from group
            final DisplayGroup displayGroup = getDisplayGroupLocked(
                    getDisplayGroupIdFromDisplayIdLocked(displayId));
            if (displayGroup != null) {
                displayGroup.removeDisplayLocked(display);
            }

            Slog.i(TAG, "Removing (disabled) display: " + displayId);
            mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_REMOVED);
            continue;

        // The display is new.
                    // 新逻辑屏,之前没有更新,做添加操作。
        } else if (!wasPreviouslyUpdated) {
            Slog.i(TAG, "Adding new display: " + displayId + ": " + newDisplayInfo);
            assignDisplayGroupLocked(display);
            mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_ADDED);

        // Underlying displays device has changed to a different one.
        } else if (!TextUtils.equals(mTempDisplayInfo.uniqueId, newDisplayInfo.uniqueId)) {
            // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
            assignDisplayGroupLocked(display);
            mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_SWAPPED);

        // Something about the display device has changed.
        } else if (!mTempDisplayInfo.equals(newDisplayInfo)) {
            // FLAG_OWN_DISPLAY_GROUP could have changed, recalculate just in case
            assignDisplayGroupLocked(display);
            mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);

        // The display is involved in a display layout transition
        } else if (isTransitioning) {
            mLogicalDisplaysToUpdate.put(displayId,
                    LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);

        // Display frame rate overrides changed.
        } else if (!display.getPendingFrameRateOverrideUids().isEmpty()) {
            mLogicalDisplaysToUpdate.put(
                    displayId, LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);

        // Non-override display values changed.
        } else {
            // While application shouldn't know nor care about the non-overridden info, we
            // still need to let WindowManager know so it can update its own internal state for
            // things like display cutouts.
            display.getNonOverrideDisplayInfoLocked(mTempDisplayInfo);
            if (!mTempNonOverrideDisplayInfo.equals(mTempDisplayInfo)) {
                mLogicalDisplaysToUpdate.put(displayId, LOGICAL_DISPLAY_EVENT_CHANGED);
            }
        }

        mUpdatedLogicalDisplays.put(displayId, UPDATE_STATE_UPDATED);
    }

    // Go through the groups and do the same thing. We do this after displays since group
    // information can change in the previous loop.
    // Loops in reverse so that groups can be removed during the loop without affecting the
    // rest of the loop.
    for (int i = mDisplayGroups.size() - 1; i >= 0; i--) {
        final int groupId = mDisplayGroups.keyAt(i);
        final DisplayGroup group = mDisplayGroups.valueAt(i);
        final boolean wasPreviouslyUpdated = mUpdatedDisplayGroups.indexOfKey(groupId) > -1;
        final int changeCount = group.getChangeCountLocked();

        if (group.isEmptyLocked()) {
            mUpdatedDisplayGroups.delete(groupId);
            if (wasPreviouslyUpdated) {
                mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_REMOVED);
            }
            continue;
        } else if (!wasPreviouslyUpdated) {
            mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_ADDED);
        } else if (mUpdatedDisplayGroups.get(groupId) != changeCount) {
            mDisplayGroupsToUpdate.put(groupId, DISPLAY_GROUP_EVENT_CHANGED);
        }
        mUpdatedDisplayGroups.put(groupId, changeCount);
    }

    // Send the display and display group updates in order by message type. This is important
    // to ensure that addition and removal notifications happen in the right order.
    sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_DEVICE_STATE_TRANSITION);
    sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_ADDED);
    sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_REMOVED);
    sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_CHANGED);
    sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_FRAME_RATE_OVERRIDES_CHANGED);
    sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_SWAPPED);
    sendUpdatesForDisplaysLocked(LOGICAL_DISPLAY_EVENT_ADDED);
    sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_CHANGED);
    sendUpdatesForGroupsLocked(DISPLAY_GROUP_EVENT_REMOVED);

    mLogicalDisplaysToUpdate.clear();
    mDisplayGroupsToUpdate.clear();
}
```
// LogicalDisplayMapper
private void sendUpdatesForDisplaysLocked(int msg) {
    for (int i = mLogicalDisplaysToUpdate.size() - 1; i >= 0; --i) {
        final int currMsg = mLogicalDisplaysToUpdate.valueAt(i);
        if (currMsg != msg) {
            continue;
        }

        final int id = mLogicalDisplaysToUpdate.keyAt(i);
        final LogicalDisplay display = getDisplayLocked(id, /* includeDisabled= */ true);
        if (DEBUG) {
            final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
            final String uniqueId = device == null ? "null" : device.getUniqueId();
            Slog.d(TAG, "Sending " + displayEventToString(msg) + " for display=" + id
                    + " with device=" + uniqueId);
        }
        mListener.onLogicalDisplayEventLocked(display, msg);
        if (msg == LOGICAL_DISPLAY_EVENT_REMOVED && !display.isValidLocked()) {
            // We wait until we sent the EVENT_REMOVED event before actually removing the
            // display.
            mLogicalDisplays.delete(id);
        }
    }
}
```

以上方法中会回调监听器的onLogicalDisplayEventLocked方法,DMS实现了该监听器,该mListener是在DMS实例化LogicalDisplayMapper的时候传入的,我们看下handleLogicalDisplayAddedLocked

// DMS
private void handleLogicalDisplayAddedLocked(LogicalDisplay display) {
    final DisplayDevice device = display.getPrimaryDisplayDeviceLocked();
    final int displayId = display.getDisplayIdLocked();
    final boolean isDefault = displayId == Display.DEFAULT_DISPLAY;
    configureColorModeLocked(display, device);
    if (!mAreUserDisabledHdrTypesAllowed) {
        display.setUserDisabledHdrTypes(mUserDisabledHdrTypes);
    }
    if (isDefault) {
        recordStableDisplayStatsIfNeededLocked(display);
        recordTopInsetLocked(display);
    }
    if (mUserPreferredMode != null) {
        device.setUserPreferredDisplayModeLocked(mUserPreferredMode);
    } else {
        configurePreferredDisplayModeLocked(display);
    }
    addDisplayPowerControllerLocked(display);

    mDisplayStates.append(displayId, Display.STATE_UNKNOWN);

    final float brightnessDefault = display.getDisplayInfoLocked().brightnessDefault;
    mDisplayBrightnesses.append(displayId,
            new BrightnessPair(brightnessDefault, brightnessDefault));

    DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();

    // Wake up waitForDefaultDisplay.
    if (isDefault) {
        mSyncRoot.notifyAll();
    }

    sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_ADDED);

    Runnable work = updateDisplayStateLocked(device);
    if (work != null) {
        work.run();
    }
    scheduleTraversalLocked(false);
}
```

以上方法主要是为新添加的逻辑屏创建DisplayPowerController,从Android 开始,每一个逻辑屏都对应一个自己的dpc,这样可以确保可以独立控制每个屏幕的亮度和显示状态.

更新亮度和display状态

此时,逻辑屏已经更新完毕,当系统启动阶段走到PHASE_SYSTEM_SERVICES_READY时,代表核心系统服务已经全部加载完毕,此时会回调PowerManagerService的onBootPhase方法执行更新电源状态去更新亮度display状态。

// PowerManagerService
@Override
public void onBootPhase(int phase) {
    if (phase == PHASE_SYSTEM_SERVICES_READY) {
        systemReady();
```

```
private void systemReady() {
      updatePowerStateLocked();
}

然后PowerManagerService会一路回调到DisplayPowerController,在其核心方法updatePowerState中进行亮度和state的更新。

针对折叠屏而言,开机阶段两块屏都会执行上述操作,这样两块屏就完成了加载和显示的任务。 之后当折叠屏的铰链sensor或lid_swtich上报当前设备的折叠展开状态后,就又会开始布局和每个Display的更新,我们在下一篇wiki中具体分析。