blob: aeb195fe945e453b68db5c602f891ad1eb3bcaba [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;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import com.android.internal.app.IBatteryStats;
22import com.android.server.am.BatteryStatsService;
Adam Lesinskief2ea1f2013-12-05 16:48:06 -080023import com.android.server.lights.Light;
24import com.android.server.lights.LightsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025
26import android.app.ActivityManagerNative;
27import android.content.ContentResolver;
28import android.content.Context;
29import android.content.Intent;
30import android.content.pm.PackageManager;
31import android.os.BatteryManager;
Todd Poynor26faecc2013-05-22 18:54:48 -070032import android.os.BatteryProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033import android.os.Binder;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070034import android.os.FileUtils;
Jeff Brown605ea692012-10-05 16:33:10 -070035import android.os.Handler;
Todd Poynor26faecc2013-05-22 18:54:48 -070036import android.os.IBatteryPropertiesListener;
37import android.os.IBatteryPropertiesRegistrar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.IBinder;
Dan Egnor18e93962010-02-10 19:27:58 -080039import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.os.RemoteException;
41import android.os.ServiceManager;
42import android.os.SystemClock;
43import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070044import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.provider.Settings;
46import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080047import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048
49import java.io.File;
50import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import java.io.FileOutputStream;
52import java.io.IOException;
53import java.io.PrintWriter;
54
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055
56/**
57 * <p>BatteryService monitors the charging status, and charge level of the device
58 * battery. When these values change this service broadcasts the new values
59 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
60 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
61 * BATTERY_CHANGED} action.</p>
62 * <p>The new values are stored in the Intent data and can be retrieved by
63 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
64 * following keys:</p>
65 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
66 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
67 * <p>&quot;status&quot; - String, the current charging status.<br />
68 * <p>&quot;health&quot; - String, the current battery health.<br />
69 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
70 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
71 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
72 * into an AC power adapter; 2 if plugged in via USB.</p>
73 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
74 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
75 * a degree Centigrade</p>
76 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
Jeff Brown605ea692012-10-05 16:33:10 -070077 *
78 * <p>
79 * The battery service may be called by the power manager while holding its locks so
80 * we take care to post all outcalls into the activity manager to a handler.
81 *
82 * FIXME: Ideally the power manager would perform all of its calls into the battery
83 * service asynchronously itself.
84 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080085 */
Jeff Browna4d82042012-10-02 19:11:19 -070086public final class BatteryService extends Binder {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080087 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -080088
Jeff Browna4d82042012-10-02 19:11:19 -070089 private static final boolean DEBUG = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -080090
Jeff Browna4d82042012-10-02 19:11:19 -070091 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092
93 // Used locally for determining when to make a last ditch effort to log
94 // discharge stats before the device dies.
Joe Onorato4ca7f1e2010-10-27 15:32:23 -070095 private int mCriticalBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096
97 private static final int DUMP_MAX_LENGTH = 24 * 1024;
Jeff Sharkeyec43a6b2013-04-30 13:33:18 -070098 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
Doug Zongkerab5c49c2009-12-04 10:31:43 -080099
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100 private static final String DUMPSYS_DATA_PATH = "/data/system/";
101
102 // This should probably be exposed in the API, though it's not critical
103 private static final int BATTERY_PLUGGED_NONE = 0;
104
105 private final Context mContext;
106 private final IBatteryStats mBatteryStats;
Jeff Brown605ea692012-10-05 16:33:10 -0700107 private final Handler mHandler;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800108
Jeff Browna4d82042012-10-02 19:11:19 -0700109 private final Object mLock = new Object();
110
Todd Poynor26faecc2013-05-22 18:54:48 -0700111 private BatteryProperties mBatteryProps;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800112 private final BatteryProperties mLastBatteryProps = new BatteryProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 private boolean mBatteryLevelCritical;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 private int mLastBatteryStatus;
115 private int mLastBatteryHealth;
116 private boolean mLastBatteryPresent;
117 private int mLastBatteryLevel;
118 private int mLastBatteryVoltage;
119 private int mLastBatteryTemperature;
120 private boolean mLastBatteryLevelCritical;
Jeff Browna4d82042012-10-02 19:11:19 -0700121
122 private int mInvalidCharger;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700123 private int mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400124
125 private int mLowBatteryWarningLevel;
126 private int mLowBatteryCloseWarningLevel;
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700127 private int mShutdownBatteryTemperature;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400128
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129 private int mPlugType;
130 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800131
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700132 private boolean mBatteryLevelLow;
133
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 private long mDischargeStartTime;
135 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800136
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700137 private boolean mUpdatesStopped;
138
Joe Onoratode1b3592010-10-25 20:36:47 -0700139 private Led mLed;
140
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700141 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800142
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800143 public BatteryService(Context context, LightsManager lightsManager) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800144 mContext = context;
Jeff Brown605ea692012-10-05 16:33:10 -0700145 mHandler = new Handler(true /*async*/);
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800146 mLed = new Led(context, lightsManager);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 mBatteryStats = BatteryStatsService.getService();
148
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700149 mCriticalBatteryLevel = mContext.getResources().getInteger(
150 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400151 mLowBatteryWarningLevel = mContext.getResources().getInteger(
152 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Dianne Hackborn14272302014-06-10 23:13:02 -0700153 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
154 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700155 mShutdownBatteryTemperature = mContext.getResources().getInteger(
156 com.android.internal.R.integer.config_shutdownBatteryTemperature);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400157
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400158 // watch for invalid charger messages if the invalid_charger switch exists
159 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
Jeff Browna4d82042012-10-02 19:11:19 -0700160 mInvalidChargerObserver.startObserving(
161 "DEVPATH=/devices/virtual/switch/invalid_charger");
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400162 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163
Todd Poynor0edc5b52013-10-22 17:53:13 -0700164 IBinder b = ServiceManager.getService("batteryproperties");
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800165 final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
166 IBatteryPropertiesRegistrar.Stub.asInterface(b);
Todd Poynor26faecc2013-05-22 18:54:48 -0700167 try {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800168 batteryPropertiesRegistrar.registerListener(new BatteryListener());
Todd Poynor26faecc2013-05-22 18:54:48 -0700169 } catch (RemoteException e) {
170 // Should never happen.
Jeff Browna4d82042012-10-02 19:11:19 -0700171 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 }
173
Jeff Browna4d82042012-10-02 19:11:19 -0700174 void systemReady() {
175 // check our power situation now that it is safe to display the shutdown dialog.
176 synchronized (mLock) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700177 ContentObserver obs = new ContentObserver(mHandler) {
178 @Override
179 public void onChange(boolean selfChange) {
180 synchronized (mLock) {
181 updateBatteryWarningLevelLocked();
182 }
183 }
184 };
185 final ContentResolver resolver = mContext.getContentResolver();
186 resolver.registerContentObserver(Settings.Global.getUriFor(
187 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
188 false, obs, UserHandle.USER_ALL);
189 updateBatteryWarningLevelLocked();
Jeff Browna4d82042012-10-02 19:11:19 -0700190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 }
192
Dianne Hackborn14272302014-06-10 23:13:02 -0700193 void updateBatteryWarningLevelLocked() {
194 final ContentResolver resolver = mContext.getContentResolver();
195 int defWarnLevel = mContext.getResources().getInteger(
196 com.android.internal.R.integer.config_lowBatteryWarningLevel);
197 mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
198 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
199 if (mLowBatteryWarningLevel == 0) {
200 mLowBatteryWarningLevel = defWarnLevel;
201 }
202 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
203 mLowBatteryWarningLevel = mCriticalBatteryLevel;
204 }
205 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
206 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
207 processValuesLocked(true);
208 }
209
Jeff Browna4d82042012-10-02 19:11:19 -0700210 /**
211 * Returns true if the device is plugged into any of the specified plug types.
212 */
213 public boolean isPowered(int plugTypeSet) {
214 synchronized (mLock) {
215 return isPoweredLocked(plugTypeSet);
216 }
217 }
218
219 private boolean isPoweredLocked(int plugTypeSet) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800220 // assume we are powered if battery state is unknown so
221 // the "stay on while plugged in" option will work.
Todd Poynor26faecc2013-05-22 18:54:48 -0700222 if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 return true;
224 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700225 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700226 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800227 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700228 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700229 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800230 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700231 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700232 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800233 }
Jeff Browna4d82042012-10-02 19:11:19 -0700234 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 }
236
Jeff Browna4d82042012-10-02 19:11:19 -0700237 /**
Jeff Brownf3fb8952012-10-02 20:57:05 -0700238 * Returns the current plug type.
239 */
240 public int getPlugType() {
241 synchronized (mLock) {
242 return mPlugType;
243 }
244 }
245
246 /**
Jeff Browna4d82042012-10-02 19:11:19 -0700247 * Returns battery level as a percentage.
248 */
249 public int getBatteryLevel() {
250 synchronized (mLock) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700251 return mBatteryProps.batteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 }
Jeff Browna4d82042012-10-02 19:11:19 -0700253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800254
Jeff Browna4d82042012-10-02 19:11:19 -0700255 /**
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700256 * Returns whether we currently consider the battery level to be low.
Jeff Browna4d82042012-10-02 19:11:19 -0700257 */
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700258 public boolean getBatteryLevelLow() {
Jeff Browna4d82042012-10-02 19:11:19 -0700259 synchronized (mLock) {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700260 return mBatteryLevelLow;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400261 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 }
263
Dianne Hackborn14272302014-06-10 23:13:02 -0700264 public boolean shouldSendBatteryLowLocked() {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700265 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
266 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
267
268 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
269 * - is just un-plugged (previously was plugged) and battery level is
270 * less than or equal to WARNING, or
271 * - is not plugged and battery level falls to WARNING boundary
272 * (becomes <= mLowBatteryWarningLevel).
273 */
274 return !plugged
275 && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
276 && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
277 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
278 }
279
Svetoslav6a08a122013-05-03 11:24:26 -0700280 /**
281 * Returns a non-zero value if an unsupported charger is attached.
282 */
283 public int getInvalidCharger() {
284 synchronized (mLock) {
285 return mInvalidCharger;
286 }
287 }
288
Jeff Browna4d82042012-10-02 19:11:19 -0700289 private void shutdownIfNoPowerLocked() {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400290 // shut down gracefully if our battery is critically low and we are not powered.
291 // wait until the system has booted before attempting to display the shutdown dialog.
Todd Poynor26faecc2013-05-22 18:54:48 -0700292 if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
Jeff Brown605ea692012-10-05 16:33:10 -0700293 mHandler.post(new Runnable() {
294 @Override
295 public void run() {
296 if (ActivityManagerNative.isSystemReady()) {
297 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
298 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
299 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
300 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
301 }
302 }
303 });
Mike Lockwood07a500f2009-08-12 09:56:44 -0400304 }
305 }
306
Jeff Browna4d82042012-10-02 19:11:19 -0700307 private void shutdownIfOverTempLocked() {
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700308 // shut down gracefully if temperature is too high (> 68.0C by default)
309 // wait until the system has booted before attempting to display the
310 // shutdown dialog.
Todd Poynor26faecc2013-05-22 18:54:48 -0700311 if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
Jeff Brown605ea692012-10-05 16:33:10 -0700312 mHandler.post(new Runnable() {
313 @Override
314 public void run() {
315 if (ActivityManagerNative.isSystemReady()) {
316 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
317 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
318 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
319 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
320 }
321 }
322 });
Eric Olsen6a362a92010-03-26 15:38:41 -0700323 }
324 }
325
Todd Poynor26faecc2013-05-22 18:54:48 -0700326 private void update(BatteryProperties props) {
327 synchronized (mLock) {
328 if (!mUpdatesStopped) {
329 mBatteryProps = props;
330 // Process the new values.
Dianne Hackborn14272302014-06-10 23:13:02 -0700331 processValuesLocked(false);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800332 } else {
333 mLastBatteryProps.set(props);
Todd Poynor26faecc2013-05-22 18:54:48 -0700334 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700335 }
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700336 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337
Dianne Hackborn14272302014-06-10 23:13:02 -0700338 private void processValuesLocked(boolean force) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700339 boolean logOutlier = false;
340 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700341
Todd Poynor26faecc2013-05-22 18:54:48 -0700342 mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
343 if (mBatteryProps.chargerAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
Todd Poynor26faecc2013-05-22 18:54:48 -0700345 } else if (mBatteryProps.chargerUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
Todd Poynor26faecc2013-05-22 18:54:48 -0700347 } else if (mBatteryProps.chargerWirelessOnline) {
Brian Muramatsu37a37f42012-08-14 15:21:02 -0700348 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 } else {
350 mPlugType = BATTERY_PLUGGED_NONE;
351 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700352
Jeff Browna4d82042012-10-02 19:11:19 -0700353 if (DEBUG) {
354 Slog.d(TAG, "Processing new values: "
Todd Poynor26faecc2013-05-22 18:54:48 -0700355 + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
356 + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
357 + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
358 + ", batteryStatus=" + mBatteryProps.batteryStatus
359 + ", batteryHealth=" + mBatteryProps.batteryHealth
360 + ", batteryPresent=" + mBatteryProps.batteryPresent
361 + ", batteryLevel=" + mBatteryProps.batteryLevel
362 + ", batteryTechnology=" + mBatteryProps.batteryTechnology
363 + ", batteryVoltage=" + mBatteryProps.batteryVoltage
364 + ", batteryTemperature=" + mBatteryProps.batteryTemperature
Jeff Browna4d82042012-10-02 19:11:19 -0700365 + ", mBatteryLevelCritical=" + mBatteryLevelCritical
366 + ", mPlugType=" + mPlugType);
367 }
368
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700369 // Let the battery stats keep track of the current level.
370 try {
Todd Poynor26faecc2013-05-22 18:54:48 -0700371 mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
372 mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
373 mBatteryProps.batteryVoltage);
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700374 } catch (RemoteException e) {
375 // Should never happen.
376 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700377
Jeff Browna4d82042012-10-02 19:11:19 -0700378 shutdownIfNoPowerLocked();
379 shutdownIfOverTempLocked();
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700380
Dianne Hackborn14272302014-06-10 23:13:02 -0700381 if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
Todd Poynor26faecc2013-05-22 18:54:48 -0700382 mBatteryProps.batteryHealth != mLastBatteryHealth ||
383 mBatteryProps.batteryPresent != mLastBatteryPresent ||
384 mBatteryProps.batteryLevel != mLastBatteryLevel ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800385 mPlugType != mLastPlugType ||
Todd Poynor26faecc2013-05-22 18:54:48 -0700386 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
387 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
Dianne Hackborn14272302014-06-10 23:13:02 -0700388 mInvalidCharger != mLastInvalidCharger)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800389
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800390 if (mPlugType != mLastPlugType) {
391 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
392 // discharging -> charging
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800393
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800394 // There's no value in this data unless we've discharged at least once and the
395 // battery level has changed; so don't log until it does.
Todd Poynor26faecc2013-05-22 18:54:48 -0700396 if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryProps.batteryLevel) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700397 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
398 logOutlier = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800399 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
Todd Poynor26faecc2013-05-22 18:54:48 -0700400 mDischargeStartLevel, mBatteryProps.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800401 // make sure we see a discharge event before logging again
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800402 mDischargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
405 // charging -> discharging or we just powered up
406 mDischargeStartTime = SystemClock.elapsedRealtime();
Todd Poynor26faecc2013-05-22 18:54:48 -0700407 mDischargeStartLevel = mBatteryProps.batteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800408 }
409 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700410 if (mBatteryProps.batteryStatus != mLastBatteryStatus ||
411 mBatteryProps.batteryHealth != mLastBatteryHealth ||
412 mBatteryProps.batteryPresent != mLastBatteryPresent ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 mPlugType != mLastPlugType) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800414 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
Todd Poynor26faecc2013-05-22 18:54:48 -0700415 mBatteryProps.batteryStatus, mBatteryProps.batteryHealth, mBatteryProps.batteryPresent ? 1 : 0,
416 mPlugType, mBatteryProps.batteryTechnology);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800417 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700418 if (mBatteryProps.batteryLevel != mLastBatteryLevel) {
Dianne Hackborncf1171642013-07-12 17:26:02 -0700419 // Don't do this just from voltage or temperature changes, that is
420 // too noisy.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800421 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
Todd Poynor26faecc2013-05-22 18:54:48 -0700422 mBatteryProps.batteryLevel, mBatteryProps.batteryVoltage, mBatteryProps.batteryTemperature);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 }
424 if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
425 mPlugType == BATTERY_PLUGGED_NONE) {
426 // We want to make sure we log discharge cycle outliers
427 // if the battery is about to die.
The Android Open Source Project10592532009-03-18 17:39:46 -0700428 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
429 logOutlier = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800431
Dianne Hackborn14272302014-06-10 23:13:02 -0700432 if (!mBatteryLevelLow) {
433 // Should we now switch in to low battery mode?
434 if (mPlugType == BATTERY_PLUGGED_NONE
435 && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel) {
436 mBatteryLevelLow = true;
437 }
438 } else {
439 // Should we now switch out of low battery mode?
440 if (mPlugType != BATTERY_PLUGGED_NONE) {
441 mBatteryLevelLow = false;
442 } else if (mBatteryProps.batteryLevel >= mLowBatteryCloseWarningLevel) {
443 mBatteryLevelLow = false;
444 } else if (force && mBatteryProps.batteryLevel >= mLowBatteryWarningLevel) {
445 // If being forced, the previous state doesn't matter, we will just
446 // absolutely check to see if we are now above the warning level.
447 mBatteryLevelLow = false;
448 }
449 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800450
Jeff Browna4d82042012-10-02 19:11:19 -0700451 sendIntentLocked();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800452
Christopher Tate06ba5542009-04-09 16:03:56 -0700453 // Separate broadcast is sent for power connected / not connected
454 // since the standard intent will not wake any applications and some
455 // applications may want to have smart behavior based on this.
456 if (mPlugType != 0 && mLastPlugType == 0) {
Jeff Brown605ea692012-10-05 16:33:10 -0700457 mHandler.post(new Runnable() {
458 @Override
459 public void run() {
460 Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
461 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
462 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
463 }
464 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700465 }
466 else if (mPlugType == 0 && mLastPlugType != 0) {
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_POWER_DISCONNECTED);
471 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
472 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
473 }
474 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700475 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200476
Dianne Hackborn14272302014-06-10 23:13:02 -0700477 if (shouldSendBatteryLowLocked()) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700478 mSentLowBatteryBroadcast = true;
Jeff Brown605ea692012-10-05 16:33:10 -0700479 mHandler.post(new Runnable() {
480 @Override
481 public void run() {
482 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
483 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
484 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
485 }
486 });
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400487 } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700488 mSentLowBatteryBroadcast = false;
Jeff Brown605ea692012-10-05 16:33:10 -0700489 mHandler.post(new Runnable() {
490 @Override
491 public void run() {
492 Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
493 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
494 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
495 }
496 });
Mihai Predaa82842f2009-04-29 15:05:56 +0200497 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800498
Joe Onoratode1b3592010-10-25 20:36:47 -0700499 // Update the battery LED
500 mLed.updateLightsLocked();
501
The Android Open Source Project10592532009-03-18 17:39:46 -0700502 // This needs to be done after sendIntent() so that we get the lastest battery stats.
503 if (logOutlier && dischargeDuration != 0) {
Jeff Browna4d82042012-10-02 19:11:19 -0700504 logOutlierLocked(dischargeDuration);
The Android Open Source Project10592532009-03-18 17:39:46 -0700505 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800506
Todd Poynor26faecc2013-05-22 18:54:48 -0700507 mLastBatteryStatus = mBatteryProps.batteryStatus;
508 mLastBatteryHealth = mBatteryProps.batteryHealth;
509 mLastBatteryPresent = mBatteryProps.batteryPresent;
510 mLastBatteryLevel = mBatteryProps.batteryLevel;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700511 mLastPlugType = mPlugType;
Todd Poynor26faecc2013-05-22 18:54:48 -0700512 mLastBatteryVoltage = mBatteryProps.batteryVoltage;
513 mLastBatteryTemperature = mBatteryProps.batteryTemperature;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700514 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400515 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
517 }
518
Jeff Browna4d82042012-10-02 19:11:19 -0700519 private void sendIntentLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800520 // Pack up the values and broadcast them to everyone
Jeff Brown605ea692012-10-05 16:33:10 -0700521 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800522 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
523 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800524
Todd Poynor26faecc2013-05-22 18:54:48 -0700525 int icon = getIconLocked(mBatteryProps.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526
Todd Poynor26faecc2013-05-22 18:54:48 -0700527 intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
528 intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
529 intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
530 intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
Dianne Hackbornedd93162009-09-19 14:03:05 -0700531 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
532 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
533 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
Todd Poynor26faecc2013-05-22 18:54:48 -0700534 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
535 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
536 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400537 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800538
Jeff Browna4d82042012-10-02 19:11:19 -0700539 if (DEBUG) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700540 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel +
541 ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
542 ", health:" + mBatteryProps.batteryHealth + ", present:" + mBatteryProps.batteryPresent +
543 ", voltage: " + mBatteryProps.batteryVoltage +
544 ", temperature: " + mBatteryProps.batteryTemperature +
545 ", technology: " + mBatteryProps.batteryTechnology +
546 ", AC powered:" + mBatteryProps.chargerAcOnline + ", USB powered:" + mBatteryProps.chargerUsbOnline +
547 ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
Jeff Browna4d82042012-10-02 19:11:19 -0700548 ", icon:" + icon + ", invalid charger:" + mInvalidCharger);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800549 }
550
Jeff Brown605ea692012-10-05 16:33:10 -0700551 mHandler.post(new Runnable() {
552 @Override
553 public void run() {
554 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
555 }
556 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 }
558
Jeff Browna4d82042012-10-02 19:11:19 -0700559 private void logBatteryStatsLocked() {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700560 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800561 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800562
Dan Egnor18e93962010-02-10 19:27:58 -0800563 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
564 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
565
566 File dumpFile = null;
567 FileOutputStream dumpStream = null;
568 try {
569 // dump the service to a file
Dianne Hackborn8c841092013-06-24 13:46:13 -0700570 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
Dan Egnor18e93962010-02-10 19:27:58 -0800571 dumpStream = new FileOutputStream(dumpFile);
572 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -0700573 FileUtils.sync(dumpStream);
Dan Egnor18e93962010-02-10 19:27:58 -0800574
575 // add dump file to drop box
576 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
577 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800578 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800579 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800580 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800581 } finally {
582 // make sure we clean up
583 if (dumpStream != null) {
584 try {
585 dumpStream.close();
586 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800587 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800588 }
Dan Egnor18e93962010-02-10 19:27:58 -0800589 }
590 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800591 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800592 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800593 }
594 }
595 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800596
Jeff Browna4d82042012-10-02 19:11:19 -0700597 private void logOutlierLocked(long duration) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 ContentResolver cr = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -0700599 String dischargeThresholdString = Settings.Global.getString(cr,
600 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
601 String durationThresholdString = Settings.Global.getString(cr,
602 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800603
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800604 if (dischargeThresholdString != null && durationThresholdString != null) {
605 try {
606 long durationThreshold = Long.parseLong(durationThresholdString);
607 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608 if (duration <= durationThreshold &&
Todd Poynor26faecc2013-05-22 18:54:48 -0700609 mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 // If the discharge cycle is bad enough we want to know about it.
Jeff Browna4d82042012-10-02 19:11:19 -0700611 logBatteryStatsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800612 }
Jeff Browna4d82042012-10-02 19:11:19 -0700613 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 " discharge threshold: " + dischargeThreshold);
Jeff Browna4d82042012-10-02 19:11:19 -0700615 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
Todd Poynor26faecc2013-05-22 18:54:48 -0700616 (mDischargeStartLevel - mBatteryProps.batteryLevel));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800617 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800618 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 durationThresholdString + " or " + dischargeThresholdString);
620 return;
621 }
622 }
623 }
624
Jeff Browna4d82042012-10-02 19:11:19 -0700625 private int getIconLocked(int level) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700626 if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 return com.android.internal.R.drawable.stat_sys_battery_charge;
Todd Poynor26faecc2013-05-22 18:54:48 -0700628 } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 return com.android.internal.R.drawable.stat_sys_battery;
Todd Poynor26faecc2013-05-22 18:54:48 -0700630 } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
631 || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
Jeff Browna4d82042012-10-02 19:11:19 -0700632 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
Todd Poynor26faecc2013-05-22 18:54:48 -0700633 && mBatteryProps.batteryLevel >= 100) {
Joe Onorato794be402010-11-21 19:22:25 -0800634 return com.android.internal.R.drawable.stat_sys_battery_charge;
635 } else {
636 return com.android.internal.R.drawable.stat_sys_battery;
637 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 } else {
639 return com.android.internal.R.drawable.stat_sys_battery_unknown;
640 }
641 }
642
643 @Override
644 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
645 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
646 != PackageManager.PERMISSION_GRANTED) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 pw.println("Permission Denial: can't dump Battery service from from pid="
649 + Binder.getCallingPid()
650 + ", uid=" + Binder.getCallingUid());
651 return;
652 }
653
Jeff Browna4d82042012-10-02 19:11:19 -0700654 synchronized (mLock) {
655 if (args == null || args.length == 0 || "-a".equals(args[0])) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700656 pw.println("Current Battery Service state:");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700657 if (mUpdatesStopped) {
658 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
659 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700660 pw.println(" AC powered: " + mBatteryProps.chargerAcOnline);
661 pw.println(" USB powered: " + mBatteryProps.chargerUsbOnline);
662 pw.println(" Wireless powered: " + mBatteryProps.chargerWirelessOnline);
663 pw.println(" status: " + mBatteryProps.batteryStatus);
664 pw.println(" health: " + mBatteryProps.batteryHealth);
665 pw.println(" present: " + mBatteryProps.batteryPresent);
666 pw.println(" level: " + mBatteryProps.batteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700667 pw.println(" scale: " + BATTERY_SCALE);
Todd Poynordf89ca32013-07-30 20:33:27 -0700668 pw.println(" voltage: " + mBatteryProps.batteryVoltage);
Todd Poynor26faecc2013-05-22 18:54:48 -0700669 pw.println(" temperature: " + mBatteryProps.batteryTemperature);
670 pw.println(" technology: " + mBatteryProps.batteryTechnology);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700671 } else if (args.length == 3 && "set".equals(args[0])) {
672 String key = args[1];
673 String value = args[2];
674 try {
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800675 if (!mUpdatesStopped) {
676 mLastBatteryProps.set(mBatteryProps);
677 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700678 boolean update = true;
679 if ("ac".equals(key)) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700680 mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700681 } else if ("usb".equals(key)) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700682 mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700683 } else if ("wireless".equals(key)) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700684 mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700685 } else if ("status".equals(key)) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700686 mBatteryProps.batteryStatus = Integer.parseInt(value);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700687 } else if ("level".equals(key)) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700688 mBatteryProps.batteryLevel = Integer.parseInt(value);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700689 } else if ("invalid".equals(key)) {
690 mInvalidCharger = Integer.parseInt(value);
691 } else {
692 pw.println("Unknown set option: " + key);
693 update = false;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700694 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700695 if (update) {
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700696 long ident = Binder.clearCallingIdentity();
697 try {
698 mUpdatesStopped = true;
Dianne Hackborn14272302014-06-10 23:13:02 -0700699 processValuesLocked(false);
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700700 } finally {
701 Binder.restoreCallingIdentity(ident);
702 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700703 }
704 } catch (NumberFormatException ex) {
705 pw.println("Bad value: " + value);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700706 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700707 } else if (args.length == 1 && "reset".equals(args[0])) {
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700708 long ident = Binder.clearCallingIdentity();
709 try {
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800710 if (mUpdatesStopped) {
Dianne Hackbornd45665b2014-02-26 12:35:32 -0800711 mUpdatesStopped = false;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800712 mBatteryProps.set(mLastBatteryProps);
Dianne Hackborn14272302014-06-10 23:13:02 -0700713 processValuesLocked(false);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800714 }
Dianne Hackborn053f61d2013-06-26 18:07:43 -0700715 } finally {
716 Binder.restoreCallingIdentity(ident);
717 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700718 } else {
719 pw.println("Dump current battery state, or:");
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800720 pw.println(" set [ac|usb|wireless|status|level|invalid] <value>");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700721 pw.println(" reset");
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 }
724 }
Joe Onoratode1b3592010-10-25 20:36:47 -0700725
Jeff Browna4d82042012-10-02 19:11:19 -0700726 private final UEventObserver mInvalidChargerObserver = new UEventObserver() {
727 @Override
728 public void onUEvent(UEventObserver.UEvent event) {
729 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
730 synchronized (mLock) {
731 if (mInvalidCharger != invalidCharger) {
732 mInvalidCharger = invalidCharger;
Jeff Browna4d82042012-10-02 19:11:19 -0700733 }
734 }
735 }
736 };
Joe Onoratode1b3592010-10-25 20:36:47 -0700737
Jeff Browna4d82042012-10-02 19:11:19 -0700738 private final class Led {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800739 private final Light mBatteryLight;
Joe Onoratode1b3592010-10-25 20:36:47 -0700740
Jeff Browna4d82042012-10-02 19:11:19 -0700741 private final int mBatteryLowARGB;
742 private final int mBatteryMediumARGB;
743 private final int mBatteryFullARGB;
744 private final int mBatteryLedOn;
745 private final int mBatteryLedOff;
746
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800747 public Led(Context context, LightsManager lights) {
748 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
Joe Onoratode1b3592010-10-25 20:36:47 -0700749
Jeff Browna4d82042012-10-02 19:11:19 -0700750 mBatteryLowARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700751 com.android.internal.R.integer.config_notificationsBatteryLowARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700752 mBatteryMediumARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700753 com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700754 mBatteryFullARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700755 com.android.internal.R.integer.config_notificationsBatteryFullARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700756 mBatteryLedOn = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700757 com.android.internal.R.integer.config_notificationsBatteryLedOn);
Jeff Browna4d82042012-10-02 19:11:19 -0700758 mBatteryLedOff = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700759 com.android.internal.R.integer.config_notificationsBatteryLedOff);
760 }
761
762 /**
763 * Synchronize on BatteryService.
764 */
Jeff Browna4d82042012-10-02 19:11:19 -0700765 public void updateLightsLocked() {
Todd Poynor26faecc2013-05-22 18:54:48 -0700766 final int level = mBatteryProps.batteryLevel;
767 final int status = mBatteryProps.batteryStatus;
Joe Onoratode1b3592010-10-25 20:36:47 -0700768 if (level < mLowBatteryWarningLevel) {
769 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
770 // Solid red when battery is charging
771 mBatteryLight.setColor(mBatteryLowARGB);
772 } else {
773 // Flash red when battery is low and not charging
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800774 mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
Joe Onoratode1b3592010-10-25 20:36:47 -0700775 mBatteryLedOn, mBatteryLedOff);
776 }
777 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
778 || status == BatteryManager.BATTERY_STATUS_FULL) {
779 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
780 // Solid green when full or charging and nearly full
781 mBatteryLight.setColor(mBatteryFullARGB);
782 } else {
783 // Solid orange when charging and halfway full
784 mBatteryLight.setColor(mBatteryMediumARGB);
785 }
786 } else {
787 // No lights if not charging and not low
788 mBatteryLight.turnOff();
789 }
790 }
791 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700792
793 private final class BatteryListener extends IBatteryPropertiesListener.Stub {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800794 @Override
Todd Poynor26faecc2013-05-22 18:54:48 -0700795 public void batteryPropertiesChanged(BatteryProperties props) {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800796 final long identity = Binder.clearCallingIdentity();
797 try {
798 BatteryService.this.update(props);
799 } finally {
800 Binder.restoreCallingIdentity(identity);
801 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700802 }
803 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804}