diff options
| author | 2025-02-24 23:53:06 +0000 | |
|---|---|---|
| committer | 2025-03-07 21:28:36 +0000 | |
| commit | 74127c07efd71aed94f2a79cfe07fa2b55a0a6a5 (patch) | |
| tree | 72f19ae5a1ba447adc77e3484930d503bce93823 | |
| parent | 22067462fc35fab2822bcd7adbbf7e72c55ff3a7 (diff) | |
Update rejected modes votes only if the display is registered
If an initial display config fails soon after hotplug,
There could be a race condition to update the rejected modes
vote for a display and display being registered.
So fix that by updating the votes by using onDisplayAdded()
and onModeRejected() callbacks.
Bug: 393132034
Test: manual, induce config failure in DRM HWC and test that the
ModeChangeObserver updates the rejected modes votes
Flag: com.android.graphics.surfaceflinger.flags.display_config_error_hal
Change-Id: Icb2ab24567eeca740ab1e997e5e9dcd818b14ed9
Signed-off-by: Manasi Navare <navaremanasi@google.com>
| -rw-r--r-- | services/core/java/com/android/server/display/mode/ModeChangeObserver.java | 128 |
1 files changed, 93 insertions, 35 deletions
diff --git a/services/core/java/com/android/server/display/mode/ModeChangeObserver.java b/services/core/java/com/android/server/display/mode/ModeChangeObserver.java index 2751835f9958..50782a2f22c8 100644 --- a/services/core/java/com/android/server/display/mode/ModeChangeObserver.java +++ b/services/core/java/com/android/server/display/mode/ModeChangeObserver.java @@ -16,9 +16,11 @@ package com.android.server.display.mode; +import android.hardware.display.DisplayManager; +import android.os.Handler; import android.os.Looper; +import android.util.LongSparseArray; import android.util.Slog; -import android.util.SparseArray; import android.view.Display; import android.view.DisplayAddress; import android.view.DisplayEventReceiver; @@ -34,72 +36,128 @@ final class ModeChangeObserver { @SuppressWarnings("unused") private DisplayEventReceiver mModeChangeListener; - private final SparseArray<Set<Integer>> mRejectedModesByDisplay = new SparseArray<>(); - private Looper mLooper; + private DisplayManager.DisplayListener mDisplayListener; + private final LongSparseArray<Set<Integer>> mRejectedModesMap = + new LongSparseArray<>(); + private final LongSparseArray<Integer> mPhysicalIdToLogicalIdMap = new LongSparseArray<>(); + private final Looper mLooper; + private final Handler mHandler; + /** + * Observer for display mode changes. + * This class observes display mode rejections and updates the vote storage + * for rejected modes vote accordingly. + */ ModeChangeObserver(VotesStorage votesStorage, DisplayModeDirector.Injector injector, Looper looper) { mVotesStorage = votesStorage; mInjector = injector; mLooper = looper; + mHandler = new Handler(mLooper); } + /** + * Start observing display mode changes. + */ void observe() { - mModeChangeListener = new DisplayEventReceiver(mLooper) { + updatePhysicalIdToLogicalIdMap(); + mDisplayListener = new DisplayManager.DisplayListener() { @Override - public void onModeRejected(long physicalDisplayId, int modeId) { - Slog.d(TAG, "Mode Rejected event received"); - int displayId = getLogicalDisplayId(physicalDisplayId); - if (displayId < 0) { - Slog.e(TAG, "Logical Display Id not found"); + public void onDisplayAdded(int displayId) { + updateVoteForDisplay(displayId); + } + + @Override + public void onDisplayRemoved(int displayId) { + int oldPhysicalDisplayIdIndex = mPhysicalIdToLogicalIdMap.indexOfValue(displayId); + if (oldPhysicalDisplayIdIndex < 0) { + Slog.e(TAG, "Removed display not found"); return; } - populateRejectedModesListByDisplay(displayId, modeId); + long oldPhysicalDisplayId = + mPhysicalIdToLogicalIdMap.keyAt(oldPhysicalDisplayIdIndex); + mPhysicalIdToLogicalIdMap.delete(oldPhysicalDisplayId); + mRejectedModesMap.delete(oldPhysicalDisplayId); + mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, null); } @Override - public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) { - Slog.d(TAG, "Hotplug event received"); - if (!connected) { - int displayId = getLogicalDisplayId(physicalDisplayId); - if (displayId < 0) { - Slog.e(TAG, "Logical Display Id not found"); - return; - } - clearRejectedModesListByDisplay(displayId); + public void onDisplayChanged(int displayId) { + int oldPhysicalDisplayIdIndex = mPhysicalIdToLogicalIdMap.indexOfValue(displayId); + if (oldPhysicalDisplayIdIndex < 0) { + Slog.e(TAG, "Changed display not found"); + return; + } + long oldPhysicalDisplayId = + mPhysicalIdToLogicalIdMap.keyAt(oldPhysicalDisplayIdIndex); + mPhysicalIdToLogicalIdMap.delete(oldPhysicalDisplayId); + + updateVoteForDisplay(displayId); + } + }; + mInjector.registerDisplayListener(mDisplayListener, mHandler, + DisplayManager.EVENT_TYPE_DISPLAY_ADDED + | DisplayManager.EVENT_TYPE_DISPLAY_CHANGED + | DisplayManager.EVENT_TYPE_DISPLAY_REMOVED); + mModeChangeListener = new DisplayEventReceiver(mLooper) { + @Override + public void onModeRejected(long physicalDisplayId, int modeId) { + Slog.d(TAG, "Mode Rejected event received"); + updateRejectedModesListByDisplay(physicalDisplayId, modeId); + if (mPhysicalIdToLogicalIdMap.indexOfKey(physicalDisplayId) < 0) { + Slog.d(TAG, "Rejected Modes Vote will be updated after display is added"); + return; } + mVotesStorage.updateVote(mPhysicalIdToLogicalIdMap.get(physicalDisplayId), + Vote.PRIORITY_REJECTED_MODES, + Vote.forRejectedModes(mRejectedModesMap.get(physicalDisplayId))); } }; } - private int getLogicalDisplayId(long rejectedModePhysicalDisplayId) { + private void updateVoteForDisplay(int displayId) { + Display display = mInjector.getDisplay(displayId); + if (display == null) { + // We can occasionally get a display added or changed event for a display that was + // subsequently removed, which means this returns null. Check this case and bail + // out early; if it gets re-attached we will eventually get another call back for it. + Slog.e(TAG, "Added or Changed display has disappeared"); + return; + } + DisplayAddress address = display.getAddress(); + if (address instanceof DisplayAddress.Physical physical) { + long physicalDisplayId = physical.getPhysicalDisplayId(); + mPhysicalIdToLogicalIdMap.put(physicalDisplayId, displayId); + Set<Integer> modes = mRejectedModesMap.get(physicalDisplayId); + mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, + modes != null ? Vote.forRejectedModes(modes) : null); + } + } + + private void updatePhysicalIdToLogicalIdMap() { Display[] displays = mInjector.getDisplays(); for (Display display : displays) { + if (display == null) { + continue; + } DisplayAddress address = display.getAddress(); if (address instanceof DisplayAddress.Physical physical) { - long physicalDisplayId = physical.getPhysicalDisplayId(); - if (physicalDisplayId == rejectedModePhysicalDisplayId) { - return display.getDisplayId(); - } + mPhysicalIdToLogicalIdMap.put(physical.getPhysicalDisplayId(), + display.getDisplayId()); } } - return -1; } - private void populateRejectedModesListByDisplay(int displayId, int rejectedModeId) { - Set<Integer> alreadyRejectedModes = mRejectedModesByDisplay.get(displayId); + private void updateRejectedModesListByDisplay(long rejectedModePhysicalDisplayId, + int rejectedModeId) { + Set<Integer> alreadyRejectedModes = + mRejectedModesMap.get(rejectedModePhysicalDisplayId); if (alreadyRejectedModes == null) { alreadyRejectedModes = new HashSet<>(); - mRejectedModesByDisplay.put(displayId, alreadyRejectedModes); + mRejectedModesMap.put(rejectedModePhysicalDisplayId, + alreadyRejectedModes); } alreadyRejectedModes.add(rejectedModeId); - mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, - Vote.forRejectedModes(alreadyRejectedModes)); - } - - private void clearRejectedModesListByDisplay(int displayId) { - mRejectedModesByDisplay.remove(displayId); - mVotesStorage.updateVote(displayId, Vote.PRIORITY_REJECTED_MODES, null); } } |