blob: 80bc935959a2cc20e4013146868631384142f392 [file] [log] [blame]
Makoto Onuki66a78122017-11-14 15:03:21 -08001/*
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.batterysaver;
17
18import android.Manifest;
Makoto Onukie098b7592017-11-27 17:50:41 -080019import android.app.ActivityManagerInternal;
Makoto Onuki66a78122017-11-14 15:03:21 -080020import android.content.BroadcastReceiver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.hardware.power.V1_0.PowerHint;
25import android.os.Handler;
26import android.os.Looper;
27import android.os.Message;
28import android.os.PowerManager;
Makoto Onuki3aaed292017-11-15 16:31:24 -080029import android.os.PowerManagerInternal;
Makoto Onuki66a78122017-11-14 15:03:21 -080030import android.os.PowerManagerInternal.LowPowerModeListener;
31import android.os.PowerSaveState;
32import android.os.UserHandle;
33import android.util.ArrayMap;
34import android.util.Slog;
35import android.widget.Toast;
36
37import com.android.internal.annotations.GuardedBy;
Makoto Onuki3aaed292017-11-15 16:31:24 -080038import com.android.internal.util.ArrayUtils;
Makoto Onuki66a78122017-11-14 15:03:21 -080039import com.android.internal.util.Preconditions;
Makoto Onuki3aaed292017-11-15 16:31:24 -080040import com.android.server.LocalServices;
Makoto Onuki66a78122017-11-14 15:03:21 -080041import com.android.server.power.BatterySaverPolicy;
42import com.android.server.power.BatterySaverPolicy.BatterySaverPolicyListener;
43import com.android.server.power.PowerManagerService;
44
45import java.util.ArrayList;
46
47/**
48 * Responsible for battery saver mode transition logic.
49 */
50public class BatterySaverController implements BatterySaverPolicyListener {
51 static final String TAG = "BatterySaverController";
52
Makoto Onukice643a32017-11-20 14:31:06 -080053 static final boolean DEBUG = BatterySaverPolicy.DEBUG;
Makoto Onuki66a78122017-11-14 15:03:21 -080054
55 private final Object mLock = new Object();
56 private final Context mContext;
57 private final MyHandler mHandler;
58 private final FileUpdater mFileUpdater;
59
60 private PowerManager mPowerManager;
61
62 private final BatterySaverPolicy mBatterySaverPolicy;
63
64 @GuardedBy("mLock")
65 private final ArrayList<LowPowerModeListener> mListeners = new ArrayList<>();
66
67 @GuardedBy("mLock")
68 private boolean mEnabled;
69
Makoto Onuki66a78122017-11-14 15:03:21 -080070 private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
71 @Override
72 public void onReceive(Context context, Intent intent) {
73 switch (intent.getAction()) {
74 case Intent.ACTION_SCREEN_ON:
75 case Intent.ACTION_SCREEN_OFF:
Makoto Onuki3aaed292017-11-15 16:31:24 -080076 if (!isEnabled()) {
77 return; // No need to send it if not enabled.
78 }
79 // Don't send the broadcast, because we never did so in this case.
80 mHandler.postStateChanged(/*sendBroadcast=*/ false);
Makoto Onuki66a78122017-11-14 15:03:21 -080081 break;
82 }
83 }
84 };
85
86 /**
87 * Constructor.
88 */
89 public BatterySaverController(Context context, Looper looper, BatterySaverPolicy policy) {
90 mContext = context;
91 mHandler = new MyHandler(looper);
92 mBatterySaverPolicy = policy;
93 mBatterySaverPolicy.addListener(this);
94 mFileUpdater = new FileUpdater(context);
95 }
96
97 /**
98 * Add a listener.
99 */
100 public void addListener(LowPowerModeListener listener) {
101 synchronized (mLock) {
102 mListeners.add(listener);
103 }
104 }
105
106 /**
107 * Called by {@link PowerManagerService} on system ready..
108 */
109 public void systemReady() {
110 final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
111 filter.addAction(Intent.ACTION_SCREEN_OFF);
112 mContext.registerReceiver(mReceiver, filter);
Makoto Onukie098b7592017-11-27 17:50:41 -0800113
114 mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
115 .isRuntimeRestarted());
Makoto Onuki66a78122017-11-14 15:03:21 -0800116 }
117
118 private PowerManager getPowerManager() {
119 if (mPowerManager == null) {
120 mPowerManager =
121 Preconditions.checkNotNull(mContext.getSystemService(PowerManager.class));
122 }
123 return mPowerManager;
124 }
125
126 @Override
127 public void onBatterySaverPolicyChanged(BatterySaverPolicy policy) {
Makoto Onuki3aaed292017-11-15 16:31:24 -0800128 if (!isEnabled()) {
129 return; // No need to send it if not enabled.
130 }
131 mHandler.postStateChanged(/*sendBroadcast=*/ true);
Makoto Onuki66a78122017-11-14 15:03:21 -0800132 }
133
134 private class MyHandler extends Handler {
Makoto Onuki3aaed292017-11-15 16:31:24 -0800135 private static final int MSG_STATE_CHANGED = 1;
136
137 private static final int ARG_DONT_SEND_BROADCAST = 0;
138 private static final int ARG_SEND_BROADCAST = 1;
Makoto Onuki66a78122017-11-14 15:03:21 -0800139
140 public MyHandler(Looper looper) {
141 super(looper);
142 }
143
Makoto Onuki3aaed292017-11-15 16:31:24 -0800144 public void postStateChanged(boolean sendBroadcast) {
145 obtainMessage(MSG_STATE_CHANGED, sendBroadcast ?
146 ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
Makoto Onuki66a78122017-11-14 15:03:21 -0800147 }
148
149 @Override
150 public void dispatchMessage(Message msg) {
151 switch (msg.what) {
152 case MSG_STATE_CHANGED:
Makoto Onuki3aaed292017-11-15 16:31:24 -0800153 handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
Makoto Onuki66a78122017-11-14 15:03:21 -0800154 break;
155 }
156 }
157 }
158
159 /**
160 * Called by {@link PowerManagerService} to update the battery saver stete.
161 */
162 public void enableBatterySaver(boolean enable) {
163 synchronized (mLock) {
164 if (mEnabled == enable) {
165 return;
166 }
167 mEnabled = enable;
168
Makoto Onuki3aaed292017-11-15 16:31:24 -0800169 mHandler.postStateChanged(/*sendBroadcast=*/ true);
170 }
171 }
172
173 /** @return whether battery saver is enabled or not. */
174 boolean isEnabled() {
175 synchronized (mLock) {
176 return mEnabled;
Makoto Onuki66a78122017-11-14 15:03:21 -0800177 }
178 }
179
180 /**
Makoto Onukia7d8c4d2017-11-20 15:20:16 -0800181 * @return true if launch boost should currently be disabled.
182 */
183 public boolean isLaunchBoostDisabled() {
184 return isEnabled() && mBatterySaverPolicy.isLaunchBoostDisabled();
185 }
186
187 /**
Makoto Onuki66a78122017-11-14 15:03:21 -0800188 * Dispatch power save events to the listeners.
189 *
Makoto Onuki3aaed292017-11-15 16:31:24 -0800190 * This method is always called on the handler thread.
191 *
192 * This method is called only in the following cases:
193 * - When battery saver becomes activated.
194 * - When battery saver becomes deactivated.
195 * - When battery saver is on the interactive state changes.
196 * - When battery saver is on the battery saver policy changes.
Makoto Onuki66a78122017-11-14 15:03:21 -0800197 */
Makoto Onuki3aaed292017-11-15 16:31:24 -0800198 void handleBatterySaverStateChanged(boolean sendBroadcast) {
Makoto Onuki66a78122017-11-14 15:03:21 -0800199 final LowPowerModeListener[] listeners;
200
Makoto Onuki66a78122017-11-14 15:03:21 -0800201 final boolean enabled;
Makoto Onuki3aaed292017-11-15 16:31:24 -0800202 final boolean isInteractive = getPowerManager().isInteractive();
Makoto Onuki66a78122017-11-14 15:03:21 -0800203 final ArrayMap<String, String> fileValues;
204
205 synchronized (mLock) {
Makoto Onuki3aaed292017-11-15 16:31:24 -0800206 Slog.i(TAG, "Battery saver " + (mEnabled ? "enabled" : "disabled")
207 + ": isInteractive=" + isInteractive);
Makoto Onuki66a78122017-11-14 15:03:21 -0800208
209 listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
Makoto Onuki66a78122017-11-14 15:03:21 -0800210 enabled = mEnabled;
211
212 if (enabled) {
Makoto Onuki3aaed292017-11-15 16:31:24 -0800213 fileValues = mBatterySaverPolicy.getFileValues(isInteractive);
Makoto Onuki66a78122017-11-14 15:03:21 -0800214 } else {
215 fileValues = null;
216 }
217 }
218
Makoto Onuki3aaed292017-11-15 16:31:24 -0800219 final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
220 if (pmi != null) {
221 pmi.powerHint(PowerHint.LOW_POWER, enabled ? 1 : 0);
222 }
Makoto Onuki66a78122017-11-14 15:03:21 -0800223
Makoto Onuki3aaed292017-11-15 16:31:24 -0800224 if (ArrayUtils.isEmpty(fileValues)) {
Makoto Onuki66a78122017-11-14 15:03:21 -0800225 mFileUpdater.restoreDefault();
226 } else {
227 mFileUpdater.writeFiles(fileValues);
228 }
229
Makoto Onuki3aaed292017-11-15 16:31:24 -0800230 if (sendBroadcast) {
Makoto Onuki1ecaf7c2017-11-27 14:05:53 -0800231 if (enabled) {
232 // STOPSHIP Remove the toast.
233 Toast.makeText(mContext,
234 com.android.internal.R.string.battery_saver_warning,
235 Toast.LENGTH_LONG).show();
236 }
237
Makoto Onuki66a78122017-11-14 15:03:21 -0800238 if (DEBUG) {
239 Slog.i(TAG, "Sending broadcasts for mode: " + enabled);
240 }
241
242 // Send the broadcasts and notify the listeners. We only do this when the battery saver
243 // mode changes, but not when only the screen state changes.
244 Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
245 .putExtra(PowerManager.EXTRA_POWER_SAVE_MODE, enabled)
246 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
247 mContext.sendBroadcast(intent);
248
249 intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
250 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
251 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
252
253 // Send internal version that requires signature permission.
254 intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL);
255 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
256 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
257 Manifest.permission.DEVICE_POWER);
258
259
260 for (LowPowerModeListener listener : listeners) {
261 final PowerSaveState result =
262 mBatterySaverPolicy.getBatterySaverPolicy(
263 listener.getServiceType(), enabled);
264 listener.onLowPowerModeChanged(result);
265 }
266 }
Makoto Onuki66a78122017-11-14 15:03:21 -0800267 }
268}