BatterySaverPolicy.java revision e7ec72a5dfff1d199de5a77b5818478c3e29d825
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     * {@code true} if vibration is disabled in battery saver mode.
91     *
92     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
93     * @see #KEY_VIBRATION_DISABLED
94     */
95    @GuardedBy("mLock")
96    private boolean mVibrationDisabled;
97
98    /**
99     * {@code true} if animation is disabled in battery saver mode.
100     *
101     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
102     * @see #KEY_ANIMATION_DISABLED
103     */
104    @GuardedBy("mLock")
105    private boolean mAnimationDisabled;
106
107    /**
108     * {@code true} if sound trigger is disabled in battery saver mode
109     * in battery saver mode.
110     *
111     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
112     * @see #KEY_SOUNDTRIGGER_DISABLED
113     */
114    @GuardedBy("mLock")
115    private boolean mSoundTriggerDisabled;
116
117    /**
118     * {@code true} if full backup is deferred in battery saver mode.
119     *
120     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
121     * @see #KEY_FULLBACKUP_DEFERRED
122     */
123    @GuardedBy("mLock")
124    private boolean mFullBackupDeferred;
125
126    /**
127     * {@code true} if key value backup is deferred in battery saver mode.
128     *
129     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
130     * @see #KEY_KEYVALUE_DEFERRED
131     */
132    @GuardedBy("mLock")
133    private boolean mKeyValueBackupDeferred;
134
135    /**
136     * {@code true} if network policy firewall is disabled in battery saver mode.
137     *
138     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
139     * @see #KEY_FIREWALL_DISABLED
140     */
141    @GuardedBy("mLock")
142    private boolean mFireWallDisabled;
143
144    /**
145     * {@code true} if adjust brightness is disabled in battery saver mode.
146     *
147     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
148     * @see #KEY_ADJUST_BRIGHTNESS_DISABLED
149     */
150    @GuardedBy("mLock")
151    private boolean mAdjustBrightnessDisabled;
152
153    /**
154     * {@code true} if data saver is disabled in battery saver mode.
155     *
156     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
157     * @see #KEY_DATASAVER_DISABLED
158     */
159    @GuardedBy("mLock")
160    private boolean mDataSaverDisabled;
161
162    /**
163     * {@code true} if launch boost should be disabled on battery saver.
164     */
165    @GuardedBy("mLock")
166    private boolean mLaunchBoostDisabled;
167
168    /**
169     * This is the flag to decide the gps mode in battery saver mode.
170     *
171     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
172     * @see #KEY_GPS_MODE
173     */
174    @GuardedBy("mLock")
175    private int mGpsMode;
176
177    /**
178     * This is the flag to decide the how much to adjust the screen brightness. This is
179     * the float value from 0 to 1 where 1 means don't change brightness.
180     *
181     * @see Settings.Global#BATTERY_SAVER_CONSTANTS
182     * @see #KEY_ADJUST_BRIGHTNESS_FACTOR
183     */
184    @GuardedBy("mLock")
185    private float mAdjustBrightnessFactor;
186
187    /**
188     * Whether to put all apps in the stand-by mode.
189     */
190    @GuardedBy("mLock")
191    private boolean mForceAllAppsStandby;
192
193    /**
194     * Whether to put all apps in the stand-by mode.
195     */
196    @GuardedBy("mLock")
197    private boolean mForceBackgroundCheck;
198
199    /**
200     * Weather to show non-essential sensors (e.g. edge sensors) or not.
201     */
202    @GuardedBy("mLock")
203    private boolean mOptionalSensorsDisabled;
204
205    @GuardedBy("mLock")
206    private Context mContext;
207
208    @GuardedBy("mLock")
209    private ContentResolver mContentResolver;
210
211    @GuardedBy("mLock")
212    private final List<BatterySaverPolicyListener> mListeners = new ArrayList<>();
213
214    /**
215     * List of [Filename -> content] that should be written when battery saver is activated
216     * and the device is interactive.
217     *
218     * We use this to change the max CPU frequencies.
219     */
220    @GuardedBy("mLock")
221    private ArrayMap<String, String> mFilesForInteractive;
222
223    /**
224     * List of [Filename -> content] that should be written when battery saver is activated
225     * and the device is non-interactive.
226     *
227     * We use this to change the max CPU frequencies.
228     */
229    @GuardedBy("mLock")
230    private ArrayMap<String, String> mFilesForNoninteractive;
231
232    public interface BatterySaverPolicyListener {
233        void onBatterySaverPolicyChanged(BatterySaverPolicy policy);
234    }
235
236    public BatterySaverPolicy(Handler handler) {
237        super(handler);
238    }
239
240    public void systemReady(Context context) {
241        synchronized (mLock) {
242            mContext = context;
243            mContentResolver = context.getContentResolver();
244
245            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
246                    Settings.Global.BATTERY_SAVER_CONSTANTS), false, this);
247            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
248                    Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS), false, this);
249        }
250        onChange(true, null);
251    }
252
253    public void addListener(BatterySaverPolicyListener listener) {
254        synchronized (mLock) {
255            mListeners.add(listener);
256        }
257    }
258
259    @VisibleForTesting
260    String getGlobalSetting(String key) {
261        final ContentResolver cr;
262        synchronized (mLock) {
263            cr = mContentResolver;
264        }
265        return Settings.Global.getString(cr, key);
266    }
267
268    @VisibleForTesting
269    int getDeviceSpecificConfigResId() {
270        return R.string.config_batterySaverDeviceSpecificConfig;
271    }
272
273    @Override
274    public void onChange(boolean selfChange, Uri uri) {
275        final BatterySaverPolicyListener[] listeners;
276        synchronized (mLock) {
277            // Load the non-device-specific setting.
278            final String setting = getGlobalSetting(Settings.Global.BATTERY_SAVER_CONSTANTS);
279
280            // Load the device specific setting.
281            // We first check the global setting, and if it's empty or the string "null" is set,
282            // use the default value from config.xml.
283            String deviceSpecificSetting = getGlobalSetting(
284                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS);
285            mDeviceSpecificSettingsSource =
286                    Settings.Global.BATTERY_SAVER_DEVICE_SPECIFIC_CONSTANTS;
287
288            if (TextUtils.isEmpty(deviceSpecificSetting) || "null".equals(deviceSpecificSetting)) {
289                deviceSpecificSetting =
290                        mContext.getString(getDeviceSpecificConfigResId());
291                mDeviceSpecificSettingsSource = "(overlay)";
292            }
293
294            // Update.
295            updateConstantsLocked(setting, deviceSpecificSetting);
296
297            listeners = mListeners.toArray(new BatterySaverPolicyListener[mListeners.size()]);
298        }
299
300        // Notify the listeners.
301        for (BatterySaverPolicyListener listener : listeners) {
302            listener.onBatterySaverPolicyChanged(this);
303        }
304    }
305
306    @VisibleForTesting
307    void updateConstantsLocked(final String setting, final String deviceSpecificSetting) {
308        mSettings = setting;
309        mDeviceSpecificSettings = deviceSpecificSetting;
310
311        if (DEBUG) {
312            Slog.i(TAG, "mSettings=" + mSettings);
313            Slog.i(TAG, "mDeviceSpecificSettings=" + mDeviceSpecificSettings);
314        }
315
316        final KeyValueListParser parser = new KeyValueListParser(',');
317
318        // Non-device-specific parameters.
319        try {
320            parser.setString(setting);
321        } catch (IllegalArgumentException e) {
322            Slog.wtf(TAG, "Bad battery saver constants: " + setting);
323        }
324
325        mVibrationDisabled = parser.getBoolean(KEY_VIBRATION_DISABLED, true);
326        mAnimationDisabled = parser.getBoolean(KEY_ANIMATION_DISABLED, true);
327        mSoundTriggerDisabled = parser.getBoolean(KEY_SOUNDTRIGGER_DISABLED, true);
328        mFullBackupDeferred = parser.getBoolean(KEY_FULLBACKUP_DEFERRED, true);
329        mKeyValueBackupDeferred = parser.getBoolean(KEY_KEYVALUE_DEFERRED, true);
330        mFireWallDisabled = parser.getBoolean(KEY_FIREWALL_DISABLED, false);
331        mAdjustBrightnessDisabled = parser.getBoolean(KEY_ADJUST_BRIGHTNESS_DISABLED, false);
332        mAdjustBrightnessFactor = parser.getFloat(KEY_ADJUST_BRIGHTNESS_FACTOR, 0.5f);
333        mDataSaverDisabled = parser.getBoolean(KEY_DATASAVER_DISABLED, true);
334        mLaunchBoostDisabled = parser.getBoolean(KEY_LAUNCH_BOOST_DISABLED, true);
335        mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true);
336        mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
337        mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
338
339        // Get default value from Settings.Secure
340        final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
341                GPS_MODE_NO_CHANGE);
342        mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
343
344        // Non-device-specific parameters.
345        try {
346            parser.setString(deviceSpecificSetting);
347        } catch (IllegalArgumentException e) {
348            Slog.wtf(TAG, "Bad device specific battery saver constants: "
349                    + deviceSpecificSetting);
350        }
351
352        mFilesForInteractive = (new CpuFrequencies()).parseString(
353                parser.getString(KEY_CPU_FREQ_INTERACTIVE, "")).toSysFileMap();
354
355        mFilesForNoninteractive = (new CpuFrequencies()).parseString(
356                parser.getString(KEY_CPU_FREQ_NONINTERACTIVE, "")).toSysFileMap();
357    }
358
359    /**
360     * Get the {@link PowerSaveState} based on {@paramref type} and {@paramref realMode}.
361     * The result will have {@link PowerSaveState#batterySaverEnabled} and some other
362     * parameters when necessary.
363     *
364     * @param type     type of the service, one of {@link ServiceType}
365     * @param realMode whether the battery saver is on by default
366     * @return State data that contains battery saver data
367     */
368    public PowerSaveState getBatterySaverPolicy(@ServiceType int type, boolean realMode) {
369        synchronized (mLock) {
370            final PowerSaveState.Builder builder = new PowerSaveState.Builder()
371                    .setGlobalBatterySaverEnabled(realMode);
372            if (!realMode) {
373                return builder.setBatterySaverEnabled(realMode)
374                        .build();
375            }
376            switch (type) {
377                case ServiceType.GPS:
378                    return builder.setBatterySaverEnabled(realMode)
379                            .setGpsMode(mGpsMode)
380                            .build();
381                case ServiceType.ANIMATION:
382                    return builder.setBatterySaverEnabled(mAnimationDisabled)
383                            .build();
384                case ServiceType.FULL_BACKUP:
385                    return builder.setBatterySaverEnabled(mFullBackupDeferred)
386                            .build();
387                case ServiceType.KEYVALUE_BACKUP:
388                    return builder.setBatterySaverEnabled(mKeyValueBackupDeferred)
389                            .build();
390                case ServiceType.NETWORK_FIREWALL:
391                    return builder.setBatterySaverEnabled(!mFireWallDisabled)
392                            .build();
393                case ServiceType.SCREEN_BRIGHTNESS:
394                    return builder.setBatterySaverEnabled(!mAdjustBrightnessDisabled)
395                            .setBrightnessFactor(mAdjustBrightnessFactor)
396                            .build();
397                case ServiceType.DATA_SAVER:
398                    return builder.setBatterySaverEnabled(!mDataSaverDisabled)
399                            .build();
400                case ServiceType.SOUND:
401                    return builder.setBatterySaverEnabled(mSoundTriggerDisabled)
402                            .build();
403                case ServiceType.VIBRATION:
404                    return builder.setBatterySaverEnabled(mVibrationDisabled)
405                            .build();
406                case ServiceType.FORCE_ALL_APPS_STANDBY:
407                    return builder.setBatterySaverEnabled(mForceAllAppsStandby)
408                            .build();
409                case ServiceType.FORCE_BACKGROUND_CHECK:
410                    return builder.setBatterySaverEnabled(mForceBackgroundCheck)
411                            .build();
412                case ServiceType.OPTIONAL_SENSORS:
413                    return builder.setBatterySaverEnabled(mOptionalSensorsDisabled)
414                            .build();
415                default:
416                    return builder.setBatterySaverEnabled(realMode)
417                            .build();
418            }
419        }
420    }
421
422    public ArrayMap<String, String> getFileValues(boolean interactive) {
423        synchronized (mLock) {
424            return interactive ? mFilesForInteractive : mFilesForNoninteractive;
425        }
426    }
427
428    public boolean isLaunchBoostDisabled() {
429        synchronized (mLock) {
430            return mLaunchBoostDisabled;
431        }
432    }
433
434    public void dump(PrintWriter pw) {
435        synchronized (mLock) {
436            pw.println();
437            pw.println("Battery saver policy");
438            pw.println("  Settings: " + Settings.Global.BATTERY_SAVER_CONSTANTS);
439            pw.println("    value: " + mSettings);
440            pw.println("  Settings: " + mDeviceSpecificSettingsSource);
441            pw.println("    value: " + mDeviceSpecificSettings);
442
443            pw.println();
444            pw.println("  " + KEY_VIBRATION_DISABLED + "=" + mVibrationDisabled);
445            pw.println("  " + KEY_ANIMATION_DISABLED + "=" + mAnimationDisabled);
446            pw.println("  " + KEY_FULLBACKUP_DEFERRED + "=" + mFullBackupDeferred);
447            pw.println("  " + KEY_KEYVALUE_DEFERRED + "=" + mKeyValueBackupDeferred);
448            pw.println("  " + KEY_FIREWALL_DISABLED + "=" + mFireWallDisabled);
449            pw.println("  " + KEY_DATASAVER_DISABLED + "=" + mDataSaverDisabled);
450            pw.println("  " + KEY_LAUNCH_BOOST_DISABLED + "=" + mLaunchBoostDisabled);
451            pw.println("  " + KEY_ADJUST_BRIGHTNESS_DISABLED + "=" + mAdjustBrightnessDisabled);
452            pw.println("  " + KEY_ADJUST_BRIGHTNESS_FACTOR + "=" + mAdjustBrightnessFactor);
453            pw.println("  " + KEY_GPS_MODE + "=" + mGpsMode);
454            pw.println("  " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby);
455            pw.println("  " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck);
456            pw.println("  " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled);
457            pw.println();
458
459            pw.print("  Interactive File values:\n");
460            dumpMap(pw, "    ", mFilesForInteractive);
461            pw.println();
462
463            pw.print("  Noninteractive File values:\n");
464            dumpMap(pw, "    ", mFilesForNoninteractive);
465            pw.println();
466        }
467    }
468
469    private void dumpMap(PrintWriter pw, String prefix, ArrayMap<String, String> map) {
470        if (map == null) {
471            return;
472        }
473        final int size = map.size();
474        for (int i = 0; i < size; i++) {
475            pw.print(prefix);
476            pw.print(map.keyAt(i));
477            pw.print(": '");
478            pw.print(map.valueAt(i));
479            pw.println("'");
480        }
481    }
482}
483