Merge "Add caching for getDisplayInfo" into rvc-dev

This commit is contained in:
TreeHugger Robot
2020-03-19 18:18:33 +00:00
committed by Android (Google) Code Review
4 changed files with 153 additions and 50 deletions

View File

@@ -18,6 +18,7 @@ package android.hardware.display;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage; import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context; import android.content.Context;
import android.content.pm.ParceledListSlice; import android.content.pm.ParceledListSlice;
@@ -99,6 +100,20 @@ public final class DisplayManagerGlobal {
} }
} }
private PropertyInvalidatedCache<Integer, DisplayInfo> mDisplayCache =
new PropertyInvalidatedCache<Integer, DisplayInfo>(
8, // size of display cache
CACHE_KEY_DISPLAY_INFO_PROPERTY) {
@Override
protected DisplayInfo recompute(Integer id) {
try {
return mDm.getDisplayInfo(id);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
};
/** /**
* Gets an instance of the display manager global singleton. * Gets an instance of the display manager global singleton.
* *
@@ -127,24 +142,21 @@ public final class DisplayManagerGlobal {
*/ */
@UnsupportedAppUsage @UnsupportedAppUsage
public DisplayInfo getDisplayInfo(int displayId) { public DisplayInfo getDisplayInfo(int displayId) {
try {
synchronized (mLock) { synchronized (mLock) {
DisplayInfo info; DisplayInfo info = null;
if (USE_CACHE) { if (mDisplayCache != null) {
info = mDisplayInfoCache.get(displayId); info = mDisplayCache.query(displayId);
if (info != null) { } else {
return info; try {
}
}
info = mDm.getDisplayInfo(displayId); info = mDm.getDisplayInfo(displayId);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
}
if (info == null) { if (info == null) {
return null; return null;
} }
if (USE_CACHE) {
mDisplayInfoCache.put(displayId, info);
}
registerCallbackIfNeededLocked(); registerCallbackIfNeededLocked();
if (DEBUG) { if (DEBUG) {
@@ -152,9 +164,6 @@ public final class DisplayManagerGlobal {
} }
return info; return info;
} }
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
} }
/** /**
@@ -777,4 +786,26 @@ public final class DisplayManagerGlobal {
} }
} }
} }
/**
* Name of the property containing a unique token which changes every time we update the
* system's display configuration.
*/
public static final String CACHE_KEY_DISPLAY_INFO_PROPERTY =
"cache_key.display_info";
/**
* Invalidates the contents of the display info cache for all applications. Can only
* be called by system_server.
*/
public static void invalidateLocalDisplayInfoCaches() {
PropertyInvalidatedCache.invalidateCache(CACHE_KEY_DISPLAY_INFO_PROPERTY);
}
/**
* Disables the binder call cache.
*/
public void disableLocalDisplayInfoCaches() {
mDisplayCache = null;
}
} }

View File

@@ -0,0 +1,57 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.display;
import android.annotation.Nullable;
import android.hardware.display.DisplayManagerGlobal;
import android.view.DisplayInfo;
/**
* Class for wrapping access of DisplayInfo objects by LogicalDisplay so that we can appropriately
* invalidate caches when they change.
*/
public class DisplayInfoProxy {
private DisplayInfo mInfo;
public DisplayInfoProxy(@Nullable DisplayInfo info) {
mInfo = info;
}
/**
* Set the current {@link DisplayInfo}.
*
* The also automatically invalidates the display info caches across the entire system.
* @param info the new {@link DisplayInfo}.
*/
public void set(@Nullable DisplayInfo info) {
mInfo = info;
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
}
/**
* Returns the current {@link DisplayInfo}.
*
* This info <b>must</b> be treated as immutable. Modifying the returned object is undefined
* behavior that <b>will</b> result in inconsistent states across the system.
*
* @return the current {@link DisplayInfo}
*/
@Nullable
public DisplayInfo get() {
return mInfo;
}
}

View File

@@ -215,6 +215,7 @@ public final class DisplayManagerService extends SystemService {
private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>(); private final ArrayList<DisplayDevice> mDisplayDevices = new ArrayList<DisplayDevice>();
// List of all logical displays indexed by logical display id. // List of all logical displays indexed by logical display id.
// Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
private final SparseArray<LogicalDisplay> mLogicalDisplays = private final SparseArray<LogicalDisplay> mLogicalDisplays =
new SparseArray<LogicalDisplay>(); new SparseArray<LogicalDisplay>();
private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1; private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
@@ -373,6 +374,10 @@ public final class DisplayManagerService extends SystemService {
} }
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS); 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(), publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/); true /*allowIsolated*/);
publishLocalService(DisplayManagerInternal.class, new LocalService()); publishLocalService(DisplayManagerInternal.class, new LocalService());
@@ -1005,9 +1010,17 @@ public final class DisplayManagerService extends SystemService {
if (displayId == Display.DEFAULT_DISPLAY) { if (displayId == Display.DEFAULT_DISPLAY) {
recordTopInsetLocked(display); recordTopInsetLocked(display);
} }
// We don't bother invalidating the display info caches here because any changes to the
// display info will trigger a cache invalidation inside of LogicalDisplay before we hit
// this point.
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED); sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_CHANGED);
} }
private void handleLogicalDisplayRemoved(int displayId) {
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
}
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) { private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
final int count = mDisplayDevices.size(); final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
@@ -1066,6 +1079,7 @@ public final class DisplayManagerService extends SystemService {
} }
mLogicalDisplays.put(displayId, display); mLogicalDisplays.put(displayId, display);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
// Wake up waitForDefaultDisplay. // Wake up waitForDefaultDisplay.
if (isDefault) { if (isDefault) {
@@ -1206,7 +1220,7 @@ public final class DisplayManagerService extends SystemService {
display.updateLocked(mDisplayDevices); display.updateLocked(mDisplayDevices);
if (!display.isValidLocked()) { if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i); mLogicalDisplays.removeAt(i);
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED); handleLogicalDisplayRemoved(displayId);
changed = true; changed = true;
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) { } else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
handleLogicalDisplayChanged(displayId, display); handleLogicalDisplayChanged(displayId, display);

View File

@@ -77,7 +77,7 @@ final class LogicalDisplay {
* needs to be updated. * needs to be updated.
* @see #getDisplayInfoLocked() * @see #getDisplayInfoLocked()
*/ */
private DisplayInfo mInfo; private final DisplayInfoProxy mInfo = new DisplayInfoProxy(null);
// The display device that this logical display is based on and which // The display device that this logical display is based on and which
// determines the base metrics that it uses. // determines the base metrics that it uses.
@@ -141,26 +141,27 @@ final class LogicalDisplay {
* the data changes. * the data changes.
*/ */
public DisplayInfo getDisplayInfoLocked() { public DisplayInfo getDisplayInfoLocked() {
if (mInfo == null) { if (mInfo.get() == null) {
mInfo = new DisplayInfo(); DisplayInfo info = new DisplayInfo();
mInfo.copyFrom(mBaseDisplayInfo); info.copyFrom(mBaseDisplayInfo);
if (mOverrideDisplayInfo != null) { if (mOverrideDisplayInfo != null) {
mInfo.appWidth = mOverrideDisplayInfo.appWidth; info.appWidth = mOverrideDisplayInfo.appWidth;
mInfo.appHeight = mOverrideDisplayInfo.appHeight; info.appHeight = mOverrideDisplayInfo.appHeight;
mInfo.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth; info.smallestNominalAppWidth = mOverrideDisplayInfo.smallestNominalAppWidth;
mInfo.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight; info.smallestNominalAppHeight = mOverrideDisplayInfo.smallestNominalAppHeight;
mInfo.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth; info.largestNominalAppWidth = mOverrideDisplayInfo.largestNominalAppWidth;
mInfo.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight; info.largestNominalAppHeight = mOverrideDisplayInfo.largestNominalAppHeight;
mInfo.logicalWidth = mOverrideDisplayInfo.logicalWidth; info.logicalWidth = mOverrideDisplayInfo.logicalWidth;
mInfo.logicalHeight = mOverrideDisplayInfo.logicalHeight; info.logicalHeight = mOverrideDisplayInfo.logicalHeight;
mInfo.rotation = mOverrideDisplayInfo.rotation; info.rotation = mOverrideDisplayInfo.rotation;
mInfo.displayCutout = mOverrideDisplayInfo.displayCutout; info.displayCutout = mOverrideDisplayInfo.displayCutout;
mInfo.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi; info.logicalDensityDpi = mOverrideDisplayInfo.logicalDensityDpi;
mInfo.physicalXDpi = mOverrideDisplayInfo.physicalXDpi; info.physicalXDpi = mOverrideDisplayInfo.physicalXDpi;
mInfo.physicalYDpi = mOverrideDisplayInfo.physicalYDpi; info.physicalYDpi = mOverrideDisplayInfo.physicalYDpi;
} }
mInfo.set(info);
} }
return mInfo; return mInfo.get();
} }
/** /**
@@ -181,17 +182,16 @@ final class LogicalDisplay {
if (info != null) { if (info != null) {
if (mOverrideDisplayInfo == null) { if (mOverrideDisplayInfo == null) {
mOverrideDisplayInfo = new DisplayInfo(info); mOverrideDisplayInfo = new DisplayInfo(info);
mInfo = null; mInfo.set(null);
return true; return true;
} } else if (!mOverrideDisplayInfo.equals(info)) {
if (!mOverrideDisplayInfo.equals(info)) {
mOverrideDisplayInfo.copyFrom(info); mOverrideDisplayInfo.copyFrom(info);
mInfo = null; mInfo.set(null);
return true; return true;
} }
} else if (mOverrideDisplayInfo != null) { } else if (mOverrideDisplayInfo != null) {
mOverrideDisplayInfo = null; mOverrideDisplayInfo = null;
mInfo = null; mInfo.set(null);
return true; return true;
} }
return false; return false;
@@ -306,7 +306,7 @@ final class LogicalDisplay {
mBaseDisplayInfo.displayId = mDisplayId; mBaseDisplayInfo.displayId = mDisplayId;
mPrimaryDisplayDeviceInfo = deviceInfo; mPrimaryDisplayDeviceInfo = deviceInfo;
mInfo = null; mInfo.set(null);
} }
} }
@@ -327,6 +327,7 @@ final class LogicalDisplay {
private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) { private static Rect getMaskingInsets(DisplayDeviceInfo deviceInfo) {
boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0; boolean maskCutout = (deviceInfo.flags & DisplayDeviceInfo.FLAG_MASK_DISPLAY_CUTOUT) != 0;
if (maskCutout && deviceInfo.displayCutout != null) { if (maskCutout && deviceInfo.displayCutout != null) {
// getSafeInsets is fixed at creation time and cannot change
return deviceInfo.displayCutout.getSafeInsets(); return deviceInfo.displayCutout.getSafeInsets();
} else { } else {
return new Rect(); return new Rect();