Loading services/core/java/com/android/server/camera/CameraServiceProxy.java +44 −5 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.wm.WindowManagerInternal; import java.util.ArrayList; import java.util.Collection; Loading Loading @@ -90,8 +91,10 @@ public class CameraServiceProxy extends SystemService private ICameraService mCameraServiceRaw; // Map of currently active camera IDs private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); private final MetricsLogger mLogger = new MetricsLogger(); private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; private static final String NFC_SERVICE_BINDER_NAME = "nfc"; Loading Loading @@ -415,6 +418,24 @@ public class CameraServiceProxy extends SystemService } break; case ICameraServiceProxy.CAMERA_STATE_ACTIVE: // Check current active camera IDs to see if this package is already talking to // some camera boolean alreadyActivePackage = false; for (int i = 0; i < mActiveCameraUsage.size(); i++) { if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { alreadyActivePackage = true; break; } } // If not already active, notify window manager about this new package using a // camera if (!alreadyActivePackage) { WindowManagerInternal wmi = LocalServices.getService(WindowManagerInternal.class); wmi.addNonHighRefreshRatePackage(clientName); } // Update activity events CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel); CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); if (oldEvent != null) { Loading @@ -426,13 +447,31 @@ public class CameraServiceProxy extends SystemService case ICameraServiceProxy.CAMERA_STATE_IDLE: case ICameraServiceProxy.CAMERA_STATE_CLOSED: CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); if (doneEvent != null) { if (doneEvent == null) break; doneEvent.markCompleted(); mCameraUsageHistory.add(doneEvent); if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { dumpUsageEvents(); } // Check current active camera IDs to see if this package is still talking to // some camera boolean stillActivePackage = false; for (int i = 0; i < mActiveCameraUsage.size(); i++) { if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { stillActivePackage = true; break; } } // If not longer active, notify window manager about this package being done // with camera if (!stillActivePackage) { WindowManagerInternal wmi = LocalServices.getService(WindowManagerInternal.class); wmi.removeNonHighRefreshRatePackage(clientName); } break; } boolean isEmpty = mActiveCameraUsage.isEmpty(); Loading services/core/java/com/android/server/wm/DisplayContent.java +4 −3 Original line number Diff line number Diff line Loading @@ -804,10 +804,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mTmpApplySurfaceChangesTransactionState.preferredRefreshRate = w.mAttrs.preferredRefreshRate; } final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy() .getPreferredModeId(w); if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0 && w.mAttrs.preferredDisplayModeId != 0) { mTmpApplySurfaceChangesTransactionState.preferredModeId = w.mAttrs.preferredDisplayModeId; && preferredModeId != 0) { mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId; } } } Loading services/core/java/com/android/server/wm/DisplayPolicy.java +10 −0 Original line number Diff line number Diff line Loading @@ -381,6 +381,8 @@ public class DisplayPolicy { */ @NonNull private Insets mForwardedInsets = Insets.NONE; private RefreshRatePolicy mRefreshRatePolicy; // -------- PolicyHandler -------- private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1; private static final int MSG_REQUEST_TRANSIENT_BARS = 2; Loading Loading @@ -591,6 +593,10 @@ public class DisplayPolicy { mHasStatusBar = false; mHasNavigationBar = mDisplayContent.supportsSystemDecorations(); } mRefreshRatePolicy = new RefreshRatePolicy(mService, mDisplayContent.getDisplayInfo(), mService.mHighRefreshRateBlacklist); } void systemReady() { Loading Loading @@ -3596,6 +3602,10 @@ public class DisplayPolicy { } } RefreshRatePolicy getRefreshRatePolicy() { return mRefreshRatePolicy; } void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("DisplayPolicy"); prefix += " "; Loading services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.wm; import android.annotation.NonNull; import android.os.SystemProperties; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; /** * A Blacklist for packages that should force the display out of high refresh rate. */ class HighRefreshRateBlacklist { private static final String SYSPROP_KEY = "ro.window_manager.high_refresh_rate_blacklist"; private static final String SYSPROP_KEY_LENGTH_SUFFIX = "_length"; private static final String SYSPROP_KEY_ENTRY_SUFFIX = "_entry"; private static final int MAX_ENTRIES = 50; private ArraySet<String> mBlacklistedPackages = new ArraySet<>(); static HighRefreshRateBlacklist create() { return new HighRefreshRateBlacklist(new SystemPropertyGetter() { @Override public int getInt(String key, int def) { return SystemProperties.getInt(key, def); } @Override public String get(String key) { return SystemProperties.get(key); } }); } @VisibleForTesting HighRefreshRateBlacklist(SystemPropertyGetter propertyGetter) { // Read and populate the blacklist final int length = Math.min( propertyGetter.getInt(SYSPROP_KEY + SYSPROP_KEY_LENGTH_SUFFIX, 0), MAX_ENTRIES); for (int i = 1; i <= length; i++) { final String packageName = propertyGetter.get( SYSPROP_KEY + SYSPROP_KEY_ENTRY_SUFFIX + i); if (!packageName.isEmpty()) { mBlacklistedPackages.add(packageName); } } } boolean isBlacklisted(String packageName) { return mBlacklistedPackages.contains(packageName); } interface SystemPropertyGetter { int getInt(String key, int def); @NonNull String get(String key); } } services/core/java/com/android/server/wm/RefreshRatePolicy.java 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.wm; import android.util.ArraySet; import android.view.Display.Mode; import android.view.DisplayInfo; /** * Policy to select a lower refresh rate for the display if applicable. */ class RefreshRatePolicy { private final int mLowRefreshRateId; private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>(); private final HighRefreshRateBlacklist mHighRefreshRateBlacklist; private final WindowManagerService mWmService; RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, HighRefreshRateBlacklist blacklist) { mLowRefreshRateId = findLowRefreshRateModeId(displayInfo); mHighRefreshRateBlacklist = blacklist; mWmService = wmService; } /** * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the * default mode. */ private int findLowRefreshRateModeId(DisplayInfo displayInfo) { Mode mode = displayInfo.getDefaultMode(); float[] refreshRates = displayInfo.getDefaultRefreshRates(); float bestRefreshRate = mode.getRefreshRate(); for (int i = refreshRates.length - 1; i >= 0; i--) { if (refreshRates[i] >= 60f && refreshRates[i] < bestRefreshRate) { bestRefreshRate = refreshRates[i]; } } return displayInfo.findDefaultModeByRefreshRate(bestRefreshRate); } void addNonHighRefreshRatePackage(String packageName) { mNonHighRefreshRatePackages.add(packageName); mWmService.requestTraversal(); } void removeNonHighRefreshRatePackage(String packageName) { mNonHighRefreshRatePackages.remove(packageName); mWmService.requestTraversal(); } int getPreferredModeId(WindowState w) { // If app is animating, it's not able to control refresh rate because we want the animation // to run in default refresh rate. if (w.isAnimating()) { return 0; } // If app requests a certain refresh rate or mode, don't override it. if (w.mAttrs.preferredRefreshRate != 0 || w.mAttrs.preferredDisplayModeId != 0) { return w.mAttrs.preferredDisplayModeId; } final String packageName = w.getOwningPackage(); // If app is using Camera, force it to default (lower) refresh rate. if (mNonHighRefreshRatePackages.contains(packageName)) { return mLowRefreshRateId; } // If app is blacklisted using higher refresh rate, return default (lower) refresh rate if (mHighRefreshRateBlacklist.isBlacklisted(packageName)) { return mLowRefreshRateId; } return 0; } } Loading
services/core/java/com/android/server/camera/CameraServiceProxy.java +44 −5 Original line number Diff line number Diff line Loading @@ -42,6 +42,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import com.android.server.wm.WindowManagerInternal; import java.util.ArrayList; import java.util.Collection; Loading Loading @@ -90,8 +91,10 @@ public class CameraServiceProxy extends SystemService private ICameraService mCameraServiceRaw; // Map of currently active camera IDs private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); private final MetricsLogger mLogger = new MetricsLogger(); private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; private static final String NFC_SERVICE_BINDER_NAME = "nfc"; Loading Loading @@ -415,6 +418,24 @@ public class CameraServiceProxy extends SystemService } break; case ICameraServiceProxy.CAMERA_STATE_ACTIVE: // Check current active camera IDs to see if this package is already talking to // some camera boolean alreadyActivePackage = false; for (int i = 0; i < mActiveCameraUsage.size(); i++) { if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { alreadyActivePackage = true; break; } } // If not already active, notify window manager about this new package using a // camera if (!alreadyActivePackage) { WindowManagerInternal wmi = LocalServices.getService(WindowManagerInternal.class); wmi.addNonHighRefreshRatePackage(clientName); } // Update activity events CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel); CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); if (oldEvent != null) { Loading @@ -426,13 +447,31 @@ public class CameraServiceProxy extends SystemService case ICameraServiceProxy.CAMERA_STATE_IDLE: case ICameraServiceProxy.CAMERA_STATE_CLOSED: CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); if (doneEvent != null) { if (doneEvent == null) break; doneEvent.markCompleted(); mCameraUsageHistory.add(doneEvent); if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { dumpUsageEvents(); } // Check current active camera IDs to see if this package is still talking to // some camera boolean stillActivePackage = false; for (int i = 0; i < mActiveCameraUsage.size(); i++) { if (mActiveCameraUsage.valueAt(i).mClientName.equals(clientName)) { stillActivePackage = true; break; } } // If not longer active, notify window manager about this package being done // with camera if (!stillActivePackage) { WindowManagerInternal wmi = LocalServices.getService(WindowManagerInternal.class); wmi.removeNonHighRefreshRatePackage(clientName); } break; } boolean isEmpty = mActiveCameraUsage.isEmpty(); Loading
services/core/java/com/android/server/wm/DisplayContent.java +4 −3 Original line number Diff line number Diff line Loading @@ -804,10 +804,11 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo mTmpApplySurfaceChangesTransactionState.preferredRefreshRate = w.mAttrs.preferredRefreshRate; } final int preferredModeId = getDisplayPolicy().getRefreshRatePolicy() .getPreferredModeId(w); if (mTmpApplySurfaceChangesTransactionState.preferredModeId == 0 && w.mAttrs.preferredDisplayModeId != 0) { mTmpApplySurfaceChangesTransactionState.preferredModeId = w.mAttrs.preferredDisplayModeId; && preferredModeId != 0) { mTmpApplySurfaceChangesTransactionState.preferredModeId = preferredModeId; } } } Loading
services/core/java/com/android/server/wm/DisplayPolicy.java +10 −0 Original line number Diff line number Diff line Loading @@ -381,6 +381,8 @@ public class DisplayPolicy { */ @NonNull private Insets mForwardedInsets = Insets.NONE; private RefreshRatePolicy mRefreshRatePolicy; // -------- PolicyHandler -------- private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1; private static final int MSG_REQUEST_TRANSIENT_BARS = 2; Loading Loading @@ -591,6 +593,10 @@ public class DisplayPolicy { mHasStatusBar = false; mHasNavigationBar = mDisplayContent.supportsSystemDecorations(); } mRefreshRatePolicy = new RefreshRatePolicy(mService, mDisplayContent.getDisplayInfo(), mService.mHighRefreshRateBlacklist); } void systemReady() { Loading Loading @@ -3596,6 +3602,10 @@ public class DisplayPolicy { } } RefreshRatePolicy getRefreshRatePolicy() { return mRefreshRatePolicy; } void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("DisplayPolicy"); prefix += " "; Loading
services/core/java/com/android/server/wm/HighRefreshRateBlacklist.java 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.wm; import android.annotation.NonNull; import android.os.SystemProperties; import android.util.ArraySet; import com.android.internal.annotations.VisibleForTesting; /** * A Blacklist for packages that should force the display out of high refresh rate. */ class HighRefreshRateBlacklist { private static final String SYSPROP_KEY = "ro.window_manager.high_refresh_rate_blacklist"; private static final String SYSPROP_KEY_LENGTH_SUFFIX = "_length"; private static final String SYSPROP_KEY_ENTRY_SUFFIX = "_entry"; private static final int MAX_ENTRIES = 50; private ArraySet<String> mBlacklistedPackages = new ArraySet<>(); static HighRefreshRateBlacklist create() { return new HighRefreshRateBlacklist(new SystemPropertyGetter() { @Override public int getInt(String key, int def) { return SystemProperties.getInt(key, def); } @Override public String get(String key) { return SystemProperties.get(key); } }); } @VisibleForTesting HighRefreshRateBlacklist(SystemPropertyGetter propertyGetter) { // Read and populate the blacklist final int length = Math.min( propertyGetter.getInt(SYSPROP_KEY + SYSPROP_KEY_LENGTH_SUFFIX, 0), MAX_ENTRIES); for (int i = 1; i <= length; i++) { final String packageName = propertyGetter.get( SYSPROP_KEY + SYSPROP_KEY_ENTRY_SUFFIX + i); if (!packageName.isEmpty()) { mBlacklistedPackages.add(packageName); } } } boolean isBlacklisted(String packageName) { return mBlacklistedPackages.contains(packageName); } interface SystemPropertyGetter { int getInt(String key, int def); @NonNull String get(String key); } }
services/core/java/com/android/server/wm/RefreshRatePolicy.java 0 → 100644 +92 −0 Original line number Diff line number Diff line /* * Copyright (C) 2019 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.wm; import android.util.ArraySet; import android.view.Display.Mode; import android.view.DisplayInfo; /** * Policy to select a lower refresh rate for the display if applicable. */ class RefreshRatePolicy { private final int mLowRefreshRateId; private final ArraySet<String> mNonHighRefreshRatePackages = new ArraySet<>(); private final HighRefreshRateBlacklist mHighRefreshRateBlacklist; private final WindowManagerService mWmService; RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, HighRefreshRateBlacklist blacklist) { mLowRefreshRateId = findLowRefreshRateModeId(displayInfo); mHighRefreshRateBlacklist = blacklist; mWmService = wmService; } /** * Finds the mode id with the lowest refresh rate which is >= 60hz and same resolution as the * default mode. */ private int findLowRefreshRateModeId(DisplayInfo displayInfo) { Mode mode = displayInfo.getDefaultMode(); float[] refreshRates = displayInfo.getDefaultRefreshRates(); float bestRefreshRate = mode.getRefreshRate(); for (int i = refreshRates.length - 1; i >= 0; i--) { if (refreshRates[i] >= 60f && refreshRates[i] < bestRefreshRate) { bestRefreshRate = refreshRates[i]; } } return displayInfo.findDefaultModeByRefreshRate(bestRefreshRate); } void addNonHighRefreshRatePackage(String packageName) { mNonHighRefreshRatePackages.add(packageName); mWmService.requestTraversal(); } void removeNonHighRefreshRatePackage(String packageName) { mNonHighRefreshRatePackages.remove(packageName); mWmService.requestTraversal(); } int getPreferredModeId(WindowState w) { // If app is animating, it's not able to control refresh rate because we want the animation // to run in default refresh rate. if (w.isAnimating()) { return 0; } // If app requests a certain refresh rate or mode, don't override it. if (w.mAttrs.preferredRefreshRate != 0 || w.mAttrs.preferredDisplayModeId != 0) { return w.mAttrs.preferredDisplayModeId; } final String packageName = w.getOwningPackage(); // If app is using Camera, force it to default (lower) refresh rate. if (mNonHighRefreshRatePackages.contains(packageName)) { return mLowRefreshRateId; } // If app is blacklisted using higher refresh rate, return default (lower) refresh rate if (mHighRefreshRateBlacklist.isBlacklisted(packageName)) { return mLowRefreshRateId; } return 0; } }