BatterySaverPolicy.java revision 85dd0852fe506bcf800bea99aeb7af401e1485c4
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 */
16package com.android.server.power;
17
18import android.content.ContentResolver;
19import android.content.Context;
20import android.database.ContentObserver;
21import android.net.Uri;
22import android.os.Handler;
23import android.os.PowerManager.ServiceType;
24import android.os.PowerSaveState;
25import android.provider.Settings;
26import android.provider.Settings.Global;
27import android.text.TextUtils;
28import android.util.ArrayMap;
29import android.util.KeyValueListParser;
30import android.util.Slog;
31
32import com.android.internal.R;
33import com.android.internal.annotations.GuardedBy;
34import com.android.internal.annotations.VisibleForTesting;
35import com.android.server.power.batterysaver.CpuFrequencies;
36
37import java.io.PrintWriter;
38import java.util.ArrayList;
39import java.util.List;
40
41/**
42 * Class to decide whether to turn on battery saver mode for specific service
43 *
44 * Test:
45 atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/power/BatterySaverPolicyTest.java
46 */
47public class BatterySaverPolicy extends ContentObserver {
48    private static final String TAG = "BatterySaverPolicy";
49
50    public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
51
52    // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
53    public static final int GPS_MODE_NO_CHANGE = 0;
54    // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
55    // is enabled and the screen is off.
56    public static final int GPS_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
57    // Secure setting for GPS behavior when battery saver mode is on.
58    public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
59
60    private static final String KEY_GPS_MODE = "gps_mode";
61    private static final String KEY_VIBRATION_DISABLED = "vibration_disabled";
62    private static final String KEY_ANIMATION_DISABLED = "animation_disabled";
63    private static final String KEY_SOUNDTRIGGER_DISABLED = "soundtrigger_disabled";
64    private static final String KEY_FIREWALL_DISABLED = "firewall_disabled";
65    private static final String KEY_ADJUST_BRIGHTNESS_DISABLED = "adjust_brightness_disabled";
66    private static final String KEY_DATASAVER_DISABLED = "datasaver_disabled";
67    private static final String KEY_LAUNCH_BOOST_DISABLED = "launch_boost_disabled";
68    private static final String KEY_ADJUST_BRIGHTNESS_FACTOR = "adjust_brightness_factor";
69    private static final String KEY_FULLBACKUP_DEFERRED = "fullbackup_deferred";
70    private static final String KEY_KEYVALUE_DEFERRED = "keyvaluebackup_deferred";
71    private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby";
72    private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check";
73    private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled";
74
75    private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i";
76    private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n";
77
78    private final Object mLock = new Object();
79
80    @GuardedBy("mLock")
81    private String mSettings;
82
83    @GuardedBy("mLock")
84    private String mDeviceSpecificSettings;
85
86    @GuardedBy("mLock")
87    private String mDeviceSpecificSettingsSource; // For dump() only.
88
89    /**
90     * A short string describing which battery saver is now enabled, which we dump in the eventlog.
91     */
92    @GuardedBy("mLock")
93    private String mEventLogKeys;
94
95    /**
96     * {@code true} if vibration is disabled in battery saver mode.
97     *
98     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
99     * @see #KEY_VIBRATION_DISABLED
100     */
101    @GuardedBy("mLock")
102    private boolean mVibrationDisabled;
103
104    /**
105     * {@code true} if animation is disabled in battery saver mode.
106     *
107     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
108     * @see #KEY_ANIMATION_DISABLED
109     */
110    @GuardedBy("mLock")
111    private boolean mAnimationDisabled;
112
113    /**
114     * {@code true} if sound trigger is disabled in battery saver mode
115     * in battery saver mode.
116     *
117     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
118     * @see #KEY_SOUNDTRIGGER_DISABLED
119     */
120    @GuardedBy("mLock")
121    private boolean mSoundTriggerDisabled;
122
123    /**
124     * {@code true} if full backup is deferred in battery saver mode.
125     *
126     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
127     * @see #KEY_FULLBACKUP_DEFERRED
128     */
129    @GuardedBy("mLock")
130    private boolean mFullBackupDeferred;
131
132    /**
133     * {@code true} if key value backup is deferred in battery saver mode.
134     *
135     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
136     * @see #KEY_KEYVALUE_DEFERRED
137     */
138    @GuardedBy("mLock")
139    private boolean mKeyValueBackupDeferred;
140
141    /**
142     * {@code true} if network policy firewall is disabled in battery saver mode.
143     *
144     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
145     * @see #KEY_FIREWALL_DISABLED
146     */
147    @GuardedBy("mLock")
148    private boolean mFireWallDisabled;
149
150    /**
151     * {@code true} if adjust brightness is disabled in battery saver mode.
152     *
153     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
154     * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
155     */
156    @GuardedBy("mLock")
157    private boolean mAdjustBrightnessDisabled;
158
159    /**
160     * {@code true} if data saver is disabled in battery saver mode.
161     *
162     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
163     * @see #KEY_DATASAVER_DISABLED
164     */
165    @GuardedBy("mLock")
166    private boolean mDataSaverDisabled;
167
168    /**
169     * {@code true} if launch boost should be disabled on battery saver.
170     */
171    @GuardedBy("mLock")
172    private boolean mLaunchBoostDisabled;
173
174    /**
175     * This is the flag to decide the gps mode in battery saver mode.
176     *
177     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
178     * @see #KEY_GPS_MODE
179     */
180    @GuardedBy("mLock")
181    private int mGpsMode;
182
183    /**
184     * This is the flag to decide the how much to adjust the screen brightness. This is
185     * the float value from 0 to 1 where 1 means don't change brightness.
186     *
187     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
188     * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
189     */
190    @GuardedBy("mLock")
191    private float mAdjustBrightnessFactor;
192
193    /**
194     * Whether to put all apps in the stand-by mode.
195     */
196    @GuardedBy("mLock")
197    private boolean mForceAllAppsStandby;
198
199    /**
200     * Whether to put all apps in the stand-by mode.
201     */
202    @GuardedBy("mLock")
203    private boolean mForceBackgroundCheck;
204
205    /**
206     * Weather to show non-essential sensors (e.g. edge sensors) or not.
207     */
208    @GuardedBy("mLock")
209    private boolean mOptionalSensorsDisabled;
210
211    @GuardedBy("mLock")
212    private Context mContext;
213
214    @GuardedBy("mLock")
215    private ContentResolver mContentResolver;
216
217    @GuardedBy("mLock")
218    private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
219
220    /**
221     * List of [Filename -> content] that should be written when battery saver is activated
222     * and the device is interactive.
223     *
224     * We use this to change the max CPU frequencies.
225     */
226    @GuardedBy("mLock")
227    private ArrayMap<String, String> mFilesForInteractive;
228
229    /**
230     * List of [Filename -> content] that should be written when battery saver is activated
231     * and the device is non-interactive.
232     *
233     * We use this to change the max CPU frequencies.
234     */
235    @GuardedBy("mLock")
236    private ArrayMap<String, String> mFilesForNoninteractive;
237
238    public interface BatterySaverPolicyListener {
239        void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
240    }
241
242    public BatterySaverPolicy(Handler handler) {
243        super(handler);
244    }
245
246    public void systemReady(Context context) {
247        synchronized (mLock) {
248            mContext = context;
249            mContentResolver = context.getContentResolver();
250
251            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
252                    Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
253            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
254                    Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
255        }
256        onChange(true, null);
257    }
258
259    public void addListener(BatterySaverPolicyListener listener) {
260        synchronized (mLock) {
261            mListeners.add(listener);
262        }
263    }
264
265    @VisibleForTesting
266    String getGlobalSetting(String key) {
267        final ContentResolver cr;
268        synchronized (mLock) {
269            cr = mContentResolver;
270        }
271        return Settings.Global.getString(cr, key);
272    }
273
274    @VisibleForTesting
275    int getDeviceSpecificConfigResId() {
276        return R.string.config_batterySaverDeviceSpecificConfig;
277    }
278
279    @Override
280    public void onChange(boolean selfChange, Uri uri) {
281        final BatterySaverPolicyListener[] listeners;
282        synchronized (mLock) {
283            // Load the non-device-specific setting.
284            final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
285
286            // Load the device specific setting.
287            // We first check the global setting, and if it's empty or the string "null" is set,
288            // use the default value from config.xml.
289            String deviceSpecificSetting = getGlobalSetting(
290                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
291            mDeviceSpecificSettingsSource =
292                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;
293
294            if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
295                deviceSpecificSetting =
296                        mContext.getString(getDeviceSpecificConfigResId());
297                mDeviceSpecificSettingsSource = "(overlay)";
298            }
299
300            // Update.
301            updateConstantsLocked(setting, deviceSpecificSetting);
302
303            listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
304        }
305
306        // Notify the listeners.
307        for (BatterySaverPolicyListener listener : listeners) {
308            listener.onBatterySaverPolicyChanged(this);
309        }
310    }
311
312    @VisibleForTesting
313    void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
314        mSettings = setting;
315        mDeviceSpecificSettings = deviceSpecificSetting;
316
317        if (DEBUG) {
318            Slog.i(TAG, "mSettings=" + mSettings);
319            Slog.i(TAG, "mDeviceSpecificSettings=" + mDeviceSpecificSettings);
320        }
321
322        final KeyValueListParser parser = new KeyValueListParser(',');
323
324        // Non-device-specific parameters.
325        try {
326            parser.setString(setting);
327        } catch (IllegalArgumentException e) {
328            Slog.wtf(TAG, "Bad battery saver constants: " + setting);
329        }
330
331        mVibrationDisabled = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
332        mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, true);
333        mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
334        mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
335        mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
336        mFireWallDisabled = parser.getBoolean(KEY_FIREWALL_DISABLED, false);
337        mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
338        mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
339        mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
340        mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
341        mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
342        mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
343        mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
344
345        // Get default value from Settings.Secure
346        final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
347                GPS_MODE_NO_CHANGE);
348        mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
349
350        // Non-device-specific parameters.
351        try {
352            parser.setString(deviceSpecificSetting);
353        } catch (IllegalArgumentException e) {
354            Slog.wtf(TAG, "Bad device specific battery saver constants: "
355                    + deviceSpecificSetting);
356        }
357
358        mFilesForInteractive = (new CpuFrequencies()).parseString(
359                parser.getString(KEY_CPU_FREQ_INTERACTIVE, "")).toSysFileMap();
360
361        mFilesForNoninteractive = (new CpuFrequencies()).parseString(
362                parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
363
364        final StringBuilder sb = new StringBuilder();
365
366        if (mForceAllAppsStandby) sb.append("A");
367        if (mForceBackgroundCheck) sb.append("B");
368
369        if (mVibrationDisabled) sb.append("v");
370        if (mAnimationDisabled) sb.append("a");
371        if (mSoundTriggerDisabled) sb.append("s");
372        if (mFullBackupDeferred) sb.append("F");
373        if (mKeyValueBackupDeferred) sb.append("K");
374        if (!mFireWallDisabled) sb.append("f");
375        if (!mDataSaverDisabled) sb.append("d");
376        if (!mAdjustBrightnessDisabled) sb.append("b");
377
378        if (mLaunchBoostDisabled) sb.append("l");
379        if (mOptionalSensorsDisabled) sb.append("S");
380
381        sb.append(mGpsMode);
382
383        mEventLogKeys = sb.toString();
384    }
385
386    /**
387     * Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
388     * The result will have {@link PowerSaveState#batterySaverEnabled} and some other
389     * parameters when necessary.
390     *
391     * @param type     type of the service, one of {@link ServiceType}
392     * @param realMode whether the battery saver is on by default
393     * @return State data that contains battery saver data
394     */
395    public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
396        synchronized (mLock) {
397            final PowerSaveState.Builder builder = new PowerSaveState.Builder()
398                    .setGlobalBatterySaverEnabled(realMode);
399            if (!realMode) {
400                return builder.setBatterySaverEnabled(realMode)
401                        .build();
402            }
403            switch (type) {
404                case ServiceType.GPS:
405                    return builder.setBatterySaverEnabled(realMode)
406                            .setGpsMode(mGpsMode)
407                            .build();
408                case ServiceType.ANIMATION:
409                    return builder.setBatterySaverEnabled(mAnimationDisabled)
410                            .build();
411                case ServiceType.FULL_BACKUP:
412                    return builder.setBatterySaverEnabled(mFullBackupDeferred)
413                            .build();
414                case ServiceType.KEYVALUE_BACKUP:
415                    return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
416                            .build();
417                case ServiceType.NETWORK_FIREWALL:
418                    return builder.setBatterySaverEnabled(!mFireWallDisabled)
419                            .build();
420                case ServiceType.SCREEN_BRIGHTNESS:
421                    return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
422                            .setBrightnessFactor(mAdjustBrightnessFactor)
423                            .build();
424                case ServiceType.DATA_SAVER:
425                    return builder.setBatterySaverEnabled(!mDataSaverDisabled)
426                            .build();
427                case ServiceType.SOUND:
428                    return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
429                            .build();
430                case ServiceType.VIBRATION:
431                    return builder.setBatterySaverEnabled(mVibrationDisabled)
432                            .build();
433                case ServiceType.FORCE_ALL_APPS_STANDBY:
434                    return builder.setBatterySaverEnabled(mForceAllAppsStandby)
435                            .build();
436                case ServiceType.FORCE_BACKGROUND_CHECK:
437                    return builder.setBatterySaverEnabled(mForceBackgroundCheck)
438                            .build();
439                case ServiceType.OPTIONAL_SENSORS:
440                    return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
441                            .build();
442                default:
443                    return builder.setBatterySaverEnabled(realMode)
444                            .build();
445            }
446        }
447    }
448
449    public ArrayMap<String, String> getFileValues(boolean interactive) {
450        synchronized (mLock) {
451            return interactive ? mFilesForInteractive : mFilesForNoninteractive;
452        }
453    }
454
455    public boolean isLaunchBoostDisabled() {
456        synchronized (mLock) {
457            return mLaunchBoostDisabled;
458        }
459    }
460
461    public String toEventLogString() {
462        synchronized (mLock) {
463            return mEventLogKeys;
464        }
465    }
466
467    public void dump(PrintWriter pw) {
468        synchronized (mLock) {
469            pw.println();
470            pw.println("Battery saver policy");
471            pw.println("  Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS);
472            pw.println("    value: " + mSettings);
473            pw.println("  Settings: " + mDeviceSpecificSettingsSource);
474            pw.println("    value: " + mDeviceSpecificSettings);
475
476            pw.println();
477            pw.println("  " + KEY_VIBRATION_DISABLED + "=" + mVibrationDisabled);
478            pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
479            pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
480            pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
481            pw.println("  " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
482            pw.println("  " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
483            pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled);
484            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
485            pw.println("  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
486            pw.println("  " + KEY_GPS_MODE + "=" + mGpsMode);
487            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
488            pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
489            pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
490            pw.println();
491
492            pw.print("  Interactive File values:\n");
493            dumpMap(pw, "    ", mFilesForInteractive);
494            pw.println();
495
496            pw.print("  Noninteractive File values:\n");
497            dumpMap(pw, "    ", mFilesForNoninteractive);
498            pw.println();
499        }
500    }
501
502    private void dumpMap(PrintWriter pw, String prefix, ArrayMap<String, String> map) {
503        if (map == null) {
504            return;
505        }
506        final int size = map.size();
507        for (int i = 0; i < size; i++) {
508            pw.print(prefix);
509            pw.print(map.keyAt(i));
510            pw.print(": '");
511            pw.print(map.valueAt(i));
512            pw.println("'");
513        }
514    }
515}
516