blob: 48e96aa17c35fdfcea3dae40137681f377a9e15e [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 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
17package com.android.server;
18
Dianne Hackborn14272302014-06-10 23:13:02 -070019import android.database.ContentObserver;
Dianne Hackborn8c841092013-06-24 13:46:13 -070020import android.os.BatteryStats;
Jeff Brown21392762014-06-13 19:00:36 -070021
Dianne Hackborn2e441072015-10-28 18:00:57 -070022import android.os.ResultReceiver;
23import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024import com.android.internal.app.IBatteryStats;
25import com.android.server.am.BatteryStatsService;
Adam Lesinskief2ea1f2013-12-05 16:48:06 -080026import com.android.server.lights.Light;
27import com.android.server.lights.LightsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028
29import android.app.ActivityManagerNative;
30import android.content.ContentResolver;
31import android.content.Context;
32import android.content.Intent;
33import android.content.pm.PackageManager;
34import android.os.BatteryManager;
Jeff Brown21392762014-06-13 19:00:36 -070035import android.os.BatteryManagerInternal;
Todd Poynor26faecc2013-05-22 18:54:48 -070036import android.os.BatteryProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037import android.os.Binder;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070038import android.os.FileUtils;
Jeff Brown605ea692012-10-05 16:33:10 -070039import android.os.Handler;
Todd Poynor26faecc2013-05-22 18:54:48 -070040import android.os.IBatteryPropertiesListener;
41import android.os.IBatteryPropertiesRegistrar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080042import android.os.IBinder;
Dan Egnor18e93962010-02-10 19:27:58 -080043import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.RemoteException;
45import android.os.ServiceManager;
46import android.os.SystemClock;
47import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070048import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.provider.Settings;
50import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080051import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080052
53import java.io.File;
54import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import java.io.FileOutputStream;
56import java.io.IOException;
57import java.io.PrintWriter;
58
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059
60/**
61 * <p>BatteryService monitors the charging status, and charge level of the device
62 * battery. When these values change this service broadcasts the new values
63 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
64 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
65 * BATTERY_CHANGED} action.</p>
66 * <p>The new values are stored in the Intent data and can be retrieved by
67 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
68 * following keys:</p>
69 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
70 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
71 * <p>&quot;status&quot; - String, the current charging status.<br />
72 * <p>&quot;health&quot; - String, the current battery health.<br />
73 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
74 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
75 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
76 * into an AC power adapter; 2 if plugged in via USB.</p>
77 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
78 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
79 * a degree Centigrade</p>
80 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
Jeff Brown605ea692012-10-05 16:33:10 -070081 *
82 * <p>
83 * The battery service may be called by the power manager while holding its locks so
84 * we take care to post all outcalls into the activity manager to a handler.
85 *
86 * FIXME: Ideally the power manager would perform all of its calls into the battery
87 * service asynchronously itself.
88 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080089 */
Jeff Brown21392762014-06-13 19:00:36 -070090public final class BatteryService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080091 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -080092
Jeff Browna4d82042012-10-02 19:11:19 -070093 private static final boolean DEBUG = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -080094
Jeff Browna4d82042012-10-02 19:11:19 -070095 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
97 // Used locally for determining when to make a last ditch effort to log
98 // discharge stats before the device dies.
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070099 private int mCriticalBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
Jeff Sharkeyec43a6b2013-04-30 13:33:18 -0700101 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800102
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103 private static final String DUMPSYS_DATA_PATH = "/data/system/";
104
105 // This should probably be exposed in the API, though it's not critical
106 private static final int BATTERY_PLUGGED_NONE = 0;
107
108 private final Context mContext;
109 private final IBatteryStats mBatteryStats;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700110 BinderService mBinderService;
Jeff Brown605ea692012-10-05 16:33:10 -0700111 private final Handler mHandler;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800112
Jeff Browna4d82042012-10-02 19:11:19 -0700113 private final Object mLock = new Object();
114
Todd Poynor26faecc2013-05-22 18:54:48 -0700115 private BatteryProperties mBatteryProps;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800116 private final BatteryProperties mLastBatteryProps = new BatteryProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800117 private boolean mBatteryLevelCritical;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 private int mLastBatteryStatus;
119 private int mLastBatteryHealth;
120 private boolean mLastBatteryPresent;
121 private int mLastBatteryLevel;
122 private int mLastBatteryVoltage;
123 private int mLastBatteryTemperature;
124 private boolean mLastBatteryLevelCritical;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700125 private int mLastMaxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700126 private int mLastMaxChargingVoltage;
Jeff Browna4d82042012-10-02 19:11:19 -0700127
128 private int mInvalidCharger;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700129 private int mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400130
131 private int mLowBatteryWarningLevel;
132 private int mLowBatteryCloseWarningLevel;
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700133 private int mShutdownBatteryTemperature;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400134
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135 private int mPlugType;
136 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800137
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700138 private boolean mBatteryLevelLow;
139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 private long mDischargeStartTime;
141 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800142
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700143 private boolean mUpdatesStopped;
144
Joe Onoratode1b3592010-10-25 20:36:47 -0700145 private Led mLed;
146
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700147 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800148
Jeff Brown21392762014-06-13 19:00:36 -0700149 public BatteryService(Context context) {
150 super(context);
151
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 mContext = context;
Jeff Brown605ea692012-10-05 16:33:10 -0700153 mHandler = new Handler(true /*async*/);
Jeff Brown21392762014-06-13 19:00:36 -0700154 mLed = new Led(context, getLocalService(LightsManager.class));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 mBatteryStats = BatteryStatsService.getService();
156
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700157 mCriticalBatteryLevel = mContext.getResources().getInteger(
158 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400159 mLowBatteryWarningLevel = mContext.getResources().getInteger(
160 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Dianne Hackborn14272302014-06-10 23:13:02 -0700161 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
162 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700163 mShutdownBatteryTemperature = mContext.getResources().getInteger(
164 com.android.internal.R.integer.config_shutdownBatteryTemperature);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400165
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400166 // watch for invalid charger messages if the invalid_charger switch exists
167 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700168 UEventObserver invalidChargerObserver = new UEventObserver() {
169 @Override
170 public void onUEvent(UEvent event) {
171 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
172 synchronized (mLock) {
173 if (mInvalidCharger != invalidCharger) {
174 mInvalidCharger = invalidCharger;
175 }
176 }
177 }
178 };
179 invalidChargerObserver.startObserving(
Jeff Browna4d82042012-10-02 19:11:19 -0700180 "DEVPATH=/devices/virtual/switch/invalid_charger");
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400181 }
Jeff Brown21392762014-06-13 19:00:36 -0700182 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183
Jeff Brown21392762014-06-13 19:00:36 -0700184 @Override
185 public void onStart() {
Todd Poynor0edc5b52013-10-22 17:53:13 -0700186 IBinder b = ServiceManager.getService("batteryproperties");
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800187 final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
188 IBatteryPropertiesRegistrar.Stub.asInterface(b);
Todd Poynor26faecc2013-05-22 18:54:48 -0700189 try {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800190 batteryPropertiesRegistrar.registerListener(new BatteryListener());
Todd Poynor26faecc2013-05-22 18:54:48 -0700191 } catch (RemoteException e) {
192 // Should never happen.
Jeff Browna4d82042012-10-02 19:11:19 -0700193 }
Jeff Brown21392762014-06-13 19:00:36 -0700194
Dianne Hackborn2e441072015-10-28 18:00:57 -0700195 mBinderService = new BinderService();
196 publishBinderService("battery", mBinderService);
Jeff Brown21392762014-06-13 19:00:36 -0700197 publishLocalService(BatteryManagerInternal.class, new LocalService());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800198 }
199
Jeff Brown21392762014-06-13 19:00:36 -0700200 @Override
201 public void onBootPhase(int phase) {
202 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
203 // check our power situation now that it is safe to display the shutdown dialog.
204 synchronized (mLock) {
205 ContentObserver obs = new ContentObserver(mHandler) {
206 @Override
207 public void onChange(boolean selfChange) {
208 synchronized (mLock) {
209 updateBatteryWarningLevelLocked();
210 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700211 }
Jeff Brown21392762014-06-13 19:00:36 -0700212 };
213 final ContentResolver resolver = mContext.getContentResolver();
214 resolver.registerContentObserver(Settings.Global.getUriFor(
215 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
216 false, obs, UserHandle.USER_ALL);
217 updateBatteryWarningLevelLocked();
218 }
Jeff Browna4d82042012-10-02 19:11:19 -0700219 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 }
221
Jeff Brown21392762014-06-13 19:00:36 -0700222 private void updateBatteryWarningLevelLocked() {
Dianne Hackborn14272302014-06-10 23:13:02 -0700223 final ContentResolver resolver = mContext.getContentResolver();
224 int defWarnLevel = mContext.getResources().getInteger(
225 com.android.internal.R.integer.config_lowBatteryWarningLevel);
226 mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
227 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
228 if (mLowBatteryWarningLevel == 0) {
229 mLowBatteryWarningLevel = defWarnLevel;
230 }
231 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
232 mLowBatteryWarningLevel = mCriticalBatteryLevel;
233 }
234 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
235 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
236 processValuesLocked(true);
237 }
238
Jeff Browna4d82042012-10-02 19:11:19 -0700239 private boolean isPoweredLocked(int plugTypeSet) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240 // assume we are powered if battery state is unknown so
241 // the "stay on while plugged in" option will work.
Todd Poynor26faecc2013-05-22 18:54:48 -0700242 if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800243 return true;
244 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700245 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700246 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700248 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700249 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800250 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700251 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700252 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800253 }
Jeff Browna4d82042012-10-02 19:11:19 -0700254 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 }
256
Jeff Brown21392762014-06-13 19:00:36 -0700257 private boolean shouldSendBatteryLowLocked() {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700258 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
259 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
260
261 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
262 * - is just un-plugged (previously was plugged) and battery level is
263 * less than or equal to WARNING, or
264 * - is not plugged and battery level falls to WARNING boundary
265 * (becomes <= mLowBatteryWarningLevel).
266 */
267 return !plugged
268 && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
269 && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
270 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
271 }
272
Jeff Browna4d82042012-10-02 19:11:19 -0700273 private void shutdownIfNoPowerLocked() {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400274 // shut down gracefully if our battery is critically low and we are not powered.
275 // wait until the system has booted before attempting to display the shutdown dialog.
Todd Poynor26faecc2013-05-22 18:54:48 -0700276 if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
Jeff Brown605ea692012-10-05 16:33:10 -0700277 mHandler.post(new Runnable() {
278 @Override
279 public void run() {
280 if (ActivityManagerNative.isSystemReady()) {
281 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
282 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
283 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
284 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
285 }
286 }
287 });
Mike Lockwood07a500f2009-08-12 09:56:44 -0400288 }
289 }
290
Jeff Browna4d82042012-10-02 19:11:19 -0700291 private void shutdownIfOverTempLocked() {
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700292 // shut down gracefully if temperature is too high (> 68.0C by default)
293 // wait until the system has booted before attempting to display the
294 // shutdown dialog.
Todd Poynor26faecc2013-05-22 18:54:48 -0700295 if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
Jeff Brown605ea692012-10-05 16:33:10 -0700296 mHandler.post(new Runnable() {
297 @Override
298 public void run() {
299 if (ActivityManagerNative.isSystemReady()) {
300 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
301 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
302 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
303 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
304 }
305 }
306 });
Eric Olsen6a362a92010-03-26 15:38:41 -0700307 }
308 }
309
Todd Poynor26faecc2013-05-22 18:54:48 -0700310 private void update(BatteryProperties props) {
311 synchronized (mLock) {
312 if (!mUpdatesStopped) {
313 mBatteryProps = props;
314 // Process the new values.
Dianne Hackborn14272302014-06-10 23:13:02 -0700315 processValuesLocked(false);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800316 } else {
317 mLastBatteryProps.set(props);
Todd Poynor26faecc2013-05-22 18:54:48 -0700318 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700319 }
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700320 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321
Dianne Hackborn14272302014-06-10 23:13:02 -0700322 private void processValuesLocked(boolean force) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700323 boolean logOutlier = false;
324 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700325
Todd Poynor26faecc2013-05-22 18:54:48 -0700326 mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
327 if (mBatteryProps.chargerAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800328 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
Todd Poynor26faecc2013-05-22 18:54:48 -0700329 } else if (mBatteryProps.chargerUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800330 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
Todd Poynor26faecc2013-05-22 18:54:48 -0700331 } else if (mBatteryProps.chargerWirelessOnline) {
Brian Muramatsu37a37f42012-08-14 15:21:02 -0700332 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 } else {
334 mPlugType = BATTERY_PLUGGED_NONE;
335 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700336
Jeff Browna4d82042012-10-02 19:11:19 -0700337 if (DEBUG) {
338 Slog.d(TAG, "Processing new values: "
Todd Poynor26faecc2013-05-22 18:54:48 -0700339 + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
340 + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
341 + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
Adrian Roos7b043112015-07-10 13:00:33 -0700342 + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700343 + ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage
Todd Poynor26faecc2013-05-22 18:54:48 -0700344 + ", batteryStatus=" + mBatteryProps.batteryStatus
345 + ", batteryHealth=" + mBatteryProps.batteryHealth
346 + ", batteryPresent=" + mBatteryProps.batteryPresent
347 + ", batteryLevel=" + mBatteryProps.batteryLevel
348 + ", batteryTechnology=" + mBatteryProps.batteryTechnology
349 + ", batteryVoltage=" + mBatteryProps.batteryVoltage
350 + ", batteryTemperature=" + mBatteryProps.batteryTemperature
Jeff Browna4d82042012-10-02 19:11:19 -0700351 + ", mBatteryLevelCritical=" + mBatteryLevelCritical
352 + ", mPlugType=" + mPlugType);
353 }
354
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700355 // Let the battery stats keep track of the current level.
356 try {
Todd Poynor26faecc2013-05-22 18:54:48 -0700357 mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
358 mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
359 mBatteryProps.batteryVoltage);
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700360 } catch (RemoteException e) {
361 // Should never happen.
362 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700363
Jeff Browna4d82042012-10-02 19:11:19 -0700364 shutdownIfNoPowerLocked();
365 shutdownIfOverTempLocked();
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700366
Dianne Hackborn14272302014-06-10 23:13:02 -0700367 if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
Todd Poynor26faecc2013-05-22 18:54:48 -0700368 mBatteryProps.batteryHealth != mLastBatteryHealth ||
369 mBatteryProps.batteryPresent != mLastBatteryPresent ||
370 mBatteryProps.batteryLevel != mLastBatteryLevel ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800371 mPlugType != mLastPlugType ||
Todd Poynor26faecc2013-05-22 18:54:48 -0700372 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
373 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
Adrian Roos76dc5a52015-07-21 16:20:36 -0700374 mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent ||
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700375 mBatteryProps.maxChargingVoltage != mLastMaxChargingVoltage ||
Dianne Hackborn14272302014-06-10 23:13:02 -0700376 mInvalidCharger != mLastInvalidCharger)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800377
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800378 if (mPlugType != mLastPlugType) {
379 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
380 // discharging -> charging
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800381
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 // There's no value in this data unless we've discharged at least once and the
383 // battery level has changed; so don't log until it does.
Todd Poynor26faecc2013-05-22 18:54:48 -0700384 if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700385 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
386 logOutlier = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800387 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
Todd Poynor26faecc2013-05-22 18:54:48 -0700388 mDischargeStartLevel, mBatteryProps.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 // make sure we see a discharge event before logging again
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800390 mDischargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800391 }
392 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
393 // charging -> discharging or we just powered up
394 mDischargeStartTime = SystemClock.elapsedRealtime();
Todd Poynor26faecc2013-05-22 18:54:48 -0700395 mDischargeStartLevel = mBatteryProps.batteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 }
397 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700398 if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
399 mBatteryProps.batteryHealth != mLastBatteryHealth ||
400 mBatteryProps.batteryPresent != mLastBatteryPresent ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 mPlugType != mLastPlugType) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800402 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
Todd Poynor26faecc2013-05-22 18:54:48 -0700403 mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
404 mPlugType, mBatteryProps.batteryTechnology);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800405 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700406 if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
Dianne Hackborncf1171642013-07-12 17:26:02 -0700407 // Don't do this just from voltage or temperature changes, that is
408 // too noisy.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800409 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
Todd Poynor26faecc2013-05-22 18:54:48 -0700410 mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411 }
412 if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
413 mPlugType == BATTERY_PLUGGED_NONE) {
414 // We want to make sure we log discharge cycle outliers
415 // if the battery is about to die.
The Android Open Source Project10592532009-03-18 17:39:46 -0700416 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
417 logOutlier = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800419
Dianne Hackborn14272302014-06-10 23:13:02 -0700420 if (!mBatteryLevelLow) {
421 // Should we now switch in to low battery mode?
422 if (mPlugType == BATTERY_PLUGGED_NONE
423 && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
424 mBatteryLevelLow = true;
425 }
426 } else {
427 // Should we now switch out of low battery mode?
428 if (mPlugType != BATTERY_PLUGGED_NONE) {
429 mBatteryLevelLow = false;
430 } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
431 mBatteryLevelLow = false;
432 } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
433 // If being forced, the previous state doesn't matter, we will just
434 // absolutely check to see if we are now above the warning level.
435 mBatteryLevelLow = false;
436 }
437 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800438
Jeff Browna4d82042012-10-02 19:11:19 -0700439 sendIntentLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800440
Christopher Tate06ba5542009-04-09 16:03:56 -0700441 // Separate broadcast is sent for power connected / not connected
442 // since the standard intent will not wake any applications and some
443 // applications may want to have smart behavior based on this.
444 if (mPlugType != 0 && mLastPlugType == 0) {
Jeff Brown605ea692012-10-05 16:33:10 -0700445 mHandler.post(new Runnable() {
446 @Override
447 public void run() {
448 Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
449 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
450 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
451 }
452 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700453 }
454 else if (mPlugType == 0 && mLastPlugType != 0) {
Jeff Brown605ea692012-10-05 16:33:10 -0700455 mHandler.post(new Runnable() {
456 @Override
457 public void run() {
458 Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
459 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
460 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
461 }
462 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700463 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200464
Dianne Hackborn14272302014-06-10 23:13:02 -0700465 if (shouldSendBatteryLowLocked()) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700466 mSentLowBatteryBroadcast = true;
Jeff Brown605ea692012-10-05 16:33:10 -0700467 mHandler.post(new Runnable() {
468 @Override
469 public void run() {
470 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
471 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
472 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
473 }
474 });
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400475 } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700476 mSentLowBatteryBroadcast = false;
Jeff Brown605ea692012-10-05 16:33:10 -0700477 mHandler.post(new Runnable() {
478 @Override
479 public void run() {
480 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
481 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
482 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
483 }
484 });
Mihai Predaa82842f2009-04-29 15:05:56 +0200485 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800486
Joe Onoratode1b3592010-10-25 20:36:47 -0700487 // Update the battery LED
488 mLed.updateLightsLocked();
489
The Android Open Source Project10592532009-03-18 17:39:46 -0700490 // This needs to be done after sendIntent() so that we get the lastest battery stats.
491 if (logOutlier && dischargeDuration != 0) {
Jeff Browna4d82042012-10-02 19:11:19 -0700492 logOutlierLocked(dischargeDuration);
The Android Open Source Project10592532009-03-18 17:39:46 -0700493 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800494
Todd Poynor26faecc2013-05-22 18:54:48 -0700495 mLastBatteryStatus = mBatteryProps.batteryStatus;
496 mLastBatteryHealth = mBatteryProps.batteryHealth;
497 mLastBatteryPresent = mBatteryProps.batteryPresent;
498 mLastBatteryLevel = mBatteryProps.batteryLevel;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700499 mLastPlugType = mPlugType;
Todd Poynor26faecc2013-05-22 18:54:48 -0700500 mLastBatteryVoltage = mBatteryProps.batteryVoltage;
501 mLastBatteryTemperature = mBatteryProps.batteryTemperature;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700502 mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700503 mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700504 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400505 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800506 }
507 }
508
Jeff Browna4d82042012-10-02 19:11:19 -0700509 private void sendIntentLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800510 // Pack up the values and broadcast them to everyone
Jeff Brown605ea692012-10-05 16:33:10 -0700511 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800512 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
513 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800514
Todd Poynor26faecc2013-05-22 18:54:48 -0700515 int icon = getIconLocked(mBatteryProps.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516
Todd Poynor26faecc2013-05-22 18:54:48 -0700517 intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
518 intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
519 intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
520 intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
Dianne Hackbornedd93162009-09-19 14:03:05 -0700521 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
522 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
523 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
Todd Poynor26faecc2013-05-22 18:54:48 -0700524 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
525 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
526 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400527 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
Adrian Roos7b043112015-07-10 13:00:33 -0700528 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700529 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
Jeff Browna4d82042012-10-02 19:11:19 -0700530 if (DEBUG) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700531 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel +
532 ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
Adrian Roos7b043112015-07-10 13:00:33 -0700533 ", health:" + mBatteryProps.batteryHealth +
534 ", present:" + mBatteryProps.batteryPresent +
Todd Poynor26faecc2013-05-22 18:54:48 -0700535 ", voltage: " + mBatteryProps.batteryVoltage +
536 ", temperature: " + mBatteryProps.batteryTemperature +
537 ", technology: " + mBatteryProps.batteryTechnology +
Adrian Roos7b043112015-07-10 13:00:33 -0700538 ", AC powered:" + mBatteryProps.chargerAcOnline +
539 ", USB powered:" + mBatteryProps.chargerUsbOnline +
Todd Poynor26faecc2013-05-22 18:54:48 -0700540 ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
Adrian Roos7b043112015-07-10 13:00:33 -0700541 ", icon:" + icon + ", invalid charger:" + mInvalidCharger +
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700542 ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent +
543 ", maxChargingVoltage:" + mBatteryProps.maxChargingVoltage);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800544 }
545
Jeff Brown605ea692012-10-05 16:33:10 -0700546 mHandler.post(new Runnable() {
547 @Override
548 public void run() {
549 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
550 }
551 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800552 }
553
Jeff Browna4d82042012-10-02 19:11:19 -0700554 private void logBatteryStatsLocked() {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700555 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800556 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557
Dan Egnor18e93962010-02-10 19:27:58 -0800558 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
559 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
560
561 File dumpFile = null;
562 FileOutputStream dumpStream = null;
563 try {
564 // dump the service to a file
Dianne Hackborn8c841092013-06-24 13:46:13 -0700565 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
Dan Egnor18e93962010-02-10 19:27:58 -0800566 dumpStream = new FileOutputStream(dumpFile);
567 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -0700568 FileUtils.sync(dumpStream);
Dan Egnor18e93962010-02-10 19:27:58 -0800569
570 // add dump file to drop box
571 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
572 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800573 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800574 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800575 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800576 } finally {
577 // make sure we clean up
578 if (dumpStream != null) {
579 try {
580 dumpStream.close();
581 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800582 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583 }
Dan Egnor18e93962010-02-10 19:27:58 -0800584 }
585 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800586 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800587 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
589 }
590 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800591
Jeff Browna4d82042012-10-02 19:11:19 -0700592 private void logOutlierLocked(long duration) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 ContentResolver cr = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -0700594 String dischargeThresholdString = Settings.Global.getString(cr,
595 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
596 String durationThresholdString = Settings.Global.getString(cr,
597 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800598
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800599 if (dischargeThresholdString != null && durationThresholdString != null) {
600 try {
601 long durationThreshold = Long.parseLong(durationThresholdString);
602 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800603 if (duration <= durationThreshold &&
Todd Poynor26faecc2013-05-22 18:54:48 -0700604 mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800605 // If the discharge cycle is bad enough we want to know about it.
Jeff Browna4d82042012-10-02 19:11:19 -0700606 logBatteryStatsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800607 }
Jeff Browna4d82042012-10-02 19:11:19 -0700608 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800609 " discharge threshold: " + dischargeThreshold);
Jeff Browna4d82042012-10-02 19:11:19 -0700610 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
Todd Poynor26faecc2013-05-22 18:54:48 -0700611 (mDischargeStartLevel - mBatteryProps.batteryLevel));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800613 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 durationThresholdString + " or " + dischargeThresholdString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800615 }
616 }
617 }
618
Jeff Browna4d82042012-10-02 19:11:19 -0700619 private int getIconLocked(int level) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700620 if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 return com.android.internal.R.drawable.stat_sys_battery_charge;
Todd Poynor26faecc2013-05-22 18:54:48 -0700622 } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800623 return com.android.internal.R.drawable.stat_sys_battery;
Todd Poynor26faecc2013-05-22 18:54:48 -0700624 } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
625 || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
Jeff Browna4d82042012-10-02 19:11:19 -0700626 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
Todd Poynor26faecc2013-05-22 18:54:48 -0700627 && mBatteryProps.batteryLevel >= 100) {
Joe Onorato794be402010-11-21 19:22:25 -0800628 return com.android.internal.R.drawable.stat_sys_battery_charge;
629 } else {
630 return com.android.internal.R.drawable.stat_sys_battery;
631 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800632 } else {
633 return com.android.internal.R.drawable.stat_sys_battery_unknown;
634 }
635 }
636
Dianne Hackborn2e441072015-10-28 18:00:57 -0700637 class Shell extends ShellCommand {
638 @Override
639 public int onCommand(String cmd) {
640 return onShellCommand(this, cmd);
641 }
642
643 @Override
644 public void onHelp() {
645 PrintWriter pw = getOutPrintWriter();
646 dumpHelp(pw);
647 }
648 }
649
650 static void dumpHelp(PrintWriter pw) {
651 pw.println("Battery service (battery) commands:");
652 pw.println(" help");
653 pw.println(" Print this help text.");
654 pw.println(" set [ac|usb|wireless|status|level|invalid] <value>");
655 pw.println(" Force a battery property value, freezing battery state.");
656 pw.println(" unplug");
657 pw.println(" Force battery unplugged, freezing battery state.");
658 pw.println(" reset");
659 pw.println(" Unfreeze battery state, returning to current hardware values.");
660 }
661
662 int onShellCommand(Shell shell, String cmd) {
663 if (cmd == null) {
664 return shell.handleDefaultCommands(cmd);
665 }
666 PrintWriter pw = shell.getOutPrintWriter();
667 switch (cmd) {
668 case "unplug": {
669 getContext().enforceCallingOrSelfPermission(
670 android.Manifest.permission.DEVICE_POWER, null);
671 if (!mUpdatesStopped) {
672 mLastBatteryProps.set(mBatteryProps);
673 }
674 mBatteryProps.chargerAcOnline = false;
675 mBatteryProps.chargerUsbOnline = false;
676 mBatteryProps.chargerWirelessOnline = false;
677 long ident = Binder.clearCallingIdentity();
678 try {
679 mUpdatesStopped = true;
680 processValuesLocked(false);
681 } finally {
682 Binder.restoreCallingIdentity(ident);
683 }
684 } break;
685 case "set": {
686 getContext().enforceCallingOrSelfPermission(
687 android.Manifest.permission.DEVICE_POWER, null);
688 final String key = shell.getNextArg();
689 if (key == null) {
690 pw.println("No property specified");
691 return -1;
692
693 }
694 final String value = shell.getNextArg();
695 if (value == null) {
696 pw.println("No value specified");
697 return -1;
698
699 }
700 try {
701 if (!mUpdatesStopped) {
702 mLastBatteryProps.set(mBatteryProps);
703 }
704 boolean update = true;
705 switch (key) {
706 case "ac":
707 mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
708 break;
709 case "usb":
710 mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
711 break;
712 case "wireless":
713 mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
714 break;
715 case "status":
716 mBatteryProps.batteryStatus = Integer.parseInt(value);
717 break;
718 case "level":
719 mBatteryProps.batteryLevel = Integer.parseInt(value);
720 break;
721 case "invalid":
722 mInvalidCharger = Integer.parseInt(value);
723 break;
724 default:
725 pw.println("Unknown set option: " + key);
726 update = false;
727 break;
728 }
729 if (update) {
730 long ident = Binder.clearCallingIdentity();
731 try {
732 mUpdatesStopped = true;
733 processValuesLocked(false);
734 } finally {
735 Binder.restoreCallingIdentity(ident);
736 }
737 }
738 } catch (NumberFormatException ex) {
739 pw.println("Bad value: " + value);
740 return -1;
741 }
742 } break;
743 case "reset": {
744 getContext().enforceCallingOrSelfPermission(
745 android.Manifest.permission.DEVICE_POWER, null);
746 long ident = Binder.clearCallingIdentity();
747 try {
748 if (mUpdatesStopped) {
749 mUpdatesStopped = false;
750 mBatteryProps.set(mLastBatteryProps);
751 processValuesLocked(false);
752 }
753 } finally {
754 Binder.restoreCallingIdentity(ident);
755 }
756 } break;
757 default:
758 return shell.handleDefaultCommands(cmd);
759 }
760 return 0;
761 }
762
763 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna4d82042012-10-02 19:11:19 -0700764 synchronized (mLock) {
765 if (args == null || args.length == 0 || "-a".equals(args[0])) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700766 pw.println("Current Battery Service state:");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700767 if (mUpdatesStopped) {
768 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
769 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700770 pw.println(" AC powered: " + mBatteryProps.chargerAcOnline);
771 pw.println(" USB powered: " + mBatteryProps.chargerUsbOnline);
772 pw.println(" Wireless powered: " + mBatteryProps.chargerWirelessOnline);
Adrian Roos7b043112015-07-10 13:00:33 -0700773 pw.println(" Max charging current: " + mBatteryProps.maxChargingCurrent);
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700774 pw.println(" Max charging voltage: " + mBatteryProps.maxChargingVoltage);
Todd Poynor26faecc2013-05-22 18:54:48 -0700775 pw.println(" status: " + mBatteryProps.batteryStatus);
776 pw.println(" health: " + mBatteryProps.batteryHealth);
777 pw.println(" present: " + mBatteryProps.batteryPresent);
778 pw.println(" level: " + mBatteryProps.batteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700779 pw.println(" scale: " + BATTERY_SCALE);
Todd Poynordf89ca32013-07-30 20:33:27 -0700780 pw.println(" voltage: " + mBatteryProps.batteryVoltage);
Todd Poynor26faecc2013-05-22 18:54:48 -0700781 pw.println(" temperature: " + mBatteryProps.batteryTemperature);
782 pw.println(" technology: " + mBatteryProps.batteryTechnology);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700783 } else {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700784 Shell shell = new Shell();
785 shell.exec(mBinderService, null, fd, null, args, new ResultReceiver(null));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700786 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800787 }
788 }
Joe Onoratode1b3592010-10-25 20:36:47 -0700789
Jeff Browna4d82042012-10-02 19:11:19 -0700790 private final class Led {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800791 private final Light mBatteryLight;
Joe Onoratode1b3592010-10-25 20:36:47 -0700792
Jeff Browna4d82042012-10-02 19:11:19 -0700793 private final int mBatteryLowARGB;
794 private final int mBatteryMediumARGB;
795 private final int mBatteryFullARGB;
796 private final int mBatteryLedOn;
797 private final int mBatteryLedOff;
798
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800799 public Led(Context context, LightsManager lights) {
800 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
Joe Onoratode1b3592010-10-25 20:36:47 -0700801
Jeff Browna4d82042012-10-02 19:11:19 -0700802 mBatteryLowARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700803 com.android.internal.R.integer.config_notificationsBatteryLowARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700804 mBatteryMediumARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700805 com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700806 mBatteryFullARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700807 com.android.internal.R.integer.config_notificationsBatteryFullARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700808 mBatteryLedOn = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700809 com.android.internal.R.integer.config_notificationsBatteryLedOn);
Jeff Browna4d82042012-10-02 19:11:19 -0700810 mBatteryLedOff = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700811 com.android.internal.R.integer.config_notificationsBatteryLedOff);
812 }
813
814 /**
815 * Synchronize on BatteryService.
816 */
Jeff Browna4d82042012-10-02 19:11:19 -0700817 public void updateLightsLocked() {
Todd Poynor26faecc2013-05-22 18:54:48 -0700818 final int level = mBatteryProps.batteryLevel;
819 final int status = mBatteryProps.batteryStatus;
Joe Onoratode1b3592010-10-25 20:36:47 -0700820 if (level < mLowBatteryWarningLevel) {
821 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
822 // Solid red when battery is charging
823 mBatteryLight.setColor(mBatteryLowARGB);
824 } else {
825 // Flash red when battery is low and not charging
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800826 mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
Joe Onoratode1b3592010-10-25 20:36:47 -0700827 mBatteryLedOn, mBatteryLedOff);
828 }
829 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
830 || status == BatteryManager.BATTERY_STATUS_FULL) {
831 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
832 // Solid green when full or charging and nearly full
833 mBatteryLight.setColor(mBatteryFullARGB);
834 } else {
835 // Solid orange when charging and halfway full
836 mBatteryLight.setColor(mBatteryMediumARGB);
837 }
838 } else {
839 // No lights if not charging and not low
840 mBatteryLight.turnOff();
841 }
842 }
843 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700844
845 private final class BatteryListener extends IBatteryPropertiesListener.Stub {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700846 @Override public void batteryPropertiesChanged(BatteryProperties props) {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800847 final long identity = Binder.clearCallingIdentity();
848 try {
849 BatteryService.this.update(props);
850 } finally {
851 Binder.restoreCallingIdentity(identity);
852 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700853 }
854 }
Jeff Brown21392762014-06-13 19:00:36 -0700855
856 private final class BinderService extends Binder {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700857 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Brown21392762014-06-13 19:00:36 -0700858 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
859 != PackageManager.PERMISSION_GRANTED) {
860
861 pw.println("Permission Denial: can't dump Battery service from from pid="
862 + Binder.getCallingPid()
863 + ", uid=" + Binder.getCallingUid());
864 return;
865 }
866
Dianne Hackborn2e441072015-10-28 18:00:57 -0700867 dumpInternal(fd, pw, args);
868 }
869
870 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
871 FileDescriptor err, String[] args, ResultReceiver resultReceiver) {
872 (new Shell()).exec(this, in, out, err, args, resultReceiver);
Jeff Brown21392762014-06-13 19:00:36 -0700873 }
874 }
875
876 private final class LocalService extends BatteryManagerInternal {
877 @Override
878 public boolean isPowered(int plugTypeSet) {
879 synchronized (mLock) {
880 return isPoweredLocked(plugTypeSet);
881 }
882 }
883
884 @Override
885 public int getPlugType() {
886 synchronized (mLock) {
887 return mPlugType;
888 }
889 }
890
891 @Override
892 public int getBatteryLevel() {
893 synchronized (mLock) {
894 return mBatteryProps.batteryLevel;
895 }
896 }
897
898 @Override
899 public boolean getBatteryLevelLow() {
900 synchronized (mLock) {
901 return mBatteryLevelLow;
902 }
903 }
904
905 @Override
906 public int getInvalidCharger() {
907 synchronized (mLock) {
908 return mInvalidCharger;
909 }
910 }
911 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800912}