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