blob: a8ccfc0305e57377552df57e43c6fcb8cd4946b1 [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
19import com.android.internal.app.IBatteryStats;
20import com.android.server.am.BatteryStatsService;
21
22import android.app.ActivityManagerNative;
23import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
26import android.content.pm.PackageManager;
27import android.os.BatteryManager;
28import android.os.Binder;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import android.os.IBinder;
Dan Egnor18e93962010-02-10 19:27:58 -080030import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import android.os.RemoteException;
32import android.os.ServiceManager;
33import android.os.SystemClock;
34import android.os.UEventObserver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.provider.Settings;
36import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080037import android.util.Slog;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038
39import java.io.File;
40import java.io.FileDescriptor;
41import java.io.FileInputStream;
42import java.io.FileOutputStream;
43import java.io.IOException;
44import java.io.PrintWriter;
45
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046
47/**
48 * <p>BatteryService monitors the charging status, and charge level of the device
49 * battery. When these values change this service broadcasts the new values
50 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
51 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
52 * BATTERY_CHANGED} action.</p>
53 * <p>The new values are stored in the Intent data and can be retrieved by
54 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
55 * following keys:</p>
56 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
57 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
58 * <p>&quot;status&quot; - String, the current charging status.<br />
59 * <p>&quot;health&quot; - String, the current battery health.<br />
60 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
61 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
62 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
63 * into an AC power adapter; 2 if plugged in via USB.</p>
64 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
65 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
66 * a degree Centigrade</p>
67 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
68 */
69class BatteryService extends Binder {
70 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -080071
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072 private static final boolean LOCAL_LOGV = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -080073
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 static final int BATTERY_SCALE = 100; // battery capacity is a percentage
75
76 // Used locally for determining when to make a last ditch effort to log
77 // discharge stats before the device dies.
Doug Zongkerab5c49c2009-12-04 10:31:43 -080078 private static final int CRITICAL_BATTERY_LEVEL = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
80 private static final int DUMP_MAX_LENGTH = 24 * 1024;
Dianne Hackborn6447ca32009-04-07 19:50:08 -070081 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "-u" };
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080082 private static final String BATTERY_STATS_SERVICE_NAME = "batteryinfo";
Doug Zongkerab5c49c2009-12-04 10:31:43 -080083
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084 private static final String DUMPSYS_DATA_PATH = "/data/system/";
85
86 // This should probably be exposed in the API, though it's not critical
87 private static final int BATTERY_PLUGGED_NONE = 0;
88
89 private final Context mContext;
90 private final IBatteryStats mBatteryStats;
Doug Zongkerab5c49c2009-12-04 10:31:43 -080091
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080092 private boolean mAcOnline;
93 private boolean mUsbOnline;
94 private int mBatteryStatus;
95 private int mBatteryHealth;
96 private boolean mBatteryPresent;
97 private int mBatteryLevel;
98 private int mBatteryVoltage;
99 private int mBatteryTemperature;
100 private String mBatteryTechnology;
101 private boolean mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400102 private boolean mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800103
104 private int mLastBatteryStatus;
105 private int mLastBatteryHealth;
106 private boolean mLastBatteryPresent;
107 private int mLastBatteryLevel;
108 private int mLastBatteryVoltage;
109 private int mLastBatteryTemperature;
110 private boolean mLastBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400111 private boolean mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400112
113 private int mLowBatteryWarningLevel;
114 private int mLowBatteryCloseWarningLevel;
115
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 private int mPlugType;
117 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 private long mDischargeStartTime;
120 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800121
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700122 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800123
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800124 public BatteryService(Context context) {
125 mContext = context;
126 mBatteryStats = BatteryStatsService.getService();
127
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400128 mLowBatteryWarningLevel = mContext.getResources().getInteger(
129 com.android.internal.R.integer.config_lowBatteryWarningLevel);
130 mLowBatteryCloseWarningLevel = mContext.getResources().getInteger(
131 com.android.internal.R.integer.config_lowBatteryCloseWarningLevel);
132
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400133 mPowerSupplyObserver.startObserving("SUBSYSTEM=power_supply");
134
135 // watch for invalid charger messages if the invalid_charger switch exists
136 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
137 mInvalidChargerObserver.startObserving("DEVPATH=/devices/virtual/switch/invalid_charger");
138 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139
140 // set initial status
141 update();
142 }
143
144 final boolean isPowered() {
145 // assume we are powered if battery state is unknown so the "stay on while plugged in" option will work.
Jean-Baptiste Querud3e803a2010-08-31 12:29:16 -0700146 return (mAcOnline || mUsbOnline || mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 }
148
149 final boolean isPowered(int plugTypeSet) {
150 // assume we are powered if battery state is unknown so
151 // the "stay on while plugged in" option will work.
152 if (mBatteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
153 return true;
154 }
155 if (plugTypeSet == 0) {
156 return false;
157 }
158 int plugTypeBit = 0;
Jean-Baptiste Querud3e803a2010-08-31 12:29:16 -0700159 if (mAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 plugTypeBit |= BatteryManager.BATTERY_PLUGGED_AC;
161 }
Jean-Baptiste Querud3e803a2010-08-31 12:29:16 -0700162 if (mUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800163 plugTypeBit |= BatteryManager.BATTERY_PLUGGED_USB;
164 }
165 return (plugTypeSet & plugTypeBit) != 0;
166 }
167
168 final int getPlugType() {
169 return mPlugType;
170 }
171
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400172 private UEventObserver mPowerSupplyObserver = new UEventObserver() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 @Override
174 public void onUEvent(UEventObserver.UEvent event) {
175 update();
176 }
177 };
178
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400179 private UEventObserver mInvalidChargerObserver = new UEventObserver() {
180 @Override
181 public void onUEvent(UEventObserver.UEvent event) {
182 boolean invalidCharger = "1".equals(event.get("SWITCH_STATE"));
183 if (mInvalidCharger != invalidCharger) {
184 mInvalidCharger = invalidCharger;
185 update();
186 }
187 }
188 };
189
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 // returns battery level as a percentage
191 final int getBatteryLevel() {
192 return mBatteryLevel;
193 }
194
Mike Lockwood07a500f2009-08-12 09:56:44 -0400195 void systemReady() {
196 // check our power situation now that it is safe to display the shutdown dialog.
197 shutdownIfNoPower();
Eric Olsen6a362a92010-03-26 15:38:41 -0700198 shutdownIfOverTemp();
Mike Lockwood07a500f2009-08-12 09:56:44 -0400199 }
200
201 private final void shutdownIfNoPower() {
202 // shut down gracefully if our battery is critically low and we are not powered.
203 // wait until the system has booted before attempting to display the shutdown dialog.
Jean-Baptiste Querud3e803a2010-08-31 12:29:16 -0700204 if (mBatteryLevel == 0 && !isPowered() && ActivityManagerNative.isSystemReady()) {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400205 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
206 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
207 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
208 mContext.startActivity(intent);
209 }
210 }
211
Eric Olsen6a362a92010-03-26 15:38:41 -0700212 private final void shutdownIfOverTemp() {
213 // shut down gracefully if temperature is too high (> 68.0C)
214 // wait until the system has booted before attempting to display the shutdown dialog.
215 if (mBatteryTemperature > 680 && ActivityManagerNative.isSystemReady()) {
216 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
217 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
218 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
219 mContext.startActivity(intent);
220 }
221 }
222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800223 private native void native_update();
224
225 private synchronized final void update() {
226 native_update();
227
The Android Open Source Project10592532009-03-18 17:39:46 -0700228 boolean logOutlier = false;
229 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 mBatteryLevelCritical = mBatteryLevel <= CRITICAL_BATTERY_LEVEL;
232 if (mAcOnline) {
233 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
234 } else if (mUsbOnline) {
235 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
236 } else {
237 mPlugType = BATTERY_PLUGGED_NONE;
238 }
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700239
240 // Let the battery stats keep track of the current level.
241 try {
242 mBatteryStats.setBatteryState(mBatteryStatus, mBatteryHealth,
243 mPlugType, mBatteryLevel, mBatteryTemperature,
244 mBatteryVoltage);
245 } catch (RemoteException e) {
246 // Should never happen.
247 }
248
249 shutdownIfNoPower();
250 shutdownIfOverTemp();
251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252 if (mBatteryStatus != mLastBatteryStatus ||
253 mBatteryHealth != mLastBatteryHealth ||
254 mBatteryPresent != mLastBatteryPresent ||
255 mBatteryLevel != mLastBatteryLevel ||
256 mPlugType != mLastPlugType ||
257 mBatteryVoltage != mLastBatteryVoltage ||
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400258 mBatteryTemperature != mLastBatteryTemperature ||
259 mInvalidCharger != mLastInvalidCharger) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800260
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 if (mPlugType != mLastPlugType) {
262 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
263 // discharging -> charging
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800264
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265 // There's no value in this data unless we've discharged at least once and the
266 // battery level has changed; so don't log until it does.
267 if (mDischargeStartTime != 0 && mDischargeStartLevel != mBatteryLevel) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700268 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
269 logOutlier = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800270 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800271 mDischargeStartLevel, mBatteryLevel);
272 // make sure we see a discharge event before logging again
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800273 mDischargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800274 }
275 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
276 // charging -> discharging or we just powered up
277 mDischargeStartTime = SystemClock.elapsedRealtime();
278 mDischargeStartLevel = mBatteryLevel;
279 }
280 }
281 if (mBatteryStatus != mLastBatteryStatus ||
282 mBatteryHealth != mLastBatteryHealth ||
283 mBatteryPresent != mLastBatteryPresent ||
284 mPlugType != mLastPlugType) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800285 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 mBatteryStatus, mBatteryHealth, mBatteryPresent ? 1 : 0,
287 mPlugType, mBatteryTechnology);
288 }
289 if (mBatteryLevel != mLastBatteryLevel ||
290 mBatteryVoltage != mLastBatteryVoltage ||
291 mBatteryTemperature != mLastBatteryTemperature) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800292 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 mBatteryLevel, mBatteryVoltage, mBatteryTemperature);
294 }
295 if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
296 mPlugType == BATTERY_PLUGGED_NONE) {
297 // We want to make sure we log discharge cycle outliers
298 // if the battery is about to die.
The Android Open Source Project10592532009-03-18 17:39:46 -0700299 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
300 logOutlier = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800302
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700303 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
304 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
305
306 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400307 * - is just un-plugged (previously was plugged) and battery level is
308 * less than or equal to WARNING, or
309 * - is not plugged and battery level falls to WARNING boundary
310 * (becomes <= mLowBatteryWarningLevel).
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700311 */
312 final boolean sendBatteryLow = !plugged
313 && mBatteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400314 && mBatteryLevel <= mLowBatteryWarningLevel
315 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800316
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700317 sendIntent();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800318
Christopher Tate06ba5542009-04-09 16:03:56 -0700319 // Separate broadcast is sent for power connected / not connected
320 // since the standard intent will not wake any applications and some
321 // applications may want to have smart behavior based on this.
Christopher Tate93dc9fe2009-07-16 13:25:49 -0700322 Intent statusIntent = new Intent();
323 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Christopher Tate06ba5542009-04-09 16:03:56 -0700324 if (mPlugType != 0 && mLastPlugType == 0) {
Christopher Tate93dc9fe2009-07-16 13:25:49 -0700325 statusIntent.setAction(Intent.ACTION_POWER_CONNECTED);
326 mContext.sendBroadcast(statusIntent);
Christopher Tate06ba5542009-04-09 16:03:56 -0700327 }
328 else if (mPlugType == 0 && mLastPlugType != 0) {
Christopher Tate93dc9fe2009-07-16 13:25:49 -0700329 statusIntent.setAction(Intent.ACTION_POWER_DISCONNECTED);
330 mContext.sendBroadcast(statusIntent);
Christopher Tate06ba5542009-04-09 16:03:56 -0700331 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200332
Mihai Predaa82842f2009-04-29 15:05:56 +0200333 if (sendBatteryLow) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700334 mSentLowBatteryBroadcast = true;
Christopher Tate93dc9fe2009-07-16 13:25:49 -0700335 statusIntent.setAction(Intent.ACTION_BATTERY_LOW);
336 mContext.sendBroadcast(statusIntent);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400337 } else if (mSentLowBatteryBroadcast && mLastBatteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700338 mSentLowBatteryBroadcast = false;
Christopher Tate93dc9fe2009-07-16 13:25:49 -0700339 statusIntent.setAction(Intent.ACTION_BATTERY_OKAY);
340 mContext.sendBroadcast(statusIntent);
Mihai Predaa82842f2009-04-29 15:05:56 +0200341 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800342
The Android Open Source Project10592532009-03-18 17:39:46 -0700343 // This needs to be done after sendIntent() so that we get the lastest battery stats.
344 if (logOutlier && dischargeDuration != 0) {
345 logOutlier(dischargeDuration);
346 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800347
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700348 mLastBatteryStatus = mBatteryStatus;
349 mLastBatteryHealth = mBatteryHealth;
350 mLastBatteryPresent = mBatteryPresent;
351 mLastBatteryLevel = mBatteryLevel;
352 mLastPlugType = mPlugType;
353 mLastBatteryVoltage = mBatteryVoltage;
354 mLastBatteryTemperature = mBatteryTemperature;
355 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400356 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800357 }
358 }
359
360 private final void sendIntent() {
361 // Pack up the values and broadcast them to everyone
362 Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800363 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
364 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800365
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 int icon = getIcon(mBatteryLevel);
367
Dianne Hackbornedd93162009-09-19 14:03:05 -0700368 intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryStatus);
369 intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryHealth);
370 intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryPresent);
371 intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryLevel);
372 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
373 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
374 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
375 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryVoltage);
376 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryTemperature);
377 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400378 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379
380 if (false) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800381 Slog.d(TAG, "updateBattery level:" + mBatteryLevel +
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800382 " scale:" + BATTERY_SCALE + " status:" + mBatteryStatus +
383 " health:" + mBatteryHealth + " present:" + mBatteryPresent +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800384 " voltage: " + mBatteryVoltage +
385 " temperature: " + mBatteryTemperature +
386 " technology: " + mBatteryTechnology +
387 " AC powered:" + mAcOnline + " USB powered:" + mUsbOnline +
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400388 " icon:" + icon + " invalid charger:" + mInvalidCharger);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800389 }
390
391 ActivityManagerNative.broadcastStickyIntent(intent, null);
392 }
393
394 private final void logBatteryStats() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800395 IBinder batteryInfoService = ServiceManager.getService(BATTERY_STATS_SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800396 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397
Dan Egnor18e93962010-02-10 19:27:58 -0800398 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
399 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
400
401 File dumpFile = null;
402 FileOutputStream dumpStream = null;
403 try {
404 // dump the service to a file
405 dumpFile = new File(DUMPSYS_DATA_PATH + BATTERY_STATS_SERVICE_NAME + ".dump");
406 dumpStream = new FileOutputStream(dumpFile);
407 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
408 dumpStream.getFD().sync();
409
410 // add dump file to drop box
411 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
412 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800413 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800414 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800415 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800416 } finally {
417 // make sure we clean up
418 if (dumpStream != null) {
419 try {
420 dumpStream.close();
421 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800422 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800423 }
Dan Egnor18e93962010-02-10 19:27:58 -0800424 }
425 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800426 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800427 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 }
429 }
430 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800431
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 private final void logOutlier(long duration) {
433 ContentResolver cr = mContext.getContentResolver();
Doug Zongker43866e02010-01-07 12:09:54 -0800434 String dischargeThresholdString = Settings.Secure.getString(cr,
435 Settings.Secure.BATTERY_DISCHARGE_THRESHOLD);
436 String durationThresholdString = Settings.Secure.getString(cr,
437 Settings.Secure.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800438
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800439 if (dischargeThresholdString != null && durationThresholdString != null) {
440 try {
441 long durationThreshold = Long.parseLong(durationThresholdString);
442 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800443 if (duration <= durationThreshold &&
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800444 mDischargeStartLevel - mBatteryLevel >= dischargeThreshold) {
445 // If the discharge cycle is bad enough we want to know about it.
446 logBatteryStats();
447 }
Joe Onorato8a9b2202010-02-26 18:56:32 -0800448 if (LOCAL_LOGV) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449 " discharge threshold: " + dischargeThreshold);
Joe Onorato8a9b2202010-02-26 18:56:32 -0800450 if (LOCAL_LOGV) Slog.v(TAG, "duration: " + duration + " discharge: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800451 (mDischargeStartLevel - mBatteryLevel));
452 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800453 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800454 durationThresholdString + " or " + dischargeThresholdString);
455 return;
456 }
457 }
458 }
459
460 private final int getIcon(int level) {
461 if (mBatteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
462 return com.android.internal.R.drawable.stat_sys_battery_charge;
463 } else if (mBatteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING ||
464 mBatteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING ||
465 mBatteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
466 return com.android.internal.R.drawable.stat_sys_battery;
467 } else {
468 return com.android.internal.R.drawable.stat_sys_battery_unknown;
469 }
470 }
471
472 @Override
473 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
474 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
475 != PackageManager.PERMISSION_GRANTED) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800476
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800477 pw.println("Permission Denial: can't dump Battery service from from pid="
478 + Binder.getCallingPid()
479 + ", uid=" + Binder.getCallingUid());
480 return;
481 }
482
483 synchronized (this) {
484 pw.println("Current Battery Service state:");
485 pw.println(" AC powered: " + mAcOnline);
486 pw.println(" USB powered: " + mUsbOnline);
487 pw.println(" status: " + mBatteryStatus);
488 pw.println(" health: " + mBatteryHealth);
489 pw.println(" present: " + mBatteryPresent);
490 pw.println(" level: " + mBatteryLevel);
491 pw.println(" scale: " + BATTERY_SCALE);
492 pw.println(" voltage:" + mBatteryVoltage);
493 pw.println(" temperature: " + mBatteryTemperature);
494 pw.println(" technology: " + mBatteryTechnology);
495 }
496 }
497}