背景:
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方法中主要做了三件事:
- 初始化默认的DisplayDevice。
- 根据物理屏创建对应的逻辑屏。
- 应用默认的布局(该布局在步骤1中获取),然后进行逻辑屏与物理屏的绑定。
- 更新逻辑屏。 接下来我们一步步看。
初始化默认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中具体分析。