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.Nullable;
import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
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.
*
@@ -127,33 +142,27 @@ public final class DisplayManagerGlobal {
*/
@UnsupportedAppUsage
public DisplayInfo getDisplayInfo(int displayId) {
try {
synchronized (mLock) {
DisplayInfo info;
if (USE_CACHE) {
info = mDisplayInfoCache.get(displayId);
if (info != null) {
return info;
}
synchronized (mLock) {
DisplayInfo info = null;
if (mDisplayCache != null) {
info = mDisplayCache.query(displayId);
} else {
try {
info = mDm.getDisplayInfo(displayId);
} catch (RemoteException ex) {
ex.rethrowFromSystemServer();
}
info = mDm.getDisplayInfo(displayId);
if (info == null) {
return null;
}
if (USE_CACHE) {
mDisplayInfoCache.put(displayId, info);
}
registerCallbackIfNeededLocked();
if (DEBUG) {
Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
}
return info;
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
if (info == null) {
return null;
}
registerCallbackIfNeededLocked();
if (DEBUG) {
Log.d(TAG, "getDisplayInfo: displayId=" + displayId + ", info=" + info);
}
return info;
}
}
@@ -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>();
// List of all logical displays indexed by logical display id.
// Any modification to mLogicalDisplays must invalidate the DisplayManagerGlobal cache.
private final SparseArray<LogicalDisplay> mLogicalDisplays =
new SparseArray<LogicalDisplay>();
private int mNextNonDefaultDisplayId = Display.DEFAULT_DISPLAY + 1;
@@ -373,6 +374,10 @@ public final class DisplayManagerService extends SystemService {
}
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());
@@ -1005,9 +1010,17 @@ public final class DisplayManagerService extends SystemService {
if (displayId == Display.DEFAULT_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);
}
private void handleLogicalDisplayRemoved(int displayId) {
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
}
private void applyGlobalDisplayStateLocked(List<Runnable> workQueue) {
final int count = mDisplayDevices.size();
for (int i = 0; i < count; i++) {
@@ -1066,6 +1079,7 @@ public final class DisplayManagerService extends SystemService {
}
mLogicalDisplays.put(displayId, display);
DisplayManagerGlobal.invalidateLocalDisplayInfoCaches();
// Wake up waitForDefaultDisplay.
if (isDefault) {
@@ -1206,7 +1220,7 @@ public final class DisplayManagerService extends SystemService {
display.updateLocked(mDisplayDevices);
if (!display.isValidLocked()) {
mLogicalDisplays.removeAt(i);
sendDisplayEventLocked(displayId, DisplayManagerGlobal.EVENT_DISPLAY_REMOVED);
handleLogicalDisplayRemoved(displayId);
changed = true;
} else if (!mTempDisplayInfo.equals(display.getDisplayInfoLocked())) {
handleLogicalDisplayChanged(displayId, display);

View File

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