1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.server.power.batterysaver;
17 
18 import android.Manifest;
19 import android.annotation.Nullable;
20 import android.app.ActivityManagerInternal;
21 import android.content.BroadcastReceiver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.pm.PackageManagerInternal;
26 import android.hardware.power.Mode;
27 import android.os.BatteryManager;
28 import android.os.BatterySaverPolicyConfig;
29 import android.os.Handler;
30 import android.os.Looper;
31 import android.os.Message;
32 import android.os.PowerManager;
33 import android.os.PowerManagerInternal;
34 import android.os.PowerManagerInternal.LowPowerModeListener;
35 import android.os.PowerSaveState;
36 import android.os.UserHandle;
37 import android.util.ArrayMap;
38 import android.util.Slog;
39 
40 import com.android.internal.R;
41 import com.android.internal.annotations.GuardedBy;
42 import com.android.internal.annotations.VisibleForTesting;
43 import com.android.internal.util.ArrayUtils;
44 import com.android.server.EventLogTags;
45 import com.android.server.LocalServices;
46 import com.android.server.power.PowerManagerService;
47 import com.android.server.power.batterysaver.BatterySaverPolicy.BatterySaverPolicyListener;
48 import com.android.server.power.batterysaver.BatterySaverPolicy.Policy;
49 import com.android.server.power.batterysaver.BatterySaverPolicy.PolicyLevel;
50 import com.android.server.power.batterysaver.BatterySavingStats.BatterySaverState;
51 import com.android.server.power.batterysaver.BatterySavingStats.DozeState;
52 import com.android.server.power.batterysaver.BatterySavingStats.InteractiveState;
53 import com.android.server.power.batterysaver.BatterySavingStats.PlugState;
54 
55 import java.util.ArrayList;
56 import java.util.Objects;
57 import java.util.Optional;
58 
59 /**
60  * Responsible for battery saver mode transition logic.
61  *
62  * IMPORTANT: This class shares the power manager lock, which is very low in the lock hierarchy.
63  * Do not call out with the lock held. (Settings provider is okay.)
64  */
65 public class BatterySaverController implements BatterySaverPolicyListener {
66     static final String TAG = "BatterySaverController";
67 
68     static final boolean DEBUG = BatterySaverPolicy.DEBUG;
69 
70     private final Object mLock;
71     private final Context mContext;
72     private final MyHandler mHandler;
73     private final FileUpdater mFileUpdater;
74 
75     private PowerManager mPowerManager;
76 
77     private final BatterySaverPolicy mBatterySaverPolicy;
78 
79     private final BatterySavingStats mBatterySavingStats;
80 
81     @GuardedBy("mLock")
82     private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>();
83 
84     /**
85      * Do not access directly; always use {@link #setFullEnabledLocked}
86      * and {@link #getFullEnabledLocked}
87      */
88     @GuardedBy("mLock")
89     private boolean mFullEnabledRaw;
90 
91     /**
92      * Do not access directly; always use {@link #setAdaptiveEnabledLocked} and
93      * {@link #getAdaptiveEnabledLocked}.
94      */
95     @GuardedBy("mLock")
96     private boolean mAdaptiveEnabledRaw;
97 
98     @GuardedBy("mLock")
99     private boolean mIsPluggedIn;
100 
101     /**
102      * Whether full was previously enabled or not; only for the event logging. Only use it from
103      * {@link #handleBatterySaverStateChanged}.
104      */
105     private boolean mFullPreviouslyEnabled;
106 
107     /**
108      * Whether adaptive was previously enabled or not; only for the event logging. Only use it from
109      * {@link #handleBatterySaverStateChanged}.
110      */
111     private boolean mAdaptivePreviouslyEnabled;
112 
113     @GuardedBy("mLock")
114     private boolean mIsInteractive;
115 
116     /**
117      * Package name that will receive an explicit manifest broadcast for
118      * {@link PowerManager#ACTION_POWER_SAVE_MODE_CHANGED}. It's {@code null} if it hasn't been
119      * retrieved yet.
120      */
121     @Nullable
122     private Optional<String> mPowerSaveModeChangedListenerPackage;
123 
124     public static final int REASON_PERCENTAGE_AUTOMATIC_ON = 0;
125     public static final int REASON_PERCENTAGE_AUTOMATIC_OFF = 1;
126     public static final int REASON_MANUAL_ON = 2;
127     public static final int REASON_MANUAL_OFF = 3;
128     public static final int REASON_STICKY_RESTORE = 4;
129     public static final int REASON_INTERACTIVE_CHANGED = 5;
130     public static final int REASON_POLICY_CHANGED = 6;
131     public static final int REASON_PLUGGED_IN = 7;
132     public static final int REASON_SETTING_CHANGED = 8;
133     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON = 9;
134     public static final int REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF = 10;
135     public static final int REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED = 11;
136     public static final int REASON_TIMEOUT = 12;
137     public static final int REASON_FULL_POWER_SAVINGS_CHANGED = 13;
138 
reasonToString(int reason)139     static String reasonToString(int reason) {
140         switch (reason) {
141             case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_ON:
142                 return "Percentage Auto ON";
143             case BatterySaverController.REASON_PERCENTAGE_AUTOMATIC_OFF:
144                 return "Percentage Auto OFF";
145             case BatterySaverController.REASON_MANUAL_ON:
146                 return "Manual ON";
147             case BatterySaverController.REASON_MANUAL_OFF:
148                 return "Manual OFF";
149             case BatterySaverController.REASON_STICKY_RESTORE:
150                 return "Sticky restore";
151             case BatterySaverController.REASON_INTERACTIVE_CHANGED:
152                 return "Interactivity changed";
153             case BatterySaverController.REASON_POLICY_CHANGED:
154                 return "Policy changed";
155             case BatterySaverController.REASON_PLUGGED_IN:
156                 return "Plugged in";
157             case BatterySaverController.REASON_SETTING_CHANGED:
158                 return "Setting changed";
159             case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_ON:
160                 return "Dynamic Warning Auto ON";
161             case BatterySaverController.REASON_DYNAMIC_POWER_SAVINGS_AUTOMATIC_OFF:
162                 return "Dynamic Warning Auto OFF";
163             case BatterySaverController.REASON_ADAPTIVE_DYNAMIC_POWER_SAVINGS_CHANGED:
164                 return "Adaptive Power Savings changed";
165             case BatterySaverController.REASON_TIMEOUT:
166                 return "timeout";
167             case BatterySaverController.REASON_FULL_POWER_SAVINGS_CHANGED:
168                 return "Full Power Savings changed";
169             default:
170                 return "Unknown reason: " + reason;
171         }
172     }
173 
174     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
175         @Override
176         public void onReceive(Context context, Intent intent) {
177             if (DEBUG) {
178                 Slog.d(TAG, "onReceive: " + intent);
179             }
180             switch (intent.getAction()) {
181                 case Intent.ACTION_SCREEN_ON:
182                 case Intent.ACTION_SCREEN_OFF:
183                     if (!isPolicyEnabled()) {
184                         updateBatterySavingStats();
185                         return; // No need to send it if not enabled.
186                     }
187                     // We currently evaluate state only for CPU frequency changes.
188                     // Don't send the broadcast, because we never did so in this case.
189                     mHandler.postStateChanged(/*sendBroadcast=*/ false,
190                             REASON_INTERACTIVE_CHANGED);
191                     break;
192                 case Intent.ACTION_BATTERY_CHANGED:
193                     synchronized (mLock) {
194                         mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0);
195                     }
196                     // Fall-through.
197                 case PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED:
198                 case PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED:
199                     updateBatterySavingStats();
200                     break;
201             }
202         }
203     };
204 
205     /**
206      * Constructor.
207      */
BatterySaverController(Object lock, Context context, Looper looper, BatterySaverPolicy policy, BatterySavingStats batterySavingStats)208     public BatterySaverController(Object lock, Context context, Looper looper,
209             BatterySaverPolicy policy, BatterySavingStats batterySavingStats) {
210         mLock = lock;
211         mContext = context;
212         mHandler = new MyHandler(looper);
213         mBatterySaverPolicy = policy;
214         mBatterySaverPolicy.addListener(this);
215         mFileUpdater = new FileUpdater(context);
216         mBatterySavingStats = batterySavingStats;
217 
218         PowerManager.invalidatePowerSaveModeCaches();
219     }
220 
221     /**
222      * Add a listener.
223      */
addListener(LowPowerModeListener listener)224     public void addListener(LowPowerModeListener listener) {
225         synchronized (mLock) {
226             mListeners.add(listener);
227         }
228     }
229 
230     /**
231      * Called by {@link PowerManagerService} on system ready, *with no lock held*.
232      */
systemReady()233     public void systemReady() {
234         final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
235         filter.addAction(Intent.ACTION_SCREEN_OFF);
236         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
237         filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
238         filter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
239         mContext.registerReceiver(mReceiver, filter);
240 
241         mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
242                 .isRuntimeRestarted());
243         mHandler.postSystemReady();
244     }
245 
getPowerManager()246     private PowerManager getPowerManager() {
247         if (mPowerManager == null) {
248             mPowerManager =
249                     Objects.requireNonNull(mContext.getSystemService(PowerManager.class));
250         }
251         return mPowerManager;
252     }
253 
254     @Override
onBatterySaverPolicyChanged(BatterySaverPolicy policy)255     public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) {
256         if (!isPolicyEnabled()) {
257             return; // No need to send it if not enabled.
258         }
259         mHandler.postStateChanged(/*sendBroadcast=*/ true, REASON_POLICY_CHANGED);
260     }
261 
262     private class MyHandler extends Handler {
263         private static final int MSG_STATE_CHANGED = 1;
264 
265         private static final int ARG_DONT_SEND_BROADCAST = 0;
266         private static final int ARG_SEND_BROADCAST = 1;
267 
268         private static final int MSG_SYSTEM_READY = 2;
269 
MyHandler(Looper looper)270         public MyHandler(Looper looper) {
271             super(looper);
272         }
273 
postStateChanged(boolean sendBroadcast, int reason)274         void postStateChanged(boolean sendBroadcast, int reason) {
275             obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
276                     ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, reason).sendToTarget();
277         }
278 
postSystemReady()279         public void postSystemReady() {
280             obtainMessage(MSG_SYSTEM_READY, 0, 0).sendToTarget();
281         }
282 
283         @Override
dispatchMessage(Message msg)284         public void dispatchMessage(Message msg) {
285             switch (msg.what) {
286                 case MSG_STATE_CHANGED:
287                     handleBatterySaverStateChanged(
288                             msg.arg1 == ARG_SEND_BROADCAST,
289                             msg.arg2);
290                     break;
291             }
292         }
293     }
294 
295     /** Enable or disable full battery saver. */
296     @VisibleForTesting
enableBatterySaver(boolean enable, int reason)297     public void enableBatterySaver(boolean enable, int reason) {
298         synchronized (mLock) {
299             if (getFullEnabledLocked() == enable) {
300                 return;
301             }
302             setFullEnabledLocked(enable);
303 
304             if (updatePolicyLevelLocked()) {
305                 mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
306             }
307         }
308     }
309 
updatePolicyLevelLocked()310     private boolean updatePolicyLevelLocked() {
311         if (getFullEnabledLocked()) {
312             return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_FULL);
313         } else if (getAdaptiveEnabledLocked()) {
314             return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_ADAPTIVE);
315         } else {
316             return mBatterySaverPolicy.setPolicyLevel(BatterySaverPolicy.POLICY_LEVEL_OFF);
317         }
318     }
319 
getPolicyLocked(@olicyLevel int policyLevel)320     BatterySaverPolicyConfig getPolicyLocked(@PolicyLevel int policyLevel) {
321         return mBatterySaverPolicy.getPolicyLocked(policyLevel).toConfig();
322     }
323 
324     /**
325      * @return whether battery saver is enabled or not. This takes into
326      * account whether a policy says to advertise isEnabled so this can be propagated externally.
327      */
isEnabled()328     public boolean isEnabled() {
329         synchronized (mLock) {
330             return getFullEnabledLocked() || (getAdaptiveEnabledLocked()
331                     && mBatterySaverPolicy.shouldAdvertiseIsEnabled());
332         }
333     }
334 
335     /**
336      * @return whether battery saver policy is enabled or not. This does not take into account
337      * whether a policy says to advertise isEnabled, so this shouldn't be propagated externally.
338      */
isPolicyEnabled()339     private boolean isPolicyEnabled() {
340         synchronized (mLock) {
341             return getFullEnabledLocked() || getAdaptiveEnabledLocked();
342         }
343     }
344 
isFullEnabled()345     boolean isFullEnabled() {
346         synchronized (mLock) {
347             return getFullEnabledLocked();
348         }
349     }
350 
setFullPolicyLocked(BatterySaverPolicyConfig config, int reason)351     boolean setFullPolicyLocked(BatterySaverPolicyConfig config, int reason) {
352         return setFullPolicyLocked(BatterySaverPolicy.Policy.fromConfig(config), reason);
353     }
354 
setFullPolicyLocked(Policy policy, int reason)355     boolean setFullPolicyLocked(Policy policy, int reason) {
356         if (mBatterySaverPolicy.setFullPolicyLocked(policy)) {
357             mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
358             return true;
359         }
360         return false;
361     }
362 
isAdaptiveEnabled()363     boolean isAdaptiveEnabled() {
364         synchronized (mLock) {
365             return getAdaptiveEnabledLocked();
366         }
367     }
368 
setAdaptivePolicyLocked(BatterySaverPolicyConfig config, int reason)369     boolean setAdaptivePolicyLocked(BatterySaverPolicyConfig config, int reason) {
370         return setAdaptivePolicyLocked(BatterySaverPolicy.Policy.fromConfig(config), reason);
371     }
372 
setAdaptivePolicyLocked(Policy policy, int reason)373     boolean setAdaptivePolicyLocked(Policy policy, int reason) {
374         if (mBatterySaverPolicy.setAdaptivePolicyLocked(policy)) {
375             mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
376             return true;
377         }
378         return false;
379     }
380 
resetAdaptivePolicyLocked(int reason)381     boolean resetAdaptivePolicyLocked(int reason) {
382         if (mBatterySaverPolicy.resetAdaptivePolicyLocked()) {
383             mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
384             return true;
385         }
386         return false;
387     }
388 
setAdaptivePolicyEnabledLocked(boolean enabled, int reason)389     boolean setAdaptivePolicyEnabledLocked(boolean enabled, int reason) {
390         if (getAdaptiveEnabledLocked() == enabled) {
391             return false;
392         }
393         setAdaptiveEnabledLocked(enabled);
394         if (updatePolicyLevelLocked()) {
395             mHandler.postStateChanged(/*sendBroadcast=*/ true, reason);
396             return true;
397         }
398         return false;
399     }
400 
401     /** @return whether device is in interactive state. */
isInteractive()402     public boolean isInteractive() {
403         synchronized (mLock) {
404             return mIsInteractive;
405         }
406     }
407 
408     /** @return Battery saver policy. */
getBatterySaverPolicy()409     public BatterySaverPolicy getBatterySaverPolicy() {
410         return mBatterySaverPolicy;
411     }
412 
413     /**
414      * @return true if launch boost should currently be disabled.
415      */
isLaunchBoostDisabled()416     public boolean isLaunchBoostDisabled() {
417         return isPolicyEnabled() && mBatterySaverPolicy.isLaunchBoostDisabled();
418     }
419 
420     /**
421      * Dispatch power save events to the listeners.
422      *
423      * This method is always called on the handler thread.
424      *
425      * This method is called only in the following cases:
426      * - When battery saver becomes activated.
427      * - When battery saver becomes deactivated.
428      * - When battery saver is on and the interactive state changes.
429      * - When battery saver is on and the battery saver policy changes.
430      * - When adaptive battery saver becomes activated.
431      * - When adaptive battery saver becomes deactivated.
432      * - When adaptive battery saver is active (and full is off) and the policy changes.
433      */
handleBatterySaverStateChanged(boolean sendBroadcast, int reason)434     void handleBatterySaverStateChanged(boolean sendBroadcast, int reason) {
435         final LowPowerModeListener[] listeners;
436 
437         final boolean enabled;
438         final boolean isInteractive = getPowerManager().isInteractive();
439         final ArrayMap<String, String> fileValues;
440 
441         synchronized (mLock) {
442             enabled = getFullEnabledLocked() || getAdaptiveEnabledLocked();
443 
444             EventLogTags.writeBatterySaverMode(
445                     mFullPreviouslyEnabled ? 1 : 0, // Previously off or on.
446                     mAdaptivePreviouslyEnabled ? 1 : 0, // Previously off or on.
447                     getFullEnabledLocked() ? 1 : 0, // Now off or on.
448                     getAdaptiveEnabledLocked() ? 1 : 0, // Now off or on.
449                     isInteractive ?  1 : 0, // Device interactive state.
450                     enabled ? mBatterySaverPolicy.toEventLogString() : "",
451                     reason);
452 
453             mFullPreviouslyEnabled = getFullEnabledLocked();
454             mAdaptivePreviouslyEnabled = getAdaptiveEnabledLocked();
455 
456             listeners = mListeners.toArray(new LowPowerModeListener[0]);
457 
458             mIsInteractive = isInteractive;
459 
460             if (enabled) {
461                 fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
462             } else {
463                 fileValues = null;
464             }
465         }
466 
467         final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
468         if (pmi != null) {
469             pmi.setPowerMode(Mode.LOW_POWER, isEnabled());
470         }
471 
472         updateBatterySavingStats();
473 
474         if (ArrayUtils.isEmpty(fileValues)) {
475             mFileUpdater.restoreDefault();
476         } else {
477             mFileUpdater.writeFiles(fileValues);
478         }
479 
480         if (sendBroadcast) {
481 
482             if (DEBUG) {
483                 Slog.i(TAG, "Sending broadcasts for mode: " + isEnabled());
484             }
485 
486             // Send the broadcasts and notify the listeners. We only do this when the battery saver
487             // mode changes, but not when only the screen state changes.
488             Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
489             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
490             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
491 
492             // Send the broadcast to a manifest-registered receiver that is specified in the config.
493             if (getPowerSaveModeChangedListenerPackage().isPresent()) {
494                 intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED)
495                         .setPackage(getPowerSaveModeChangedListenerPackage().get())
496                         .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
497                                 | Intent.FLAG_RECEIVER_FOREGROUND);
498                 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
499             }
500 
501             // Send internal version that requires signature permission.
502             intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
503             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
504             mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
505                     Manifest.permission.DEVICE_POWER);
506 
507             for (LowPowerModeListener listener : listeners) {
508                 final PowerSaveState result =
509                         mBatterySaverPolicy.getBatterySaverPolicy(listener.getServiceType());
510                 listener.onLowPowerModeChanged(result);
511             }
512         }
513     }
514 
getPowerSaveModeChangedListenerPackage()515     private Optional<String> getPowerSaveModeChangedListenerPackage() {
516         if (mPowerSaveModeChangedListenerPackage == null) {
517             String configPowerSaveModeChangedListenerPackage =
518                     mContext.getString(R.string.config_powerSaveModeChangedListenerPackage);
519             mPowerSaveModeChangedListenerPackage =
520                     LocalServices
521                             .getService(PackageManagerInternal.class)
522                             .isSystemPackage(configPowerSaveModeChangedListenerPackage)
523                             ? Optional.of(configPowerSaveModeChangedListenerPackage)
524                             : Optional.empty();
525         }
526         return mPowerSaveModeChangedListenerPackage;
527     }
528 
updateBatterySavingStats()529     private void updateBatterySavingStats() {
530         final PowerManager pm = getPowerManager();
531         if (pm == null) {
532             Slog.wtf(TAG, "PowerManager not initialized");
533             return;
534         }
535         final boolean isInteractive = pm.isInteractive();
536         final int dozeMode =
537                 pm.isDeviceIdleMode() ? DozeState.DEEP
538                         : pm.isLightDeviceIdleMode() ? DozeState.LIGHT
539                         : DozeState.NOT_DOZING;
540 
541         synchronized (mLock) {
542             mBatterySavingStats.transitionState(
543                     getFullEnabledLocked() ? BatterySaverState.ON :
544                             (getAdaptiveEnabledLocked() ? BatterySaverState.ADAPTIVE :
545                             BatterySaverState.OFF),
546                             isInteractive ? InteractiveState.INTERACTIVE :
547                             InteractiveState.NON_INTERACTIVE,
548                             dozeMode,
549                     mIsPluggedIn ? PlugState.PLUGGED : PlugState.UNPLUGGED);
550         }
551     }
552 
553     @GuardedBy("mLock")
setFullEnabledLocked(boolean value)554     private void setFullEnabledLocked(boolean value) {
555         if (mFullEnabledRaw == value) {
556             return;
557         }
558         PowerManager.invalidatePowerSaveModeCaches();
559         mFullEnabledRaw = value;
560     }
561 
562     /** Non-blocking getter exists as a reminder not to directly modify the cached field */
getFullEnabledLocked()563     private boolean getFullEnabledLocked() {
564         return mFullEnabledRaw;
565     }
566 
567     @GuardedBy("mLock")
setAdaptiveEnabledLocked(boolean value)568     private void setAdaptiveEnabledLocked(boolean value) {
569         if (mAdaptiveEnabledRaw == value) {
570             return;
571         }
572         PowerManager.invalidatePowerSaveModeCaches();
573         mAdaptiveEnabledRaw = value;
574     }
575 
576     /** Non-blocking getter exists as a reminder not to directly modify the cached field */
getAdaptiveEnabledLocked()577     private boolean getAdaptiveEnabledLocked() {
578         return mAdaptiveEnabledRaw;
579     }
580 }
581