Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 19862ada authored by Danae Savvidi's avatar Danae Savvidi
Browse files

Update caching in DisplayInfoProxy.

To include what DisplayInfoGroups changed and the source of the change.

Bug: 435146856
Bug: 431149632
Flag: com.android.server.display.feature.flags.enable_logging_for_display_events
Test: atest DisplayManagerServiceTest
Test: atest DisplayInfoTest
Test: atest LogicalDisplayTest
Change-Id: Ia3e60b989422a21d4e6ae6f68ea562f8212d6b89
parent abf969a4
Loading
Loading
Loading
Loading
+12 −0
Original line number Original line Diff line number Diff line
@@ -927,9 +927,21 @@ public final class DisplayInfo implements Parcelable {
        compatInfo.applyDisplayMetricsIfNeeded(outMetrics, applyToSize);
        compatInfo.applyDisplayMetricsIfNeeded(outMetrics, applyToSize);
    }
    }


    /**
     * The source of a change in the display info object.
     */
    public enum DisplayInfoChangeSource {
        DISPLAY_SWAP,
        DISPLAY_MANAGER,
        WINDOW_MANAGER,
        OTHER
    }

    /**
    /**
     * Groups of related fields within a {@link DisplayInfo} object.
     * Groups of related fields within a {@link DisplayInfo} object.
     * Used to categorize changes between two instances.
     * Used to categorize changes between two instances.
     * Any changes to which fields belong to which groups need to update:
     * {@link com.android.server.wm.utils.DisplayInfoOverrides#WM_OVERRIDE_GROUPS}.
     */
     */
    public enum DisplayInfoGroup {
    public enum DisplayInfoGroup {
        /** Basic properties like IDs, flags, type, and ownership. */
        /** Basic properties like IDs, flags, type, and ownership. */
+68 −8
Original line number Original line Diff line number Diff line
@@ -16,29 +16,79 @@


package com.android.server.display;
package com.android.server.display;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.hardware.display.DisplayManagerGlobal;
import android.hardware.display.DisplayManagerGlobal;
import android.view.DisplayInfo;
import android.view.DisplayInfo;


import androidx.annotation.IntRange;

/**
/**
 * Class for wrapping access of DisplayInfo objects by LogicalDisplay so that we can appropriately
 * A proxy class for {@link DisplayInfo} objects.
 * invalidate caches when they change.
 * This class wraps access to {@link DisplayInfo} objects by {@link LogicalDisplay} to allow
 * invalidating caches when the display information changes.
 */
 */
public class DisplayInfoProxy {
public class DisplayInfoProxy {
    private DisplayInfo mInfo;
    private DisplayInfo mInfo;


    /**
     * The bitmask of {@link DisplayInfo} groups that have changed in the last update.
     * Related to {@link DisplayInfo#getBasicChangedGroups(DisplayInfo)}.
     */
    private int mDisplayInfoGroupsChanged = 0;

    /** The source of the last {@link DisplayInfo} change. */
    private DisplayInfo.DisplayInfoChangeSource mDisplayInfoChangeSource;

    public DisplayInfoProxy(@Nullable DisplayInfo info) {
    public DisplayInfoProxy(@Nullable DisplayInfo info) {
        mInfo = info;
        mInfo = info;
    }
    }


    /**
    /**
     * Set the current {@link DisplayInfo}.
     * Sets the current {@link DisplayInfo} and invalidates system-wide caches. This method does
     * not track changes or the source of changes, and should only be used if these are recorded
     * elsewhere. To update the cache when something has triggered a change in
     * the {@link DisplayInfo} object use {@link #set(int, DisplayInfo.DisplayInfoChangeSource)}
     * or {@link #set(DisplayInfo, DisplayInfo, DisplayInfo.DisplayInfoChangeSource)}.
     *
     *
     * The also automatically invalidates the display info caches across the entire system.
     * @param newInfo The new {@link DisplayInfo} to apply. Must not be null.
     * @param info the new {@link DisplayInfo}.
     */
     */
    public void set(@Nullable DisplayInfo info) {
    public void set(@NonNull DisplayInfo newInfo) {
        mInfo = info;
        mInfo = newInfo;
        DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
    }

    /**
     * Invalidates the current display information by computing the differences between an old and
     * new state, and then setting the new state.
     *
     * @param oldInfo The previous {@link DisplayInfo} state. Must not be null.
     * @param newInfo The new {@link DisplayInfo} state. Must not be null. If it is null,
     *                use the other updateCache method with all groups marked as changed.
     * @param source The source of the change.
     */
    public void set(@NonNull DisplayInfo oldInfo, @NonNull DisplayInfo newInfo,
            DisplayInfo.DisplayInfoChangeSource source) {
        mDisplayInfoGroupsChanged = oldInfo.getBasicChangedGroups(newInfo);
        mDisplayInfoChangeSource = source;
        set(newInfo);
    }

    /**
     * Invalidates the current display information using a pre-computed set of changed groups.
     *
     * This is an optimization for targeted updates where re-computing the full
     * {@link DisplayInfo} is unnecessary.
     *
     * @param changedGroups A positive integer bitmask representing the {@link DisplayInfo} groups
     *                      that have changed.
     * @param source The source of the change.
     */
    public void set(@IntRange(from = 1) int changedGroups,
            DisplayInfo.DisplayInfoChangeSource source) {
        mDisplayInfoGroupsChanged = changedGroups;
        mDisplayInfoChangeSource = source;
        mInfo = null;
        DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
        DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
    }
    }


@@ -54,4 +104,14 @@ public class DisplayInfoProxy {
    public DisplayInfo get() {
    public DisplayInfo get() {
        return mInfo;
        return mInfo;
    }
    }

    /** Gets the display info groups that have changed. */
    public int getDisplayInfoGroupsChanged() {
        return mDisplayInfoGroupsChanged;
    }

    /** Gets the source of the last update. */
    public DisplayInfo.DisplayInfoChangeSource getDisplayInfoChangeSource() {
        return mDisplayInfoChangeSource;
    }
}
}
 No newline at end of file
+46 −13
Original line number Original line Diff line number Diff line
@@ -21,6 +21,8 @@ import static android.view.Display.Mode.INVALID_MODE_ID;
import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
import static com.android.server.display.DisplayDeviceInfo.TOUCH_NONE;
import static com.android.server.display.layout.Layout.Display.POSITION_REAR;
import static com.android.server.display.layout.Layout.Display.POSITION_REAR;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_GROUPS;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_GROUPS_ENUMSET;
import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;
import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;


import android.annotation.NonNull;
import android.annotation.NonNull;
@@ -294,12 +296,31 @@ final class LogicalDisplay {
     */
     */
    public DisplayInfo getDisplayInfoLocked() {
    public DisplayInfo getDisplayInfoLocked() {
        if (mInfo.get() == null) {
        if (mInfo.get() == null) {
            // We do not want to update displayInfoGroupsChanged
            // as no change has triggered this call
            mInfo.set(computeCurrentDisplayInfoLocked());
        }
        return mInfo.get();
    }

    /**
     * Computes the current display information based on the base and override info.
     *
     * Warning: this does not update the cache.
     */
    private DisplayInfo computeCurrentDisplayInfoLocked() {
        DisplayInfo info = new DisplayInfo();
        DisplayInfo info = new DisplayInfo();
        copyDisplayInfoFields(info, mBaseDisplayInfo, mOverrideDisplayInfo,
        copyDisplayInfoFields(info, mBaseDisplayInfo, mOverrideDisplayInfo,
                WM_OVERRIDE_FIELDS);
                WM_OVERRIDE_FIELDS);
            mInfo.set(info);
        return info;
    }
    }
        return mInfo.get();

    public int getDisplayInfoGroupsChangedLocked() {
        return mInfo.getDisplayInfoGroupsChanged();
    }

    public DisplayInfo.DisplayInfoChangeSource getDisplayInfoChangeSource() {
        return mInfo.getDisplayInfoChangeSource();
    }
    }


    /**
    /**
@@ -341,16 +362,20 @@ final class LogicalDisplay {
        if (info != null) {
        if (info != null) {
            if (mOverrideDisplayInfo == null) {
            if (mOverrideDisplayInfo == null) {
                mOverrideDisplayInfo = new DisplayInfo(info);
                mOverrideDisplayInfo = new DisplayInfo(info);
                mInfo.set(null);
                mInfo.set(WM_OVERRIDE_GROUPS, DisplayInfo.DisplayInfoChangeSource.WINDOW_MANAGER);
                return true;
                return true;
            } else if (!mOverrideDisplayInfo.equals(info)) {
            }

            int groupsChanged = info.getBasicChangedGroups(mOverrideDisplayInfo,
                    WM_OVERRIDE_GROUPS_ENUMSET);
            if (groupsChanged != 0) {
                mOverrideDisplayInfo.copyFrom(info);
                mOverrideDisplayInfo.copyFrom(info);
                mInfo.set(null);
                mInfo.set(groupsChanged, DisplayInfo.DisplayInfoChangeSource.WINDOW_MANAGER);
                return true;
                return true;
            }
            }
        } else if (mOverrideDisplayInfo != null) {
        } else if (mOverrideDisplayInfo != null) {
            mOverrideDisplayInfo = null;
            mOverrideDisplayInfo = null;
            mInfo.set(null);
            mInfo.set(WM_OVERRIDE_GROUPS, DisplayInfo.DisplayInfoChangeSource.WINDOW_MANAGER);
            return true;
            return true;
        }
        }
        return false;
        return false;
@@ -440,6 +465,8 @@ final class LogicalDisplay {
        DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked();
        DisplayDeviceInfo deviceInfo = mPrimaryDisplayDevice.getDisplayDeviceInfoLocked();
        DisplayDeviceConfig config = mPrimaryDisplayDevice.getDisplayDeviceConfig();
        DisplayDeviceConfig config = mPrimaryDisplayDevice.getDisplayDeviceConfig();
        if (!Objects.equals(mPrimaryDisplayDeviceInfo, deviceInfo) || mDirty) {
        if (!Objects.equals(mPrimaryDisplayDeviceInfo, deviceInfo) || mDirty) {
            DisplayInfo oldDisplayInfo = getDisplayInfoLocked();

            mBaseDisplayInfo.layerStack = mLayerStack;
            mBaseDisplayInfo.layerStack = mLayerStack;
            mBaseDisplayInfo.flags = 0;
            mBaseDisplayInfo.flags = 0;
            // Displays default to moving content to the primary display when removed
            // Displays default to moving content to the primary display when removed
@@ -605,7 +632,8 @@ final class LogicalDisplay {
            mBaseDisplayInfo.canHostTasks = mCanHostTasks;
            mBaseDisplayInfo.canHostTasks = mCanHostTasks;


            mPrimaryDisplayDeviceInfo = deviceInfo;
            mPrimaryDisplayDeviceInfo = deviceInfo;
            mInfo.set(null);
            mInfo.set(oldDisplayInfo, computeCurrentDisplayInfoLocked(),
                    DisplayInfo.DisplayInfoChangeSource.DISPLAY_MANAGER);
            mDirty = false;
            mDirty = false;
        }
        }
    }
    }
@@ -992,7 +1020,8 @@ final class LogicalDisplay {
        if (mUserDisabledHdrTypes != userDisabledHdrTypes) {
        if (mUserDisabledHdrTypes != userDisabledHdrTypes) {
            mUserDisabledHdrTypes = userDisabledHdrTypes;
            mUserDisabledHdrTypes = userDisabledHdrTypes;
            mBaseDisplayInfo.userDisabledHdrTypes = userDisabledHdrTypes;
            mBaseDisplayInfo.userDisabledHdrTypes = userDisabledHdrTypes;
            mInfo.set(null);
            mInfo.set(DisplayInfo.DisplayInfoGroup.COLOR_AND_BRIGHTNESS.getMask(),
                    DisplayInfo.DisplayInfoChangeSource.OTHER);
        }
        }
    }
    }


@@ -1013,7 +1042,8 @@ final class LogicalDisplay {
        boolean handleLogicalDisplayChangedLocked = false;
        boolean handleLogicalDisplayChangedLocked = false;
        if (isTargetDisplayType && mBaseDisplayInfo.isForceSdr != isForceSdr) {
        if (isTargetDisplayType && mBaseDisplayInfo.isForceSdr != isForceSdr) {
            mBaseDisplayInfo.isForceSdr = isForceSdr;
            mBaseDisplayInfo.isForceSdr = isForceSdr;
            mInfo.set(null);
            mInfo.set(DisplayInfo.DisplayInfoGroup.COLOR_AND_BRIGHTNESS.getMask(),
                    DisplayInfo.DisplayInfoChangeSource.OTHER);
            handleLogicalDisplayChangedLocked = true;
            handleLogicalDisplayChangedLocked = true;
        }
        }
        return handleLogicalDisplayChangedLocked;
        return handleLogicalDisplayChangedLocked;
@@ -1039,7 +1069,8 @@ final class LogicalDisplay {
        Slog.i(TAG, "Set canHostTasks for display " + displayId + ": " + canHostTasks);
        Slog.i(TAG, "Set canHostTasks for display " + displayId + ": " + canHostTasks);
        mCanHostTasks = canHostTasks;
        mCanHostTasks = canHostTasks;
        mBaseDisplayInfo.canHostTasks = canHostTasks;
        mBaseDisplayInfo.canHostTasks = canHostTasks;
        mInfo.set(null);
        mInfo.set(DisplayInfo.DisplayInfoGroup.BASIC_PROPERTIES.getMask(),
                DisplayInfo.DisplayInfoChangeSource.OTHER);
        return true;
        return true;
    }
    }


@@ -1110,13 +1141,15 @@ final class LogicalDisplay {
     * @return The previously set display device.
     * @return The previously set display device.
     */
     */
    public DisplayDevice setPrimaryDisplayDeviceLocked(@Nullable DisplayDevice device) {
    public DisplayDevice setPrimaryDisplayDeviceLocked(@Nullable DisplayDevice device) {
        DisplayInfo oldDisplayInfo = getDisplayInfoLocked();
        final DisplayDevice old = mPrimaryDisplayDevice;
        final DisplayDevice old = mPrimaryDisplayDevice;
        mPrimaryDisplayDevice = device;
        mPrimaryDisplayDevice = device;


        // Reset all our display info data
        // Reset all our display info data
        mPrimaryDisplayDeviceInfo = null;
        mPrimaryDisplayDeviceInfo = null;
        mBaseDisplayInfo.copyFrom(EMPTY_DISPLAY_INFO);
        mBaseDisplayInfo.copyFrom(EMPTY_DISPLAY_INFO);
        mInfo.set(null);
        mInfo.set(oldDisplayInfo, computeCurrentDisplayInfoLocked(),
                DisplayInfo.DisplayInfoChangeSource.DISPLAY_SWAP);


        // Since mCanHostTasks depends on mPrimaryDisplayDevice, we should refresh mCanHostTasks
        // Since mCanHostTasks depends on mPrimaryDisplayDevice, we should refresh mCanHostTasks
        // when mPrimaryDisplayDevice changes.
        // when mPrimaryDisplayDevice changes.
+21 −1
Original line number Original line Diff line number Diff line
@@ -20,6 +20,8 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.view.DisplayInfo;
import android.view.DisplayInfo;


import java.util.EnumSet;

/**
/**
 * Helper class to copy only subset of fields of DisplayInfo object or to perform
 * Helper class to copy only subset of fields of DisplayInfo object or to perform
 * comparison operation between DisplayInfo objects only with a subset of fields.
 * comparison operation between DisplayInfo objects only with a subset of fields.
@@ -28,7 +30,7 @@ public class DisplayInfoOverrides {


    /**
    /**
     * Set of DisplayInfo fields that are overridden in DisplayManager using values from
     * Set of DisplayInfo fields that are overridden in DisplayManager using values from
     * WindowManager
     * WindowManager. Any changes to the fields in here need to update {@link #WM_OVERRIDE_GROUPS}.
     */
     */
    public static final DisplayInfoFieldsUpdater WM_OVERRIDE_FIELDS = (out, source) -> {
    public static final DisplayInfoFieldsUpdater WM_OVERRIDE_FIELDS = (out, source) -> {
        out.appWidth = source.appWidth;
        out.appWidth = source.appWidth;
@@ -48,6 +50,24 @@ public class DisplayInfoOverrides {
        out.displayShape = source.displayShape;
        out.displayShape = source.displayShape;
    };
    };


    /**
     * A bitmask of all {@link DisplayInfo.DisplayInfoGroup}s that can be affected by
     * {@link #WM_OVERRIDE_FIELDS}. Must be in sync with {@link #WM_OVERRIDE_FIELDS}
     * and {@link #WM_OVERRIDE_GROUPS_ENUMSET}.
     */
    public static final int WM_OVERRIDE_GROUPS =
            DisplayInfo.DisplayInfoGroup.ORIENTATION_AND_ROTATION.getMask()
                    | DisplayInfo.DisplayInfoGroup.DIMENSIONS_AND_SHAPES.getMask();

    /**
     * Same as {@link #WM_OVERRIDE_GROUPS}, but as an EnumSet.
     * This is used to optimize part of the code
     * in {@link LogicalDisplay#setDisplayInfoOverrideFromWindowManagerLocked}.
     */
    public static final EnumSet<DisplayInfo.DisplayInfoGroup> WM_OVERRIDE_GROUPS_ENUMSET =
            EnumSet.of(DisplayInfo.DisplayInfoGroup.ORIENTATION_AND_ROTATION,
                    DisplayInfo.DisplayInfoGroup.DIMENSIONS_AND_SHAPES);

    /**
    /**
     * Gets {@param base} DisplayInfo, overrides WindowManager-specific overrides using
     * Gets {@param base} DisplayInfo, overrides WindowManager-specific overrides using
     * {@param override} and writes the result to {@param out}
     * {@param override} and writes the result to {@param out}
+71 −0
Original line number Original line Diff line number Diff line
@@ -24,6 +24,9 @@ import static com.android.server.wm.DeferredDisplayUpdater.DEFERRABLE_FIELDS;
import static com.android.server.wm.DeferredDisplayUpdater.DIFF_NOT_WM_DEFERRABLE;
import static com.android.server.wm.DeferredDisplayUpdater.DIFF_NOT_WM_DEFERRABLE;
import static com.android.server.wm.DeferredDisplayUpdater.DIFF_WM_DEFERRABLE;
import static com.android.server.wm.DeferredDisplayUpdater.DIFF_WM_DEFERRABLE;
import static com.android.server.wm.DeferredDisplayUpdater.calculateDisplayInfoDiff;
import static com.android.server.wm.DeferredDisplayUpdater.calculateDisplayInfoDiff;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_FIELDS;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_GROUPS;
import static com.android.server.wm.utils.DisplayInfoOverrides.WM_OVERRIDE_GROUPS_ENUMSET;
import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;
import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;


import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.Truth.assertWithMessage;
@@ -46,6 +49,7 @@ import android.view.SurfaceControl.RefreshRateRange;


import androidx.test.filters.SmallTest;
import androidx.test.filters.SmallTest;


import org.junit.Assert;
import org.junit.Test;
import org.junit.Test;


import java.lang.reflect.Field;
import java.lang.reflect.Field;
@@ -53,6 +57,7 @@ import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.Arrays;
import java.util.HashSet;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Consumer;


@@ -113,6 +118,72 @@ public class DeferredDisplayUpdaterDiffTest {
        });
        });
    }
    }


    /**
     * Verify that {@link com.android.server.wm.utils.DisplayInfoOverrides#WM_OVERRIDE_FIELDS}
     * and {@link com.android.server.wm.utils.DisplayInfoOverrides#WM_OVERRIDE_GROUPS}
     * and {@link com.android.server.wm.utils.DisplayInfoOverrides#WM_OVERRIDE_GROUPS} are kept in
     * sync. Works by applying the override and dynamically discovering which fields were
     * changed. It then checks that the set of {@link DisplayInfo.DisplayInfoGroup}s for those
     * fields matches the statically defined group constants.
     */
    @Test
    public void testWmOverrideFieldsAndGroupsAreInSync() {
        final DisplayInfo info1 = new DisplayInfo();
        final DisplayInfo info2 = new DisplayInfo();
        makeAllFieldsDifferent(info1, info2);

        final DisplayInfo result = new DisplayInfo();
        result.copyFrom(info1);
        WM_OVERRIDE_FIELDS.setFields(result, info2);

        final Set<DisplayInfo.DisplayInfoGroup> changedGroups = new HashSet<>();
        forEachDisplayInfoField(field -> {
            try {
                final Object val1 = field.get(info1);
                final Object val2 = field.get(info2);
                final Object resVal = field.get(result);

                // If the result's field value matches info2's value, and that's different
                // from info1's original value, then this field was updated by WM_OVERRIDE_FIELDS.
                if (Objects.equals(resVal, val2) && !Objects.equals(val1, val2)) {
                    // This field was changed by the updater. To find which group(s) it belongs to,
                    // create two DisplayInfo objects that differ only in this one field and check
                    // for changes.
                    final DisplayInfo temp1 = new DisplayInfo();
                    final DisplayInfo temp2 = new DisplayInfo();
                    setDifferentFieldValues(temp1, temp2, field);

                    int groupsMask = temp1.getBasicChangedGroups(temp2);
                    // If groupsMask is 0, the field is not part of any group, and we can ignore it

                    for (DisplayInfo.DisplayInfoGroup group :
                            DisplayInfo.DisplayInfoGroup.values()) {
                        if ((groupsMask & group.getMask()) != 0) {
                            changedGroups.add(group);
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        });

        final String errorMessage = "If you've changed the fields in WM_OVERRIDE_FIELDS, "
                + "you must update WM_OVERRIDE_GROUPS and WM_OVERRIDE_GROUPS_ENUMSET "
                + "accordingly and visa versa.";

        Assert.assertEquals("The set of changed groups does not match WM_OVERRIDE_GROUPS_ENUMSET. "
                + errorMessage, WM_OVERRIDE_GROUPS_ENUMSET, changedGroups);

        int changedGroupsMask = 0;
        for (DisplayInfo.DisplayInfoGroup group : changedGroups) {
            changedGroupsMask |= group.getMask();
        }

        Assert.assertEquals("The mask of changed groups does not match WM_OVERRIDE_GROUPS. "
                + errorMessage, WM_OVERRIDE_GROUPS, changedGroupsMask);
    }

    /**
    /**
     * Sets each field of the objects to different values using reflection
     * Sets each field of the objects to different values using reflection
     */
     */