blob: 6248cab0ce107e24722527b0b36ce240b4c052b8 [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
Sudheer Shankafc46e9b2016-10-21 17:55:27 -070019import android.app.ActivityManagerInternal;
Dianne Hackborn14272302014-06-10 23:13:02 -070020import android.database.ContentObserver;
Dianne Hackborn8c841092013-06-24 13:46:13 -070021import android.os.BatteryStats;
Jeff Brown21392762014-06-13 19:00:36 -070022
Dianne Hackborn2e441072015-10-28 18:00:57 -070023import android.os.ResultReceiver;
Dianne Hackborn354736e2016-08-22 17:00:05 -070024import android.os.ShellCallback;
Dianne Hackborn2e441072015-10-28 18:00:57 -070025import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080026import com.android.internal.app.IBatteryStats;
27import com.android.server.am.BatteryStatsService;
Adam Lesinskief2ea1f2013-12-05 16:48:06 -080028import com.android.server.lights.Light;
29import com.android.server.lights.LightsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030
Sudheer Shankadc589ac2016-11-10 15:30:17 -080031import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080032import android.content.ContentResolver;
33import android.content.Context;
34import android.content.Intent;
35import android.content.pm.PackageManager;
36import android.os.BatteryManager;
Jeff Brown21392762014-06-13 19:00:36 -070037import android.os.BatteryManagerInternal;
Todd Poynor26faecc2013-05-22 18:54:48 -070038import android.os.BatteryProperties;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080039import android.os.Binder;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070040import android.os.FileUtils;
Jeff Brown605ea692012-10-05 16:33:10 -070041import android.os.Handler;
Todd Poynor26faecc2013-05-22 18:54:48 -070042import android.os.IBatteryPropertiesListener;
43import android.os.IBatteryPropertiesRegistrar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080044import android.os.IBinder;
Dan Egnor18e93962010-02-10 19:27:58 -080045import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080046import android.os.RemoteException;
47import android.os.ServiceManager;
48import android.os.SystemClock;
49import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070050import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080051import android.provider.Settings;
Netta Pe2a3cd82017-01-26 18:03:51 -080052import android.service.battery.BatteryServiceDumpProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.util.EventLog;
Joe Onorato8a9b2202010-02-26 18:56:32 -080054import android.util.Slog;
Netta Pe2a3cd82017-01-26 18:03:51 -080055import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056
57import java.io.File;
58import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import java.io.FileOutputStream;
60import java.io.IOException;
61import java.io.PrintWriter;
62
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
64/**
65 * <p>BatteryService monitors the charging status, and charge level of the device
66 * battery. When these values change this service broadcasts the new values
67 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
68 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
69 * BATTERY_CHANGED} action.</p>
70 * <p>The new values are stored in the Intent data and can be retrieved by
71 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
72 * following keys:</p>
73 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
74 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
75 * <p>&quot;status&quot; - String, the current charging status.<br />
76 * <p>&quot;health&quot; - String, the current battery health.<br />
77 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
78 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
79 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
80 * into an AC power adapter; 2 if plugged in via USB.</p>
81 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
82 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
83 * a degree Centigrade</p>
84 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
Jeff Brown605ea692012-10-05 16:33:10 -070085 *
86 * <p>
87 * The battery service may be called by the power manager while holding its locks so
88 * we take care to post all outcalls into the activity manager to a handler.
89 *
90 * FIXME: Ideally the power manager would perform all of its calls into the battery
91 * service asynchronously itself.
92 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080093 */
Jeff Brown21392762014-06-13 19:00:36 -070094public final class BatteryService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080095 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -080096
Jeff Browna4d82042012-10-02 19:11:19 -070097 private static final boolean DEBUG = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -080098
Jeff Browna4d82042012-10-02 19:11:19 -070099 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800100
101 // Used locally for determining when to make a last ditch effort to log
102 // discharge stats before the device dies.
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700103 private int mCriticalBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104
Jeff Sharkeyec43a6b2013-04-30 13:33:18 -0700105 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800106
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107 private static final String DUMPSYS_DATA_PATH = "/data/system/";
108
109 // This should probably be exposed in the API, though it's not critical
110 private static final int BATTERY_PLUGGED_NONE = 0;
111
112 private final Context mContext;
113 private final IBatteryStats mBatteryStats;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700114 BinderService mBinderService;
Jeff Brown605ea692012-10-05 16:33:10 -0700115 private final Handler mHandler;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800116
Jeff Browna4d82042012-10-02 19:11:19 -0700117 private final Object mLock = new Object();
118
Todd Poynor26faecc2013-05-22 18:54:48 -0700119 private BatteryProperties mBatteryProps;
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800120 private final BatteryProperties mLastBatteryProps = new BatteryProperties();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121 private boolean mBatteryLevelCritical;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 private int mLastBatteryStatus;
123 private int mLastBatteryHealth;
124 private boolean mLastBatteryPresent;
125 private int mLastBatteryLevel;
126 private int mLastBatteryVoltage;
127 private int mLastBatteryTemperature;
128 private boolean mLastBatteryLevelCritical;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700129 private int mLastMaxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700130 private int mLastMaxChargingVoltage;
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700131 private int mLastChargeCounter;
Jeff Browna4d82042012-10-02 19:11:19 -0700132
133 private int mInvalidCharger;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700134 private int mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400135
136 private int mLowBatteryWarningLevel;
137 private int mLowBatteryCloseWarningLevel;
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700138 private int mShutdownBatteryTemperature;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400139
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 private int mPlugType;
141 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800142
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700143 private boolean mBatteryLevelLow;
144
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 private long mDischargeStartTime;
146 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800147
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700148 private boolean mUpdatesStopped;
149
Joe Onoratode1b3592010-10-25 20:36:47 -0700150 private Led mLed;
151
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700152 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800153
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700154 private ActivityManagerInternal mActivityManagerInternal;
155
Jeff Brown21392762014-06-13 19:00:36 -0700156 public BatteryService(Context context) {
157 super(context);
158
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800159 mContext = context;
Jeff Brown605ea692012-10-05 16:33:10 -0700160 mHandler = new Handler(true /*async*/);
Jeff Brown21392762014-06-13 19:00:36 -0700161 mLed = new Led(context, getLocalService(LightsManager.class));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 mBatteryStats = BatteryStatsService.getService();
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700163 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800164
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700165 mCriticalBatteryLevel = mContext.getResources().getInteger(
166 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400167 mLowBatteryWarningLevel = mContext.getResources().getInteger(
168 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Dianne Hackborn14272302014-06-10 23:13:02 -0700169 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
170 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700171 mShutdownBatteryTemperature = mContext.getResources().getInteger(
172 com.android.internal.R.integer.config_shutdownBatteryTemperature);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400173
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400174 // watch for invalid charger messages if the invalid_charger switch exists
175 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700176 UEventObserver invalidChargerObserver = new UEventObserver() {
177 @Override
178 public void onUEvent(UEvent event) {
179 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
180 synchronized (mLock) {
181 if (mInvalidCharger != invalidCharger) {
182 mInvalidCharger = invalidCharger;
183 }
184 }
185 }
186 };
187 invalidChargerObserver.startObserving(
Jeff Browna4d82042012-10-02 19:11:19 -0700188 "DEVPATH=/devices/virtual/switch/invalid_charger");
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400189 }
Jeff Brown21392762014-06-13 19:00:36 -0700190 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191
Jeff Brown21392762014-06-13 19:00:36 -0700192 @Override
193 public void onStart() {
Todd Poynor0edc5b52013-10-22 17:53:13 -0700194 IBinder b = ServiceManager.getService("batteryproperties");
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800195 final IBatteryPropertiesRegistrar batteryPropertiesRegistrar =
196 IBatteryPropertiesRegistrar.Stub.asInterface(b);
Todd Poynor26faecc2013-05-22 18:54:48 -0700197 try {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800198 batteryPropertiesRegistrar.registerListener(new BatteryListener());
Todd Poynor26faecc2013-05-22 18:54:48 -0700199 } catch (RemoteException e) {
200 // Should never happen.
Jeff Browna4d82042012-10-02 19:11:19 -0700201 }
Jeff Brown21392762014-06-13 19:00:36 -0700202
Dianne Hackborn2e441072015-10-28 18:00:57 -0700203 mBinderService = new BinderService();
204 publishBinderService("battery", mBinderService);
Jeff Brown21392762014-06-13 19:00:36 -0700205 publishLocalService(BatteryManagerInternal.class, new LocalService());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 }
207
Jeff Brown21392762014-06-13 19:00:36 -0700208 @Override
209 public void onBootPhase(int phase) {
210 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
211 // check our power situation now that it is safe to display the shutdown dialog.
212 synchronized (mLock) {
213 ContentObserver obs = new ContentObserver(mHandler) {
214 @Override
215 public void onChange(boolean selfChange) {
216 synchronized (mLock) {
217 updateBatteryWarningLevelLocked();
218 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700219 }
Jeff Brown21392762014-06-13 19:00:36 -0700220 };
221 final ContentResolver resolver = mContext.getContentResolver();
222 resolver.registerContentObserver(Settings.Global.getUriFor(
223 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
224 false, obs, UserHandle.USER_ALL);
225 updateBatteryWarningLevelLocked();
226 }
Jeff Browna4d82042012-10-02 19:11:19 -0700227 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 }
229
Jeff Brown21392762014-06-13 19:00:36 -0700230 private void updateBatteryWarningLevelLocked() {
Dianne Hackborn14272302014-06-10 23:13:02 -0700231 final ContentResolver resolver = mContext.getContentResolver();
232 int defWarnLevel = mContext.getResources().getInteger(
233 com.android.internal.R.integer.config_lowBatteryWarningLevel);
234 mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
235 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
236 if (mLowBatteryWarningLevel == 0) {
237 mLowBatteryWarningLevel = defWarnLevel;
238 }
239 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
240 mLowBatteryWarningLevel = mCriticalBatteryLevel;
241 }
242 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
243 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
244 processValuesLocked(true);
245 }
246
Jeff Browna4d82042012-10-02 19:11:19 -0700247 private boolean isPoweredLocked(int plugTypeSet) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800248 // assume we are powered if battery state is unknown so
249 // the "stay on while plugged in" option will work.
Todd Poynor26faecc2013-05-22 18:54:48 -0700250 if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800251 return true;
252 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700253 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mBatteryProps.chargerAcOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700254 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800255 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700256 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mBatteryProps.chargerUsbOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700257 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700259 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mBatteryProps.chargerWirelessOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700260 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800261 }
Jeff Browna4d82042012-10-02 19:11:19 -0700262 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800263 }
264
Jeff Brown21392762014-06-13 19:00:36 -0700265 private boolean shouldSendBatteryLowLocked() {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700266 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
267 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
268
269 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
270 * - is just un-plugged (previously was plugged) and battery level is
271 * less than or equal to WARNING, or
272 * - is not plugged and battery level falls to WARNING boundary
273 * (becomes <= mLowBatteryWarningLevel).
274 */
275 return !plugged
276 && mBatteryProps.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
277 && mBatteryProps.batteryLevel <= mLowBatteryWarningLevel
278 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
279 }
280
Jeff Browna4d82042012-10-02 19:11:19 -0700281 private void shutdownIfNoPowerLocked() {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400282 // shut down gracefully if our battery is critically low and we are not powered.
283 // wait until the system has booted before attempting to display the shutdown dialog.
Todd Poynor26faecc2013-05-22 18:54:48 -0700284 if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
Jeff Brown605ea692012-10-05 16:33:10 -0700285 mHandler.post(new Runnable() {
286 @Override
287 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700288 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700289 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
290 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
291 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
292 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
293 }
294 }
295 });
Mike Lockwood07a500f2009-08-12 09:56:44 -0400296 }
297 }
298
Jeff Browna4d82042012-10-02 19:11:19 -0700299 private void shutdownIfOverTempLocked() {
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700300 // shut down gracefully if temperature is too high (> 68.0C by default)
301 // wait until the system has booted before attempting to display the
302 // shutdown dialog.
Todd Poynor26faecc2013-05-22 18:54:48 -0700303 if (mBatteryProps.batteryTemperature > mShutdownBatteryTemperature) {
Jeff Brown605ea692012-10-05 16:33:10 -0700304 mHandler.post(new Runnable() {
305 @Override
306 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700307 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700308 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
309 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
310 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
311 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
312 }
313 }
314 });
Eric Olsen6a362a92010-03-26 15:38:41 -0700315 }
316 }
317
Todd Poynor26faecc2013-05-22 18:54:48 -0700318 private void update(BatteryProperties props) {
319 synchronized (mLock) {
320 if (!mUpdatesStopped) {
321 mBatteryProps = props;
322 // Process the new values.
Dianne Hackborn14272302014-06-10 23:13:02 -0700323 processValuesLocked(false);
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800324 } else {
325 mLastBatteryProps.set(props);
Todd Poynor26faecc2013-05-22 18:54:48 -0700326 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700327 }
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700328 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329
Dianne Hackborn14272302014-06-10 23:13:02 -0700330 private void processValuesLocked(boolean force) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700331 boolean logOutlier = false;
332 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700333
Todd Poynor26faecc2013-05-22 18:54:48 -0700334 mBatteryLevelCritical = (mBatteryProps.batteryLevel <= mCriticalBatteryLevel);
335 if (mBatteryProps.chargerAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
Todd Poynor26faecc2013-05-22 18:54:48 -0700337 } else if (mBatteryProps.chargerUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800338 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
Todd Poynor26faecc2013-05-22 18:54:48 -0700339 } else if (mBatteryProps.chargerWirelessOnline) {
Brian Muramatsu37a37f42012-08-14 15:21:02 -0700340 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 } else {
342 mPlugType = BATTERY_PLUGGED_NONE;
343 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700344
Jeff Browna4d82042012-10-02 19:11:19 -0700345 if (DEBUG) {
346 Slog.d(TAG, "Processing new values: "
Todd Poynor26faecc2013-05-22 18:54:48 -0700347 + "chargerAcOnline=" + mBatteryProps.chargerAcOnline
348 + ", chargerUsbOnline=" + mBatteryProps.chargerUsbOnline
349 + ", chargerWirelessOnline=" + mBatteryProps.chargerWirelessOnline
Adrian Roos7b043112015-07-10 13:00:33 -0700350 + ", maxChargingCurrent" + mBatteryProps.maxChargingCurrent
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700351 + ", maxChargingVoltage" + mBatteryProps.maxChargingVoltage
Todd Poynor26faecc2013-05-22 18:54:48 -0700352 + ", batteryStatus=" + mBatteryProps.batteryStatus
353 + ", batteryHealth=" + mBatteryProps.batteryHealth
354 + ", batteryPresent=" + mBatteryProps.batteryPresent
355 + ", batteryLevel=" + mBatteryProps.batteryLevel
356 + ", batteryTechnology=" + mBatteryProps.batteryTechnology
357 + ", batteryVoltage=" + mBatteryProps.batteryVoltage
Adam Lesinskiabcb9f32016-12-09 19:27:39 -0800358 + ", batteryChargeCounter=" + mBatteryProps.batteryChargeCounter
359 + ", batteryFullCharge=" + mBatteryProps.batteryFullCharge
Todd Poynor26faecc2013-05-22 18:54:48 -0700360 + ", batteryTemperature=" + mBatteryProps.batteryTemperature
Jeff Browna4d82042012-10-02 19:11:19 -0700361 + ", mBatteryLevelCritical=" + mBatteryLevelCritical
362 + ", mPlugType=" + mPlugType);
363 }
364
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700365 // Let the battery stats keep track of the current level.
366 try {
Todd Poynor26faecc2013-05-22 18:54:48 -0700367 mBatteryStats.setBatteryState(mBatteryProps.batteryStatus, mBatteryProps.batteryHealth,
368 mPlugType, mBatteryProps.batteryLevel, mBatteryProps.batteryTemperature,
Adam Lesinski041d9172016-12-12 12:03:56 -0800369 mBatteryProps.batteryVoltage, mBatteryProps.batteryChargeCounter,
370 mBatteryProps.batteryFullCharge);
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700371 } catch (RemoteException e) {
372 // Should never happen.
373 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700374
Jeff Browna4d82042012-10-02 19:11:19 -0700375 shutdownIfNoPowerLocked();
376 shutdownIfOverTempLocked();
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700377
Dianne Hackborn14272302014-06-10 23:13:02 -0700378 if (force || (mBatteryProps.batteryStatus != mLastBatteryStatus ||
Todd Poynor26faecc2013-05-22 18:54:48 -0700379 mBatteryProps.batteryHealth != mLastBatteryHealth ||
380 mBatteryProps.batteryPresent != mLastBatteryPresent ||
381 mBatteryProps.batteryLevel != mLastBatteryLevel ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800382 mPlugType != mLastPlugType ||
Todd Poynor26faecc2013-05-22 18:54:48 -0700383 mBatteryProps.batteryVoltage != mLastBatteryVoltage ||
384 mBatteryProps.batteryTemperature != mLastBatteryTemperature ||
Adrian Roos76dc5a52015-07-21 16:20:36 -0700385 mBatteryProps.maxChargingCurrent != mLastMaxChargingCurrent ||
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700386 mBatteryProps.maxChargingVoltage != mLastMaxChargingVoltage ||
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700387 mBatteryProps.batteryChargeCounter != mLastChargeCounter ||
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;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700514 mLastMaxChargingCurrent = mBatteryProps.maxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700515 mLastMaxChargingVoltage = mBatteryProps.maxChargingVoltage;
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700516 mLastChargeCounter = mBatteryProps.batteryChargeCounter;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700517 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400518 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800519 }
520 }
521
Jeff Browna4d82042012-10-02 19:11:19 -0700522 private void sendIntentLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 // Pack up the values and broadcast them to everyone
Jeff Brown605ea692012-10-05 16:33:10 -0700524 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800525 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
526 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800527
Todd Poynor26faecc2013-05-22 18:54:48 -0700528 int icon = getIconLocked(mBatteryProps.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800529
Todd Poynor26faecc2013-05-22 18:54:48 -0700530 intent.putExtra(BatteryManager.EXTRA_STATUS, mBatteryProps.batteryStatus);
531 intent.putExtra(BatteryManager.EXTRA_HEALTH, mBatteryProps.batteryHealth);
532 intent.putExtra(BatteryManager.EXTRA_PRESENT, mBatteryProps.batteryPresent);
533 intent.putExtra(BatteryManager.EXTRA_LEVEL, mBatteryProps.batteryLevel);
Dianne Hackbornedd93162009-09-19 14:03:05 -0700534 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
535 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
536 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
Todd Poynor26faecc2013-05-22 18:54:48 -0700537 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mBatteryProps.batteryVoltage);
538 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mBatteryProps.batteryTemperature);
539 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mBatteryProps.batteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400540 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
Adrian Roos7b043112015-07-10 13:00:33 -0700541 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700542 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700543 intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
Jeff Browna4d82042012-10-02 19:11:19 -0700544 if (DEBUG) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700545 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. level:" + mBatteryProps.batteryLevel +
546 ", scale:" + BATTERY_SCALE + ", status:" + mBatteryProps.batteryStatus +
Adrian Roos7b043112015-07-10 13:00:33 -0700547 ", health:" + mBatteryProps.batteryHealth +
548 ", present:" + mBatteryProps.batteryPresent +
Todd Poynor26faecc2013-05-22 18:54:48 -0700549 ", voltage: " + mBatteryProps.batteryVoltage +
550 ", temperature: " + mBatteryProps.batteryTemperature +
551 ", technology: " + mBatteryProps.batteryTechnology +
Adrian Roos7b043112015-07-10 13:00:33 -0700552 ", AC powered:" + mBatteryProps.chargerAcOnline +
553 ", USB powered:" + mBatteryProps.chargerUsbOnline +
Todd Poynor26faecc2013-05-22 18:54:48 -0700554 ", Wireless powered:" + mBatteryProps.chargerWirelessOnline +
Adrian Roos7b043112015-07-10 13:00:33 -0700555 ", icon:" + icon + ", invalid charger:" + mInvalidCharger +
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700556 ", maxChargingCurrent:" + mBatteryProps.maxChargingCurrent +
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700557 ", maxChargingVoltage:" + mBatteryProps.maxChargingVoltage +
558 ", chargeCounter:" + mBatteryProps.batteryChargeCounter);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800559 }
560
Jeff Brown605ea692012-10-05 16:33:10 -0700561 mHandler.post(new Runnable() {
562 @Override
563 public void run() {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800564 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
Jeff Brown605ea692012-10-05 16:33:10 -0700565 }
566 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800567 }
568
Jeff Browna4d82042012-10-02 19:11:19 -0700569 private void logBatteryStatsLocked() {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700570 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800571 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800572
Dan Egnor18e93962010-02-10 19:27:58 -0800573 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
574 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
575
576 File dumpFile = null;
577 FileOutputStream dumpStream = null;
578 try {
579 // dump the service to a file
Dianne Hackborn8c841092013-06-24 13:46:13 -0700580 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
Dan Egnor18e93962010-02-10 19:27:58 -0800581 dumpStream = new FileOutputStream(dumpFile);
582 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -0700583 FileUtils.sync(dumpStream);
Dan Egnor18e93962010-02-10 19:27:58 -0800584
585 // add dump file to drop box
586 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
587 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800588 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800589 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800590 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800591 } finally {
592 // make sure we clean up
593 if (dumpStream != null) {
594 try {
595 dumpStream.close();
596 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800597 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800598 }
Dan Egnor18e93962010-02-10 19:27:58 -0800599 }
600 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800601 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800602 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800603 }
604 }
605 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800606
Jeff Browna4d82042012-10-02 19:11:19 -0700607 private void logOutlierLocked(long duration) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800608 ContentResolver cr = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -0700609 String dischargeThresholdString = Settings.Global.getString(cr,
610 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
611 String durationThresholdString = Settings.Global.getString(cr,
612 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800613
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800614 if (dischargeThresholdString != null && durationThresholdString != null) {
615 try {
616 long durationThreshold = Long.parseLong(durationThresholdString);
617 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800618 if (duration <= durationThreshold &&
Todd Poynor26faecc2013-05-22 18:54:48 -0700619 mDischargeStartLevel - mBatteryProps.batteryLevel >= dischargeThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800620 // If the discharge cycle is bad enough we want to know about it.
Jeff Browna4d82042012-10-02 19:11:19 -0700621 logBatteryStatsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800622 }
Jeff Browna4d82042012-10-02 19:11:19 -0700623 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 " discharge threshold: " + dischargeThreshold);
Jeff Browna4d82042012-10-02 19:11:19 -0700625 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
Todd Poynor26faecc2013-05-22 18:54:48 -0700626 (mDischargeStartLevel - mBatteryProps.batteryLevel));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800628 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800629 durationThresholdString + " or " + dischargeThresholdString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 }
631 }
632 }
633
Jeff Browna4d82042012-10-02 19:11:19 -0700634 private int getIconLocked(int level) {
Todd Poynor26faecc2013-05-22 18:54:48 -0700635 if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800636 return com.android.internal.R.drawable.stat_sys_battery_charge;
Todd Poynor26faecc2013-05-22 18:54:48 -0700637 } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800638 return com.android.internal.R.drawable.stat_sys_battery;
Todd Poynor26faecc2013-05-22 18:54:48 -0700639 } else if (mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
640 || mBatteryProps.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
Jeff Browna4d82042012-10-02 19:11:19 -0700641 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
Todd Poynor26faecc2013-05-22 18:54:48 -0700642 && mBatteryProps.batteryLevel >= 100) {
Joe Onorato794be402010-11-21 19:22:25 -0800643 return com.android.internal.R.drawable.stat_sys_battery_charge;
644 } else {
645 return com.android.internal.R.drawable.stat_sys_battery;
646 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800647 } else {
648 return com.android.internal.R.drawable.stat_sys_battery_unknown;
649 }
650 }
651
Dianne Hackborn2e441072015-10-28 18:00:57 -0700652 class Shell extends ShellCommand {
653 @Override
654 public int onCommand(String cmd) {
655 return onShellCommand(this, cmd);
656 }
657
658 @Override
659 public void onHelp() {
660 PrintWriter pw = getOutPrintWriter();
661 dumpHelp(pw);
662 }
663 }
664
665 static void dumpHelp(PrintWriter pw) {
666 pw.println("Battery service (battery) commands:");
667 pw.println(" help");
668 pw.println(" Print this help text.");
669 pw.println(" set [ac|usb|wireless|status|level|invalid] <value>");
670 pw.println(" Force a battery property value, freezing battery state.");
671 pw.println(" unplug");
672 pw.println(" Force battery unplugged, freezing battery state.");
673 pw.println(" reset");
674 pw.println(" Unfreeze battery state, returning to current hardware values.");
675 }
676
677 int onShellCommand(Shell shell, String cmd) {
678 if (cmd == null) {
679 return shell.handleDefaultCommands(cmd);
680 }
681 PrintWriter pw = shell.getOutPrintWriter();
682 switch (cmd) {
683 case "unplug": {
684 getContext().enforceCallingOrSelfPermission(
685 android.Manifest.permission.DEVICE_POWER, null);
686 if (!mUpdatesStopped) {
687 mLastBatteryProps.set(mBatteryProps);
688 }
689 mBatteryProps.chargerAcOnline = false;
690 mBatteryProps.chargerUsbOnline = false;
691 mBatteryProps.chargerWirelessOnline = false;
692 long ident = Binder.clearCallingIdentity();
693 try {
694 mUpdatesStopped = true;
695 processValuesLocked(false);
696 } finally {
697 Binder.restoreCallingIdentity(ident);
698 }
699 } break;
700 case "set": {
701 getContext().enforceCallingOrSelfPermission(
702 android.Manifest.permission.DEVICE_POWER, null);
703 final String key = shell.getNextArg();
704 if (key == null) {
705 pw.println("No property specified");
706 return -1;
707
708 }
709 final String value = shell.getNextArg();
710 if (value == null) {
711 pw.println("No value specified");
712 return -1;
713
714 }
715 try {
716 if (!mUpdatesStopped) {
717 mLastBatteryProps.set(mBatteryProps);
718 }
719 boolean update = true;
720 switch (key) {
721 case "ac":
722 mBatteryProps.chargerAcOnline = Integer.parseInt(value) != 0;
723 break;
724 case "usb":
725 mBatteryProps.chargerUsbOnline = Integer.parseInt(value) != 0;
726 break;
727 case "wireless":
728 mBatteryProps.chargerWirelessOnline = Integer.parseInt(value) != 0;
729 break;
730 case "status":
731 mBatteryProps.batteryStatus = Integer.parseInt(value);
732 break;
733 case "level":
734 mBatteryProps.batteryLevel = Integer.parseInt(value);
735 break;
736 case "invalid":
737 mInvalidCharger = Integer.parseInt(value);
738 break;
739 default:
740 pw.println("Unknown set option: " + key);
741 update = false;
742 break;
743 }
744 if (update) {
745 long ident = Binder.clearCallingIdentity();
746 try {
747 mUpdatesStopped = true;
748 processValuesLocked(false);
749 } finally {
750 Binder.restoreCallingIdentity(ident);
751 }
752 }
753 } catch (NumberFormatException ex) {
754 pw.println("Bad value: " + value);
755 return -1;
756 }
757 } break;
758 case "reset": {
759 getContext().enforceCallingOrSelfPermission(
760 android.Manifest.permission.DEVICE_POWER, null);
761 long ident = Binder.clearCallingIdentity();
762 try {
763 if (mUpdatesStopped) {
764 mUpdatesStopped = false;
765 mBatteryProps.set(mLastBatteryProps);
766 processValuesLocked(false);
767 }
768 } finally {
769 Binder.restoreCallingIdentity(ident);
770 }
771 } break;
772 default:
773 return shell.handleDefaultCommands(cmd);
774 }
775 return 0;
776 }
777
778 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna4d82042012-10-02 19:11:19 -0700779 synchronized (mLock) {
780 if (args == null || args.length == 0 || "-a".equals(args[0])) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700781 pw.println("Current Battery Service state:");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700782 if (mUpdatesStopped) {
783 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
784 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700785 pw.println(" AC powered: " + mBatteryProps.chargerAcOnline);
786 pw.println(" USB powered: " + mBatteryProps.chargerUsbOnline);
787 pw.println(" Wireless powered: " + mBatteryProps.chargerWirelessOnline);
Adrian Roos7b043112015-07-10 13:00:33 -0700788 pw.println(" Max charging current: " + mBatteryProps.maxChargingCurrent);
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700789 pw.println(" Max charging voltage: " + mBatteryProps.maxChargingVoltage);
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700790 pw.println(" Charge counter: " + mBatteryProps.batteryChargeCounter);
Todd Poynor26faecc2013-05-22 18:54:48 -0700791 pw.println(" status: " + mBatteryProps.batteryStatus);
792 pw.println(" health: " + mBatteryProps.batteryHealth);
793 pw.println(" present: " + mBatteryProps.batteryPresent);
794 pw.println(" level: " + mBatteryProps.batteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700795 pw.println(" scale: " + BATTERY_SCALE);
Todd Poynordf89ca32013-07-30 20:33:27 -0700796 pw.println(" voltage: " + mBatteryProps.batteryVoltage);
Todd Poynor26faecc2013-05-22 18:54:48 -0700797 pw.println(" temperature: " + mBatteryProps.batteryTemperature);
798 pw.println(" technology: " + mBatteryProps.batteryTechnology);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700799 } else {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700800 Shell shell = new Shell();
Dianne Hackborn354736e2016-08-22 17:00:05 -0700801 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700802 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800803 }
804 }
Joe Onoratode1b3592010-10-25 20:36:47 -0700805
Netta Pe2a3cd82017-01-26 18:03:51 -0800806 private void dumpProto(FileDescriptor fd) {
807 final ProtoOutputStream proto = new ProtoOutputStream(fd);
808
809 synchronized (mLock) {
810 proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
811 int batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_NONE;
812 if (mBatteryProps.chargerAcOnline) {
813 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_AC;
814 } else if (mBatteryProps.chargerUsbOnline) {
815 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_USB;
816 } else if (mBatteryProps.chargerWirelessOnline) {
817 batteryPluggedValue = BatteryServiceDumpProto.BATTERY_PLUGGED_WIRELESS;
818 }
819 proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
820 proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mBatteryProps.maxChargingCurrent);
821 proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mBatteryProps.maxChargingVoltage);
822 proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mBatteryProps.batteryChargeCounter);
823 proto.write(BatteryServiceDumpProto.STATUS, mBatteryProps.batteryStatus);
824 proto.write(BatteryServiceDumpProto.HEALTH, mBatteryProps.batteryHealth);
825 proto.write(BatteryServiceDumpProto.IS_PRESENT, mBatteryProps.batteryPresent);
826 proto.write(BatteryServiceDumpProto.LEVEL, mBatteryProps.batteryLevel);
827 proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
828 proto.write(BatteryServiceDumpProto.VOLTAGE, mBatteryProps.batteryVoltage);
829 proto.write(BatteryServiceDumpProto.TEMPERATURE, mBatteryProps.batteryTemperature);
830 proto.write(BatteryServiceDumpProto.TECHNOLOGY, mBatteryProps.batteryTechnology);
831 }
832 proto.flush();
833 }
834
Jeff Browna4d82042012-10-02 19:11:19 -0700835 private final class Led {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800836 private final Light mBatteryLight;
Joe Onoratode1b3592010-10-25 20:36:47 -0700837
Jeff Browna4d82042012-10-02 19:11:19 -0700838 private final int mBatteryLowARGB;
839 private final int mBatteryMediumARGB;
840 private final int mBatteryFullARGB;
841 private final int mBatteryLedOn;
842 private final int mBatteryLedOff;
843
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800844 public Led(Context context, LightsManager lights) {
845 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
Joe Onoratode1b3592010-10-25 20:36:47 -0700846
Jeff Browna4d82042012-10-02 19:11:19 -0700847 mBatteryLowARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700848 com.android.internal.R.integer.config_notificationsBatteryLowARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700849 mBatteryMediumARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700850 com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700851 mBatteryFullARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700852 com.android.internal.R.integer.config_notificationsBatteryFullARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700853 mBatteryLedOn = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700854 com.android.internal.R.integer.config_notificationsBatteryLedOn);
Jeff Browna4d82042012-10-02 19:11:19 -0700855 mBatteryLedOff = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700856 com.android.internal.R.integer.config_notificationsBatteryLedOff);
857 }
858
859 /**
860 * Synchronize on BatteryService.
861 */
Jeff Browna4d82042012-10-02 19:11:19 -0700862 public void updateLightsLocked() {
Todd Poynor26faecc2013-05-22 18:54:48 -0700863 final int level = mBatteryProps.batteryLevel;
864 final int status = mBatteryProps.batteryStatus;
Joe Onoratode1b3592010-10-25 20:36:47 -0700865 if (level < mLowBatteryWarningLevel) {
866 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
867 // Solid red when battery is charging
868 mBatteryLight.setColor(mBatteryLowARGB);
869 } else {
870 // Flash red when battery is low and not charging
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800871 mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
Joe Onoratode1b3592010-10-25 20:36:47 -0700872 mBatteryLedOn, mBatteryLedOff);
873 }
874 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
875 || status == BatteryManager.BATTERY_STATUS_FULL) {
876 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
877 // Solid green when full or charging and nearly full
878 mBatteryLight.setColor(mBatteryFullARGB);
879 } else {
880 // Solid orange when charging and halfway full
881 mBatteryLight.setColor(mBatteryMediumARGB);
882 }
883 } else {
884 // No lights if not charging and not low
885 mBatteryLight.turnOff();
886 }
887 }
888 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700889
890 private final class BatteryListener extends IBatteryPropertiesListener.Stub {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700891 @Override public void batteryPropertiesChanged(BatteryProperties props) {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800892 final long identity = Binder.clearCallingIdentity();
893 try {
894 BatteryService.this.update(props);
895 } finally {
896 Binder.restoreCallingIdentity(identity);
897 }
Todd Poynor26faecc2013-05-22 18:54:48 -0700898 }
899 }
Jeff Brown21392762014-06-13 19:00:36 -0700900
901 private final class BinderService extends Binder {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700902 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Brown21392762014-06-13 19:00:36 -0700903 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
904 != PackageManager.PERMISSION_GRANTED) {
905
906 pw.println("Permission Denial: can't dump Battery service from from pid="
907 + Binder.getCallingPid()
908 + ", uid=" + Binder.getCallingUid());
909 return;
910 }
911
Netta Pe2a3cd82017-01-26 18:03:51 -0800912 if (args.length > 0 && "--proto".equals(args[0])) {
913 dumpProto(fd);
914 } else {
915 dumpInternal(fd, pw, args);
916 }
Dianne Hackborn2e441072015-10-28 18:00:57 -0700917 }
918
919 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -0700920 FileDescriptor err, String[] args, ShellCallback callback,
921 ResultReceiver resultReceiver) {
922 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Jeff Brown21392762014-06-13 19:00:36 -0700923 }
924 }
925
926 private final class LocalService extends BatteryManagerInternal {
927 @Override
928 public boolean isPowered(int plugTypeSet) {
929 synchronized (mLock) {
930 return isPoweredLocked(plugTypeSet);
931 }
932 }
933
934 @Override
935 public int getPlugType() {
936 synchronized (mLock) {
937 return mPlugType;
938 }
939 }
940
941 @Override
942 public int getBatteryLevel() {
943 synchronized (mLock) {
944 return mBatteryProps.batteryLevel;
945 }
946 }
947
948 @Override
949 public boolean getBatteryLevelLow() {
950 synchronized (mLock) {
951 return mBatteryLevelLow;
952 }
953 }
954
955 @Override
956 public int getInvalidCharger() {
957 synchronized (mLock) {
958 return mInvalidCharger;
959 }
960 }
961 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800962}