Cache PowerManager binder calls
Use PropertyInvalidatedCache to save on redundant
binder calls for isPowerSaveMode and isInteractive.
Bug: 140788621
Test: atest BatterySaverTest
Test: atest PowerManagerTest
Change-Id: I849a48eb7c901d3178097d33dce01630dbb78267
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 267613f..a8fa6db 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -26,6 +26,7 @@
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
+import android.app.PropertyInvalidatedCache;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.service.dreams.Sandman;
@@ -877,6 +878,39 @@
}
}
+ private static final String CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY =
+ "cache_key.is_power_save_mode";
+
+ private static final String CACHE_KEY_IS_INTERACTIVE_PROPERTY = "cache_key.is_interactive";
+
+ private static final int MAX_CACHE_ENTRIES = 1;
+
+ private PropertyInvalidatedCache<Void, Boolean> mPowerSaveModeCache =
+ new PropertyInvalidatedCache<Void, Boolean>(MAX_CACHE_ENTRIES,
+ CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY) {
+ @Override
+ protected Boolean recompute(Void query) {
+ try {
+ return mService.isPowerSaveMode();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ };
+
+ private PropertyInvalidatedCache<Void, Boolean> mInteractiveCache =
+ new PropertyInvalidatedCache<Void, Boolean>(MAX_CACHE_ENTRIES,
+ CACHE_KEY_IS_INTERACTIVE_PROPERTY) {
+ @Override
+ protected Boolean recompute(Void query) {
+ try {
+ return mService.isInteractive();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ };
+
final Context mContext;
@UnsupportedAppUsage
final IPowerManager mService;
@@ -1440,11 +1474,7 @@
* @see android.content.Intent#ACTION_SCREEN_OFF
*/
public boolean isInteractive() {
- try {
- return mService.isInteractive();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mInteractiveCache.query(null);
}
/**
@@ -1504,11 +1534,7 @@
* @return Returns true if currently in low power mode, else false.
*/
public boolean isPowerSaveMode() {
- try {
- return mService.isPowerSaveMode();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
+ return mPowerSaveModeCache.query(null);
}
/**
@@ -2508,4 +2534,18 @@
};
}
}
+
+ /**
+ * @hide
+ */
+ public static void invalidatePowerSaveModeCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_IS_POWER_SAVE_MODE_PROPERTY);
+ }
+
+ /**
+ * @hide
+ */
+ public static void invalidateIsInteractiveCaches() {
+ PropertyInvalidatedCache.invalidateCache(CACHE_KEY_IS_INTERACTIVE_PROPERTY);
+ }
}
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index a7b0d84..8483c77 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -242,8 +242,8 @@
private final ServiceThread mHandlerThread;
private final PowerManagerHandler mHandler;
private final AmbientDisplayConfiguration mAmbientDisplayConfiguration;
- private final BatterySaverPolicy mBatterySaverPolicy;
private final BatterySaverController mBatterySaverController;
+ private final BatterySaverPolicy mBatterySaverPolicy;
private final BatterySaverStateMachine mBatterySaverStateMachine;
private final BatterySavingStats mBatterySavingStats;
private final AttentionDetector mAttentionDetector;
@@ -275,7 +275,8 @@
// Indicates whether the device is awake or asleep or somewhere in between.
// This is distinct from the screen power state, which is managed separately.
- private int mWakefulness;
+ // Do not access directly; always use {@link #setWakefulness} and {@link getWakefulness}.
+ private int mWakefulnessRaw;
private boolean mWakefulnessChanging;
// True if the sandman has just been summoned for the first time since entering the
@@ -764,6 +765,13 @@
return new BatterySaverPolicy(lock, context, batterySavingStats);
}
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return new BatterySaverController(lock, context, BackgroundThread.get().getLooper(),
+ batterySaverPolicy, batterySavingStats);
+ }
+
NativeWrapper createNativeWrapper() {
return new NativeWrapper();
}
@@ -794,6 +802,10 @@
}
};
}
+
+ void invalidateIsInteractiveCaches() {
+ PowerManager.invalidateIsInteractiveCaches();
+ }
}
final Constants mConstants;
@@ -833,9 +845,8 @@
mBatterySavingStats = new BatterySavingStats(mLock);
mBatterySaverPolicy =
mInjector.createBatterySaverPolicy(mLock, mContext, mBatterySavingStats);
- mBatterySaverController = new BatterySaverController(mLock, mContext,
- BackgroundThread.get().getLooper(), mBatterySaverPolicy,
- mBatterySavingStats);
+ mBatterySaverController = mInjector.createBatterySaverController(mLock, mContext,
+ mBatterySaverPolicy, mBatterySavingStats);
mBatterySaverStateMachine = new BatterySaverStateMachine(
mLock, mContext, mBatterySaverController);
@@ -939,13 +950,14 @@
mHalAutoSuspendModeEnabled = false;
mHalInteractiveModeEnabled = true;
- mWakefulness = WAKEFULNESS_AWAKE;
+ mWakefulnessRaw = WAKEFULNESS_AWAKE;
sQuiescent = mSystemProperties.get(SYSTEM_PROPERTY_QUIESCENT, "0").equals("1");
mNativeWrapper.nativeInit(this);
mNativeWrapper.nativeSetAutoSuspend(false);
mNativeWrapper.nativeSetInteractive(true);
mNativeWrapper.nativeSetFeature(POWER_FEATURE_DOUBLE_TAP_TO_WAKE, 0);
+ mInjector.invalidateIsInteractiveCaches();
}
}
@@ -1567,8 +1579,8 @@
mOverriddenTimeout = -1;
}
- if (mWakefulness == WAKEFULNESS_ASLEEP
- || mWakefulness == WAKEFULNESS_DOZING
+ if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP
+ || getWakefulnessLocked() == WAKEFULNESS_DOZING
|| (flags & PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
return false;
}
@@ -1624,7 +1636,7 @@
Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
}
- if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
+ if (eventTime < mLastSleepTime || getWakefulnessLocked() == WAKEFULNESS_AWAKE
|| mForceSuspendActive || !mSystemReady) {
return false;
}
@@ -1634,7 +1646,7 @@
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
try {
Slog.i(TAG, "Waking up from "
- + PowerManagerInternal.wakefulnessToString(mWakefulness)
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ " (uid=" + reasonUid
+ ", reason=" + PowerManager.wakeReasonToString(reason)
+ ", details=" + details
@@ -1680,8 +1692,8 @@
}
if (eventTime < mLastWakeTime
- || mWakefulness == WAKEFULNESS_ASLEEP
- || mWakefulness == WAKEFULNESS_DOZING
+ || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
+ || getWakefulnessLocked() == WAKEFULNESS_DOZING
|| !mSystemReady
|| !mBootCompleted) {
return false;
@@ -1738,7 +1750,7 @@
Slog.d(TAG, "napNoUpdateLocked: eventTime=" + eventTime + ", uid=" + uid);
}
- if (eventTime < mLastWakeTime || mWakefulness != WAKEFULNESS_AWAKE
+ if (eventTime < mLastWakeTime || getWakefulnessLocked() != WAKEFULNESS_AWAKE
|| !mBootCompleted || !mSystemReady) {
return false;
}
@@ -1762,7 +1774,7 @@
+ ", uid=" + uid);
}
- if (eventTime < mLastWakeTime || mWakefulness == WAKEFULNESS_ASLEEP
+ if (eventTime < mLastWakeTime || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
|| !mBootCompleted || !mSystemReady) {
return false;
}
@@ -1781,13 +1793,15 @@
@VisibleForTesting
void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
- if (mWakefulness != wakefulness) {
- mWakefulness = wakefulness;
+ if (getWakefulnessLocked() != wakefulness) {
+ // Under lock, invalidate before set ensures caches won't return stale values.
+ mInjector.invalidateIsInteractiveCaches();
+ mWakefulnessRaw = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
// This is only valid while we are in wakefulness dozing. Set to false otherwise.
- mDozeStartInProgress &= (mWakefulness == WAKEFULNESS_DOZING);
+ mDozeStartInProgress &= (getWakefulnessLocked() == WAKEFULNESS_DOZING);
if (mNotifier != null) {
mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
@@ -1797,8 +1811,8 @@
}
@VisibleForTesting
- int getWakefulness() {
- return mWakefulness;
+ int getWakefulnessLocked() {
+ return mWakefulnessRaw;
}
/**
@@ -1816,17 +1830,18 @@
private void finishWakefulnessChangeIfNeededLocked() {
if (mWakefulnessChanging && mDisplayReady) {
- if (mWakefulness == WAKEFULNESS_DOZING
+ if (getWakefulnessLocked() == WAKEFULNESS_DOZING
&& (mWakeLockSummary & WAKE_LOCK_DOZE) == 0) {
return; // wait until dream has enabled dozing
} else {
// Doze wakelock acquired (doze started) or device is no longer dozing.
mDozeStartInProgress = false;
}
- if (mWakefulness == WAKEFULNESS_DOZING || mWakefulness == WAKEFULNESS_ASLEEP) {
+ if (getWakefulnessLocked() == WAKEFULNESS_DOZING
+ || getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
logSleepTimeoutRecapturedLocked();
}
- if (mWakefulness == WAKEFULNESS_AWAKE) {
+ if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime);
if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
@@ -2006,7 +2021,7 @@
}
// If already dreaming and becoming powered, then don't wake.
- if (mIsPowered && mWakefulness == WAKEFULNESS_DREAMING) {
+ if (mIsPowered && getWakefulnessLocked() == WAKEFULNESS_DREAMING) {
return false;
}
@@ -2016,7 +2031,7 @@
}
// On Always On Display, SystemUI shows the charging indicator
- if (mAlwaysOnEnabled && mWakefulness == WAKEFULNESS_DOZING) {
+ if (mAlwaysOnEnabled && getWakefulnessLocked() == WAKEFULNESS_DOZING) {
return false;
}
@@ -2081,7 +2096,7 @@
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakeLockSummaryLocked: mWakefulness="
- + PowerManagerInternal.wakefulnessToString(mWakefulness)
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary));
}
}
@@ -2089,23 +2104,23 @@
private int adjustWakeLockSummaryLocked(int wakeLockSummary) {
// Cancel wake locks that make no sense based on the current state.
- if (mWakefulness != WAKEFULNESS_DOZING) {
+ if (getWakefulnessLocked() != WAKEFULNESS_DOZING) {
wakeLockSummary &= ~(WAKE_LOCK_DOZE | WAKE_LOCK_DRAW);
}
- if (mWakefulness == WAKEFULNESS_ASLEEP
+ if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP
|| (wakeLockSummary & WAKE_LOCK_DOZE) != 0) {
wakeLockSummary &= ~(WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM
| WAKE_LOCK_BUTTON_BRIGHT);
- if (mWakefulness == WAKEFULNESS_ASLEEP) {
+ if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP) {
wakeLockSummary &= ~WAKE_LOCK_PROXIMITY_SCREEN_OFF;
}
}
// Infer implied wake locks where necessary based on the current state.
if ((wakeLockSummary & (WAKE_LOCK_SCREEN_BRIGHT | WAKE_LOCK_SCREEN_DIM)) != 0) {
- if (mWakefulness == WAKEFULNESS_AWAKE) {
+ if (getWakefulnessLocked() == WAKEFULNESS_AWAKE) {
wakeLockSummary |= WAKE_LOCK_CPU | WAKE_LOCK_STAY_AWAKE;
- } else if (mWakefulness == WAKEFULNESS_DREAMING) {
+ } else if (getWakefulnessLocked() == WAKEFULNESS_DREAMING) {
wakeLockSummary |= WAKE_LOCK_CPU;
}
}
@@ -2213,9 +2228,9 @@
mHandler.removeMessages(MSG_USER_ACTIVITY_TIMEOUT);
long nextTimeout = 0;
- if (mWakefulness == WAKEFULNESS_AWAKE
- || mWakefulness == WAKEFULNESS_DREAMING
- || mWakefulness == WAKEFULNESS_DOZING) {
+ if (getWakefulnessLocked() == WAKEFULNESS_AWAKE
+ || getWakefulnessLocked() == WAKEFULNESS_DREAMING
+ || getWakefulnessLocked() == WAKEFULNESS_DOZING) {
final long attentiveTimeout = getAttentiveTimeoutLocked();
final long sleepTimeout = getSleepTimeoutLocked(attentiveTimeout);
final long screenOffTimeout = getScreenOffTimeoutLocked(sleepTimeout,
@@ -2299,7 +2314,7 @@
if (DEBUG_SPEW) {
Slog.d(TAG, "updateUserActivitySummaryLocked: mWakefulness="
- + PowerManagerInternal.wakefulnessToString(mWakefulness)
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked())
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", nextTimeout=" + TimeUtils.formatUptime(nextTimeout));
}
@@ -2368,7 +2383,7 @@
mInattentiveSleepWarningOverlayController.show();
nextTimeout = goToSleepTime;
} else {
- if (DEBUG && mWakefulness != WAKEFULNESS_ASLEEP) {
+ if (DEBUG && getWakefulnessLocked() != WAKEFULNESS_ASLEEP) {
Slog.i(TAG, "Going to sleep now due to long user inactivity");
}
}
@@ -2386,7 +2401,7 @@
return false;
}
- if (mWakefulness != WAKEFULNESS_AWAKE) {
+ if (getWakefulnessLocked() != WAKEFULNESS_AWAKE) {
mInattentiveSleepWarningOverlayController.dismiss(false);
return true;
} else if (attentiveTimeout < 0 || isBeingKeptFromShowingInattentiveSleepWarningLocked()
@@ -2490,7 +2505,7 @@
| DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
| DIRTY_DOCK_STATE | DIRTY_ATTENTIVE | DIRTY_SETTINGS
| DIRTY_SCREEN_BRIGHTNESS_BOOST)) != 0) {
- if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
+ if (getWakefulnessLocked() == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
if (DEBUG_SPEW) {
Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
}
@@ -2613,7 +2628,7 @@
final int wakefulness;
synchronized (mLock) {
mSandmanScheduled = false;
- wakefulness = mWakefulness;
+ wakefulness = getWakefulnessLocked();
if (mSandmanSummoned && mDisplayReady) {
startDreaming = canDreamLocked() || canDozeLocked();
mSandmanSummoned = false;
@@ -2655,7 +2670,7 @@
// If preconditions changed, wait for the next iteration to determine
// whether the dream should continue (or be restarted).
- if (mSandmanSummoned || mWakefulness != wakefulness) {
+ if (mSandmanSummoned || getWakefulnessLocked() != wakefulness) {
return; // wait for next cycle
}
@@ -2717,7 +2732,7 @@
* Returns true if the device is allowed to dream in its current state.
*/
private boolean canDreamLocked() {
- if (mWakefulness != WAKEFULNESS_DREAMING
+ if (getWakefulnessLocked() != WAKEFULNESS_DREAMING
|| !mDreamsSupportedConfig
|| !mDreamsEnabledSetting
|| !mDisplayPowerRequest.isBrightOrDim()
@@ -2749,7 +2764,7 @@
* Returns true if the device is allowed to doze in its current state.
*/
private boolean canDozeLocked() {
- return mWakefulness == WAKEFULNESS_DOZING;
+ return getWakefulnessLocked() == WAKEFULNESS_DOZING;
}
/**
@@ -2825,7 +2840,7 @@
if (DEBUG_SPEW) {
Slog.d(TAG, "updateDisplayPowerStateLocked: mDisplayReady=" + mDisplayReady
+ ", policy=" + mDisplayPowerRequest.policy
- + ", mWakefulness=" + mWakefulness
+ + ", mWakefulness=" + getWakefulnessLocked()
+ ", mWakeLockSummary=0x" + Integer.toHexString(mWakeLockSummary)
+ ", mUserActivitySummary=0x" + Integer.toHexString(mUserActivitySummary)
+ ", mBootCompleted=" + mBootCompleted
@@ -2871,11 +2886,11 @@
@VisibleForTesting
int getDesiredScreenPolicyLocked() {
- if (mWakefulness == WAKEFULNESS_ASLEEP || sQuiescent) {
+ if (getWakefulnessLocked() == WAKEFULNESS_ASLEEP || sQuiescent) {
return DisplayPowerRequest.POLICY_OFF;
}
- if (mWakefulness == WAKEFULNESS_DOZING) {
+ if (getWakefulnessLocked() == WAKEFULNESS_DOZING) {
if ((mWakeLockSummary & WAKE_LOCK_DOZE) != 0) {
return DisplayPowerRequest.POLICY_DOZE;
}
@@ -3079,7 +3094,7 @@
// Here we wait for mWakefulnessChanging to become false since the wakefulness
// transition to DOZING isn't considered "changed" until the doze wake lock is
// acquired.
- if (mWakefulness == WAKEFULNESS_DOZING && mDozeStartInProgress) {
+ if (getWakefulnessLocked() == WAKEFULNESS_DOZING && mDozeStartInProgress) {
return true;
}
@@ -3119,7 +3134,7 @@
private boolean isInteractiveInternal() {
synchronized (mLock) {
- return PowerManagerInternal.isInteractive(mWakefulness);
+ return PowerManagerInternal.isInteractive(getWakefulnessLocked());
}
}
@@ -3495,7 +3510,7 @@
private void boostScreenBrightnessInternal(long eventTime, int uid) {
synchronized (mLock) {
- if (!mSystemReady || mWakefulness == WAKEFULNESS_ASLEEP
+ if (!mSystemReady || getWakefulnessLocked() == WAKEFULNESS_ASLEEP
|| eventTime < mLastScreenBrightnessBoostTime) {
return;
}
@@ -3725,7 +3740,8 @@
pw.println("Power Manager State:");
mConstants.dump(pw);
pw.println(" mDirty=0x" + Integer.toHexString(mDirty));
- pw.println(" mWakefulness=" + PowerManagerInternal.wakefulnessToString(mWakefulness));
+ pw.println(" mWakefulness="
+ + PowerManagerInternal.wakefulnessToString(getWakefulnessLocked()));
pw.println(" mWakefulnessChanging=" + mWakefulnessChanging);
pw.println(" mIsPowered=" + mIsPowered);
pw.println(" mPlugType=" + mPlugType);
@@ -3936,7 +3952,7 @@
synchronized (mLock) {
mConstants.dumpProto(proto);
proto.write(PowerManagerServiceDumpProto.DIRTY, mDirty);
- proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, mWakefulness);
+ proto.write(PowerManagerServiceDumpProto.WAKEFULNESS, getWakefulnessLocked());
proto.write(PowerManagerServiceDumpProto.IS_WAKEFULNESS_CHANGING, mWakefulnessChanging);
proto.write(PowerManagerServiceDumpProto.IS_POWERED, mIsPowered);
proto.write(PowerManagerServiceDumpProto.PLUG_TYPE, mPlugType);
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index 4142e6f..beba106 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -38,7 +38,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.Preconditions;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
import com.android.server.power.PowerManagerService;
@@ -76,11 +75,19 @@
@GuardedBy("mLock")
private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>();
+ /**
+ * Do not access directly; always use {@link #setFullEnabledLocked}
+ * and {@link #getFullEnabledLocked}
+ */
@GuardedBy("mLock")
- private boolean mFullEnabled;
+ private boolean mFullEnabledRaw;
+ /**
+ * Do not access directly; always use {@link #setAdaptiveEnabledLocked} and
+ * {@link #getAdaptiveEnabledLocked}.
+ */
@GuardedBy("mLock")
- private boolean mAdaptiveEnabled;
+ private boolean mAdaptiveEnabledRaw;
@GuardedBy("mLock")
private boolean mIsPluggedIn;
@@ -208,6 +215,7 @@
mPlugins = new Plugin[] {
new BatterySaverLocationPlugin(mContext)
};
+ PowerManager.invalidatePowerSaveModeCaches();
}
/**
@@ -294,10 +302,10 @@
@VisibleForTesting
public void enableBatterySaver(boolean enable, int reason) {
synchronized (mLock) {
- if (mFullEnabled == enable) {
+ if (getFullEnabledLocked() == enable) {
return;
}
- mFullEnabled = enable;
+ setFullEnabledLocked(enable);
if (updatePolicyLevelLocked()) {
mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
@@ -306,9 +314,9 @@
}
private boolean updatePolicyLevelLocked() {
- if (mFullEnabled) {
+ if (getFullEnabledLocked()) {
return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_FULL);
- } else if (mAdaptiveEnabled) {
+ } else if (getAdaptiveEnabledLocked()) {
return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_ADAPTIVE);
} else {
return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_OFF);
@@ -321,8 +329,8 @@
*/
public boolean isEnabled() {
synchronized (mLock) {
- return mFullEnabled
- || (mAdaptiveEnabled && mBatterySaverPolicy.shouldAdvertiseIsEnabled());
+ return getFullEnabledLocked() || (getAdaptiveEnabledLocked()
+ && mBatterySaverPolicy.shouldAdvertiseIsEnabled());
}
}
@@ -332,19 +340,19 @@
*/
private boolean isPolicyEnabled() {
synchronized (mLock) {
- return mFullEnabled || mAdaptiveEnabled;
+ return getFullEnabledLocked() || getAdaptiveEnabledLocked();
}
}
boolean isFullEnabled() {
synchronized (mLock) {
- return mFullEnabled;
+ return getFullEnabledLocked();
}
}
boolean isAdaptiveEnabled() {
synchronized (mLock) {
- return mAdaptiveEnabled;
+ return getAdaptiveEnabledLocked();
}
}
@@ -375,10 +383,10 @@
}
boolean setAdaptivePolicyEnabledLocked(boolean enabled, int reason) {
- if (mAdaptiveEnabled == enabled) {
+ if (getAdaptiveEnabledLocked() == enabled) {
return false;
}
- mAdaptiveEnabled = enabled;
+ setAdaptiveEnabledLocked(enabled);
if (updatePolicyLevelLocked()) {
mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
return true;
@@ -427,19 +435,19 @@
final ArrayMap<String, String> fileValues;
synchronized (mLock) {
- enabled = mFullEnabled || mAdaptiveEnabled;
+ enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked();
EventLogTags.writeBatterySaverMode(
mFullPreviouslyEnabled ? 1 : 0, // Previously off or on.
mAdaptivePreviouslyEnabled ? 1 : 0, // Previously off or on.
- mFullEnabled ? 1 : 0, // Now off or on.
- mAdaptiveEnabled ? 1 : 0, // Now off or on.
+ getFullEnabledLocked() ? 1 : 0, // Now off or on.
+ getAdaptiveEnabledLocked() ? 1 : 0, // Now off or on.
isInteractive ? 1 : 0, // Device interactive state.
enabled ? mBatterySaverPolicy.toEventLogString() : "",
reason);
- mFullPreviouslyEnabled = mFullEnabled;
- mAdaptivePreviouslyEnabled = mAdaptiveEnabled;
+ mFullPreviouslyEnabled = getFullEnabledLocked();
+ mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked();
listeners = mListeners.toArray(new LowPowerModeListener[0]);
@@ -518,10 +526,40 @@
return;
}
mBatterySavingStats.transitionState(
- mFullEnabled ? BatterySaverState.ON :
- (mAdaptiveEnabled ? BatterySaverState.ADAPTIVE : BatterySaverState.OFF),
- isInteractive ? InteractiveState.INTERACTIVE : InteractiveState.NON_INTERACTIVE,
- dozeMode);
+ getFullEnabledLocked() ? BatterySaverState.ON :
+ (getAdaptiveEnabledLocked() ? BatterySaverState.ADAPTIVE :
+ BatterySaverState.OFF),
+ isInteractive ? InteractiveState.INTERACTIVE :
+ InteractiveState.NON_INTERACTIVE,
+ dozeMode);
}
}
+
+ @GuardedBy("mLock")
+ private void setFullEnabledLocked(boolean value) {
+ if (mFullEnabledRaw == value) {
+ return;
+ }
+ PowerManager.invalidatePowerSaveModeCaches();
+ mFullEnabledRaw = value;
+ }
+
+ /** Non-blocking getter exists as a reminder not to directly modify the cached field */
+ private boolean getFullEnabledLocked() {
+ return mFullEnabledRaw;
+ }
+
+ @GuardedBy("mLock")
+ private void setAdaptiveEnabledLocked(boolean value) {
+ if (mAdaptiveEnabledRaw == value) {
+ return;
+ }
+ PowerManager.invalidatePowerSaveModeCaches();
+ mAdaptiveEnabledRaw = value;
+ }
+
+ /** Non-blocking getter exists as a reminder not to directly modify the cached field */
+ private boolean getAdaptiveEnabledLocked() {
+ return mAdaptiveEnabledRaw;
+ }
}
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index 38bdc62..233417d 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -219,8 +219,12 @@
static final int POLICY_LEVEL_ADAPTIVE = 1;
static final int POLICY_LEVEL_FULL = 2;
+ /**
+ * Do not access directly; always use {@link #setPolicyLevel}
+ * and {@link #getPolicyLevelLocked}
+ */
@GuardedBy("mLock")
- private int mPolicyLevel = POLICY_LEVEL_OFF;
+ private int mPolicyLevelRaw = POLICY_LEVEL_OFF;
private final Context mContext;
private final ContentResolver mContentResolver;
@@ -290,6 +294,11 @@
return R.string.config_batterySaverDeviceSpecificConfig;
}
+ @VisibleForTesting
+ void invalidatePowerSaveModeCaches() {
+ PowerManager.invalidatePowerSaveModeCaches();
+ }
+
@Override
public void onChange(boolean selfChange, Uri uri) {
refreshSettings();
@@ -373,14 +382,14 @@
boolean changed = false;
Policy newFullPolicy = Policy.fromSettings(setting, deviceSpecificSetting,
DEFAULT_FULL_POLICY);
- if (mPolicyLevel == POLICY_LEVEL_FULL && !mFullPolicy.equals(newFullPolicy)) {
+ if (getPolicyLevelLocked() == POLICY_LEVEL_FULL && !mFullPolicy.equals(newFullPolicy)) {
changed = true;
}
mFullPolicy = newFullPolicy;
mDefaultAdaptivePolicy = Policy.fromSettings(adaptiveSetting, adaptiveDeviceSpecificSetting,
DEFAULT_ADAPTIVE_POLICY);
- if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE
+ if (getPolicyLevelLocked() == POLICY_LEVEL_ADAPTIVE
&& !mAdaptivePolicy.equals(mDefaultAdaptivePolicy)) {
changed = true;
}
@@ -882,14 +891,14 @@
*/
boolean setPolicyLevel(@PolicyLevel int level) {
synchronized (mLock) {
- if (mPolicyLevel == level) {
+ if (getPolicyLevelLocked() == level) {
return false;
}
switch (level) {
case POLICY_LEVEL_FULL:
case POLICY_LEVEL_ADAPTIVE:
case POLICY_LEVEL_OFF:
- mPolicyLevel = level;
+ setPolicyLevelLocked(level);
break;
default:
Slog.wtf(TAG, "setPolicyLevel invalid level given: " + level);
@@ -911,7 +920,7 @@
}
mAdaptivePolicy = p;
- if (mPolicyLevel == POLICY_LEVEL_ADAPTIVE) {
+ if (getPolicyLevelLocked() == POLICY_LEVEL_ADAPTIVE) {
updatePolicyDependenciesLocked();
return true;
}
@@ -924,7 +933,7 @@
}
private Policy getCurrentPolicyLocked() {
- switch (mPolicyLevel) {
+ switch (getPolicyLevelLocked()) {
case POLICY_LEVEL_FULL:
return mFullPolicy;
case POLICY_LEVEL_ADAPTIVE:
@@ -985,7 +994,7 @@
pw.println(" value: " + mAdaptiveDeviceSpecificSettings);
pw.println(" mAccessibilityEnabled=" + mAccessibilityEnabled);
- pw.println(" mPolicyLevel=" + mPolicyLevel);
+ pw.println(" mPolicyLevel=" + getPolicyLevelLocked());
dumpPolicyLocked(pw, " ", "full", mFullPolicy);
dumpPolicyLocked(pw, " ", "default adaptive", mDefaultAdaptivePolicy);
@@ -1067,4 +1076,20 @@
updatePolicyDependenciesLocked();
}
}
+
+ /** Non-blocking getter exists as a reminder not to modify cached fields directly */
+ @GuardedBy("mLock")
+ private int getPolicyLevelLocked() {
+ return mPolicyLevelRaw;
+ }
+
+ @GuardedBy("mLock")
+ private void setPolicyLevelLocked(int level) {
+ if (mPolicyLevelRaw == level) {
+ return;
+ }
+ // Under lock, invalidate before set ensures caches won't return stale values.
+ invalidatePowerSaveModeCaches();
+ mPolicyLevelRaw = level;
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
index 7666ab9..1c2d8e8 100644
--- a/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/NotifierTest.java
@@ -45,6 +45,7 @@
import com.android.internal.os.BatteryStatsImpl;
import com.android.server.LocalServices;
import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySavingStats;
import com.android.server.statusbar.StatusBarManagerInternal;
@@ -61,6 +62,7 @@
private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
private static final int USER_ID = 0;
+ @Mock private BatterySaverController mBatterySaverControllerMock;
@Mock private BatterySaverPolicy mBatterySaverPolicyMock;
@Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
@Mock private Notifier mNotifierMock;
@@ -223,6 +225,13 @@
}
@Override
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return mBatterySaverControllerMock;
+ }
+
+ @Override
PowerManagerService.NativeWrapper createNativeWrapper() {
return mNativeWrapperMock;
}
@@ -247,6 +256,11 @@
public SystemPropertiesWrapper createSystemPropertiesWrapper() {
return mSystemPropertiesMock;
}
+
+ @Override
+ void invalidateIsInteractiveCaches() {
+ // Avoids an SELinux denial.
+ }
};
private void enableChargingFeedback(boolean chargingFeedbackEnabled, boolean dndOn) {
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index 811089a..0ee2f55 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -81,6 +81,7 @@
import com.android.server.power.PowerManagerService.Injector;
import com.android.server.power.PowerManagerService.NativeWrapper;
import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
+import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySavingStats;
@@ -106,6 +107,7 @@
private static final float BRIGHTNESS_FACTOR = 0.7f;
private static final boolean BATTERY_SAVER_ENABLED = true;
+ @Mock private BatterySaverController mBatterySaverControllerMock;
@Mock private BatterySaverPolicy mBatterySaverPolicyMock;
@Mock private LightsManager mLightsManagerMock;
@Mock private DisplayManagerInternal mDisplayManagerInternalMock;
@@ -207,6 +209,13 @@
}
@Override
+ BatterySaverController createBatterySaverController(
+ Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
+ BatterySavingStats batterySavingStats) {
+ return mBatterySaverControllerMock;
+ }
+
+ @Override
NativeWrapper createNativeWrapper() {
return mNativeWrapperMock;
}
@@ -231,6 +240,11 @@
public SystemPropertiesWrapper createSystemPropertiesWrapper() {
return mSystemPropertiesMock;
}
+
+ @Override
+ void invalidateIsInteractiveCaches() {
+ // Avoids an SELinux failure.
+ }
});
return mService;
}
@@ -369,7 +383,7 @@
@Test
public void testWakefulnessAwake_InitialValue() throws Exception {
createService();
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
}
@Test
@@ -377,12 +391,12 @@
createService();
// Start with AWAKE state
startSystem();
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
// Take a nap and verify.
mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_APPLICATION, PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
}
@Test
@@ -399,21 +413,21 @@
int flags = PowerManager.FULL_WAKE_LOCK;
mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
null /* workSource */, null /* historyTag */);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
// Ensure that the flag does *NOT* work with a partial wake lock.
flags = PowerManager.PARTIAL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
null /* workSource */, null /* historyTag */);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
// Verify that flag forces a wakeup when paired to a FULL_WAKE_LOCK
flags = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP;
mService.getBinderServiceInstance().acquireWakeLock(token, flags, tag, packageName,
null /* workSource */, null /* historyTag */);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
mService.getBinderServiceInstance().releaseWakeLock(token, 0 /* flags */);
}
@@ -424,7 +438,7 @@
forceSleep();
mService.getBinderServiceInstance().wakeUp(SystemClock.uptimeMillis(),
PowerManager.WAKE_REASON_UNKNOWN, "testing IPowerManager.wakeUp()", "pkg.name");
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
}
/**
@@ -445,7 +459,7 @@
.thenReturn(false);
mService.readConfigurationLocked();
setPluggedIn(true);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
when(mResourcesSpy.getBoolean(com.android.internal.R.bool.config_unplugTurnsOnScreen))
.thenReturn(true);
mService.readConfigurationLocked();
@@ -460,20 +474,20 @@
when(mWirelessChargerDetectorMock.update(true /* isPowered */,
BatteryManager.BATTERY_PLUGGED_WIRELESS)).thenReturn(false);
setPluggedIn(true);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
// Test 3:
// Do not wake up if the phone is being REMOVED from a wireless charger
when(mBatteryManagerInternalMock.getPlugType()).thenReturn(0);
setPluggedIn(false);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
// Test 4:
// Do not wake if we are dreaming.
forceAwake(); // Needs to be awake first before it can dream.
forceDream();
setPluggedIn(true);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DREAMING);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DREAMING);
forceSleep();
// Test 5:
@@ -486,7 +500,7 @@
com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug))
.thenReturn(false);
setPluggedIn(false);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
Settings.Global.putInt(
mContextSpy.getContentResolver(), Settings.Global.THEATER_MODE_ON, 0);
mUserSwitchedReceiver.onReceive(mContextSpy, new Intent(Intent.ACTION_USER_SWITCHED));
@@ -499,14 +513,14 @@
forceAwake();
forceDozing();
setPluggedIn(true);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
// Test 7:
// Finally, take away all the factors above and ensure the device wakes up!
forceAwake();
forceSleep();
setPluggedIn(false);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
}
@Test
@@ -514,12 +528,12 @@
createService();
// Start with AWAKE state
startSystem();
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
// Take a nap and verify.
mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
}
@Test
@@ -546,12 +560,12 @@
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
// Verify that we start awake
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
// Grab the wakefulness value when PowerManager finally calls into the
// native component to actually perform the suspend.
when(mNativeWrapperMock.nativeForceSuspend()).then(inv -> {
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
return true;
});
@@ -559,7 +573,7 @@
assertThat(retval).isTrue();
// Still asleep when the function returns.
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
}
@Test
@@ -592,7 +606,7 @@
mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
// Verify that we start awake
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
// Create a wakelock
mService.getBinderServiceInstance().acquireWakeLock(new Binder(), flags, tag, pkg,
@@ -647,7 +661,7 @@
// Start with AWAKE state
startSystem();
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
assertTrue(isAcquired[0]);
// Take a nap and verify we no longer hold the blocker
@@ -657,7 +671,7 @@
when(mDreamManagerInternalMock.isDreaming()).thenReturn(true);
mService.getBinderServiceInstance().goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_APPLICATION, 0);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_DOZING);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_DOZING);
assertFalse(isAcquired[0]);
// Override the display state by DreamManager and verify is reacquires the blocker.
@@ -737,7 +751,7 @@
createService();
startSystem();
SystemClock.sleep(20);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
}
@FlakyTest
@@ -757,7 +771,7 @@
null /* workSource */, null /* historyTag */);
SystemClock.sleep(11);
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
}
@Test
@@ -765,7 +779,7 @@
createService();
startSystem();
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_AWAKE);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_AWAKE);
verify(mNotifierMock, never()).onWakefulnessChangeStarted(anyInt(), anyInt(), anyLong());
}
@@ -784,7 +798,7 @@
createService();
startSystem();
- assertThat(mService.getWakefulness()).isEqualTo(WAKEFULNESS_ASLEEP);
+ assertThat(mService.getWakefulnessLocked()).isEqualTo(WAKEFULNESS_ASLEEP);
verify(mNotifierMock).onWakefulnessChangeStarted(eq(WAKEFULNESS_ASLEEP), anyInt(),
anyLong());
}
diff --git a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
index 98cfc41..30ab9cd 100644
--- a/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/batterysaver/BatterySaverPolicyTest.java
@@ -78,6 +78,11 @@
return mDeviceSpecificConfigResId;
}
+ @Override
+ void invalidatePowerSaveModeCaches() {
+ // Avoids an SELinux denial.
+ }
+
@VisibleForTesting
void onChange() {
onChange(true, null);