blob: 1b61866f81b6c9dc25159527b77c56b2106800f2 [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
Sudheer Shanka292637f2017-09-25 10:36:23 -070023import android.os.PowerManager;
Dianne Hackborn2e441072015-10-28 18:00:57 -070024import android.os.ResultReceiver;
Dianne Hackborn354736e2016-08-22 17:00:05 -070025import android.os.ShellCallback;
Dianne Hackborn2e441072015-10-28 18:00:57 -070026import android.os.ShellCommand;
Yifan Hong98852792017-10-12 11:35:14 -070027import com.android.internal.annotations.VisibleForTesting;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080028import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060029import com.android.internal.util.DumpUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080030import com.android.server.am.BatteryStatsService;
Adam Lesinskief2ea1f2013-12-05 16:48:06 -080031import com.android.server.lights.Light;
32import com.android.server.lights.LightsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080033
Sudheer Shankadc589ac2016-11-10 15:30:17 -080034import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080035import android.content.ContentResolver;
36import android.content.Context;
37import android.content.Intent;
38import android.content.pm.PackageManager;
Yifan Hong98852792017-10-12 11:35:14 -070039import android.hidl.manager.V1_0.IServiceManager;
40import android.hidl.manager.V1_0.IServiceNotification;
Yifan Hong932190b2017-10-11 11:00:51 -070041import android.hardware.health.V2_0.HealthInfo;
Yifan Hong89d55c12017-10-11 11:29:01 -070042import android.hardware.health.V2_0.IHealthInfoCallback;
Yifan Hong98852792017-10-12 11:35:14 -070043import android.hardware.health.V2_0.IHealth;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070044import android.hardware.health.V2_0.Result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.BatteryManager;
Kweku Adamse6b00c22017-10-23 16:46:45 -070046import android.os.BatteryManagerProto;
Jeff Brown21392762014-06-13 19:00:36 -070047import android.os.BatteryManagerInternal;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070048import android.os.BatteryProperty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080049import android.os.Binder;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070050import android.os.FileUtils;
Jeff Brown605ea692012-10-05 16:33:10 -070051import android.os.Handler;
Todd Poynor26faecc2013-05-22 18:54:48 -070052import android.os.IBatteryPropertiesListener;
53import android.os.IBatteryPropertiesRegistrar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080054import android.os.IBinder;
Dan Egnor18e93962010-02-10 19:27:58 -080055import android.os.DropBoxManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056import android.os.RemoteException;
57import android.os.ServiceManager;
58import android.os.SystemClock;
Yifan Hong8cc18ef2017-10-31 12:27:47 -070059import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080060import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070061import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080062import android.provider.Settings;
Netta Pe2a3cd82017-01-26 18:03:51 -080063import android.service.battery.BatteryServiceDumpProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080064import android.util.EventLog;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070065import android.util.MutableInt;
Joe Onorato8a9b2202010-02-26 18:56:32 -080066import android.util.Slog;
Netta Pe2a3cd82017-01-26 18:03:51 -080067import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080068
69import java.io.File;
70import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071import java.io.FileOutputStream;
72import java.io.IOException;
73import java.io.PrintWriter;
74
Yifan Hong98852792017-10-12 11:35:14 -070075import java.util.Arrays;
76import java.util.List;
77import java.util.NoSuchElementException;
Yifan Hong89d55c12017-10-11 11:29:01 -070078import java.util.concurrent.atomic.AtomicReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079
80/**
81 * <p>BatteryService monitors the charging status, and charge level of the device
82 * battery. When these values change this service broadcasts the new values
83 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
84 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
85 * BATTERY_CHANGED} action.</p>
86 * <p>The new values are stored in the Intent data and can be retrieved by
87 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
88 * following keys:</p>
89 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
90 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
91 * <p>&quot;status&quot; - String, the current charging status.<br />
92 * <p>&quot;health&quot; - String, the current battery health.<br />
93 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
94 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
95 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
96 * into an AC power adapter; 2 if plugged in via USB.</p>
97 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
98 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
99 * a degree Centigrade</p>
100 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
Jeff Brown605ea692012-10-05 16:33:10 -0700101 *
102 * <p>
103 * The battery service may be called by the power manager while holding its locks so
104 * we take care to post all outcalls into the activity manager to a handler.
105 *
106 * FIXME: Ideally the power manager would perform all of its calls into the battery
107 * service asynchronously itself.
108 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800109 */
Jeff Brown21392762014-06-13 19:00:36 -0700110public final class BatteryService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800111 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800112
Jeff Browna4d82042012-10-02 19:11:19 -0700113 private static final boolean DEBUG = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800114
Jeff Browna4d82042012-10-02 19:11:19 -0700115 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116
Yifan Hong89d55c12017-10-11 11:29:01 -0700117 private static final long HEALTH_HAL_WAIT_MS = 1000;
118
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800119 // Used locally for determining when to make a last ditch effort to log
120 // discharge stats before the device dies.
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700121 private int mCriticalBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122
Jeff Sharkeyec43a6b2013-04-30 13:33:18 -0700123 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 private static final String DUMPSYS_DATA_PATH = "/data/system/";
126
127 // This should probably be exposed in the API, though it's not critical
128 private static final int BATTERY_PLUGGED_NONE = 0;
129
130 private final Context mContext;
131 private final IBatteryStats mBatteryStats;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700132 BinderService mBinderService;
Jeff Brown605ea692012-10-05 16:33:10 -0700133 private final Handler mHandler;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800134
Jeff Browna4d82042012-10-02 19:11:19 -0700135 private final Object mLock = new Object();
136
Yifan Hong932190b2017-10-11 11:00:51 -0700137 private HealthInfo mHealthInfo;
138 private final HealthInfo mLastHealthInfo = new HealthInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800139 private boolean mBatteryLevelCritical;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 private int mLastBatteryStatus;
141 private int mLastBatteryHealth;
142 private boolean mLastBatteryPresent;
143 private int mLastBatteryLevel;
144 private int mLastBatteryVoltage;
145 private int mLastBatteryTemperature;
146 private boolean mLastBatteryLevelCritical;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700147 private int mLastMaxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700148 private int mLastMaxChargingVoltage;
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700149 private int mLastChargeCounter;
Jeff Browna4d82042012-10-02 19:11:19 -0700150
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800151 private int mSequence = 1;
152
Jeff Browna4d82042012-10-02 19:11:19 -0700153 private int mInvalidCharger;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700154 private int mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400155
156 private int mLowBatteryWarningLevel;
157 private int mLowBatteryCloseWarningLevel;
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700158 private int mShutdownBatteryTemperature;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400159
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800160 private int mPlugType;
161 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800162
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700163 private boolean mBatteryLevelLow;
164
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 private long mDischargeStartTime;
166 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800167
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700168 private boolean mUpdatesStopped;
169
Joe Onoratode1b3592010-10-25 20:36:47 -0700170 private Led mLed;
171
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700172 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800173
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700174 private ActivityManagerInternal mActivityManagerInternal;
175
Yifan Hong89d55c12017-10-11 11:29:01 -0700176 private HealthServiceWrapper mHealthServiceWrapper;
177 private HealthHalCallback mHealthHalCallback;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -0700178 private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
Yifan Hong89d55c12017-10-11 11:29:01 -0700179
Jeff Brown21392762014-06-13 19:00:36 -0700180 public BatteryService(Context context) {
181 super(context);
182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800183 mContext = context;
Jeff Brown605ea692012-10-05 16:33:10 -0700184 mHandler = new Handler(true /*async*/);
Jeff Brown21392762014-06-13 19:00:36 -0700185 mLed = new Led(context, getLocalService(LightsManager.class));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800186 mBatteryStats = BatteryStatsService.getService();
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700187 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700189 mCriticalBatteryLevel = mContext.getResources().getInteger(
190 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400191 mLowBatteryWarningLevel = mContext.getResources().getInteger(
192 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Dianne Hackborn14272302014-06-10 23:13:02 -0700193 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
194 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700195 mShutdownBatteryTemperature = mContext.getResources().getInteger(
196 com.android.internal.R.integer.config_shutdownBatteryTemperature);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400197
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400198 // watch for invalid charger messages if the invalid_charger switch exists
199 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700200 UEventObserver invalidChargerObserver = new UEventObserver() {
201 @Override
202 public void onUEvent(UEvent event) {
203 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
204 synchronized (mLock) {
205 if (mInvalidCharger != invalidCharger) {
206 mInvalidCharger = invalidCharger;
207 }
208 }
209 }
210 };
211 invalidChargerObserver.startObserving(
Jeff Browna4d82042012-10-02 19:11:19 -0700212 "DEVPATH=/devices/virtual/switch/invalid_charger");
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400213 }
Jeff Brown21392762014-06-13 19:00:36 -0700214 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800215
Jeff Brown21392762014-06-13 19:00:36 -0700216 @Override
217 public void onStart() {
Yifan Hong89d55c12017-10-11 11:29:01 -0700218 registerHealthCallback();
Jeff Brown21392762014-06-13 19:00:36 -0700219
Dianne Hackborn2e441072015-10-28 18:00:57 -0700220 mBinderService = new BinderService();
221 publishBinderService("battery", mBinderService);
Yifan Hong1fd86f4c2017-10-09 16:50:33 -0700222 mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
223 publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);
Jeff Brown21392762014-06-13 19:00:36 -0700224 publishLocalService(BatteryManagerInternal.class, new LocalService());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 }
226
Jeff Brown21392762014-06-13 19:00:36 -0700227 @Override
228 public void onBootPhase(int phase) {
229 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
230 // check our power situation now that it is safe to display the shutdown dialog.
231 synchronized (mLock) {
232 ContentObserver obs = new ContentObserver(mHandler) {
233 @Override
234 public void onChange(boolean selfChange) {
235 synchronized (mLock) {
236 updateBatteryWarningLevelLocked();
237 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700238 }
Jeff Brown21392762014-06-13 19:00:36 -0700239 };
240 final ContentResolver resolver = mContext.getContentResolver();
241 resolver.registerContentObserver(Settings.Global.getUriFor(
242 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
243 false, obs, UserHandle.USER_ALL);
244 updateBatteryWarningLevelLocked();
245 }
Jeff Browna4d82042012-10-02 19:11:19 -0700246 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247 }
248
Yifan Hong89d55c12017-10-11 11:29:01 -0700249 private void registerHealthCallback() {
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700250 traceBegin("HealthInitWrapper");
Yifan Hong89d55c12017-10-11 11:29:01 -0700251 mHealthServiceWrapper = new HealthServiceWrapper();
252 mHealthHalCallback = new HealthHalCallback();
253 // IHealth is lazily retrieved.
254 try {
255 mHealthServiceWrapper.init(mHealthHalCallback,
256 new HealthServiceWrapper.IServiceManagerSupplier() {},
257 new HealthServiceWrapper.IHealthSupplier() {});
Yifan Hong78e8af12017-10-26 15:57:19 -0700258 } catch (RemoteException ex) {
259 Slog.e(TAG, "health: cannot register callback. (RemoteException)");
260 throw ex.rethrowFromSystemServer();
261 } catch (NoSuchElementException ex) {
262 Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");
263 throw ex;
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700264 } finally {
265 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -0700266 }
267
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700268 traceBegin("HealthInitWaitUpdate");
Yifan Hong89d55c12017-10-11 11:29:01 -0700269 // init register for new service notifications, and IServiceManager should return the
270 // existing service in a near future. Wait for this.update() to instantiate
271 // the initial mHealthInfo.
Yifan Hong78e8af12017-10-26 15:57:19 -0700272 long beforeWait = SystemClock.uptimeMillis();
Yifan Hong89d55c12017-10-11 11:29:01 -0700273 synchronized (mLock) {
Yifan Hong78e8af12017-10-26 15:57:19 -0700274 while (mHealthInfo == null) {
275 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) +
276 "ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms...");
Yifan Hong89d55c12017-10-11 11:29:01 -0700277 try {
Yifan Hong78e8af12017-10-26 15:57:19 -0700278 mLock.wait(HEALTH_HAL_WAIT_MS);
Yifan Hong89d55c12017-10-11 11:29:01 -0700279 } catch (InterruptedException ex) {
Yifan Hong78e8af12017-10-26 15:57:19 -0700280 Slog.i(TAG, "health: InterruptedException when waiting for update. "
281 + " Continuing...");
Yifan Hong89d55c12017-10-11 11:29:01 -0700282 }
283 }
Yifan Hong89d55c12017-10-11 11:29:01 -0700284 }
285
Yifan Hong78e8af12017-10-26 15:57:19 -0700286 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)
287 + "ms and received the update.");
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700288 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -0700289 }
290
Jeff Brown21392762014-06-13 19:00:36 -0700291 private void updateBatteryWarningLevelLocked() {
Dianne Hackborn14272302014-06-10 23:13:02 -0700292 final ContentResolver resolver = mContext.getContentResolver();
293 int defWarnLevel = mContext.getResources().getInteger(
294 com.android.internal.R.integer.config_lowBatteryWarningLevel);
295 mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
296 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
297 if (mLowBatteryWarningLevel == 0) {
298 mLowBatteryWarningLevel = defWarnLevel;
299 }
300 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
301 mLowBatteryWarningLevel = mCriticalBatteryLevel;
302 }
303 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
304 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
305 processValuesLocked(true);
306 }
307
Jeff Browna4d82042012-10-02 19:11:19 -0700308 private boolean isPoweredLocked(int plugTypeSet) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800309 // assume we are powered if battery state is unknown so
310 // the "stay on while plugged in" option will work.
Yifan Hong932190b2017-10-11 11:00:51 -0700311 if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800312 return true;
313 }
Yifan Hong932190b2017-10-11 11:00:51 -0700314 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.legacy.chargerAcOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700315 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 }
Yifan Hong932190b2017-10-11 11:00:51 -0700317 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.legacy.chargerUsbOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700318 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 }
Yifan Hong932190b2017-10-11 11:00:51 -0700320 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.legacy.chargerWirelessOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700321 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 }
Jeff Browna4d82042012-10-02 19:11:19 -0700323 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800324 }
325
Jeff Brown21392762014-06-13 19:00:36 -0700326 private boolean shouldSendBatteryLowLocked() {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700327 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
328 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
329
330 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
331 * - is just un-plugged (previously was plugged) and battery level is
332 * less than or equal to WARNING, or
333 * - is not plugged and battery level falls to WARNING boundary
334 * (becomes <= mLowBatteryWarningLevel).
335 */
336 return !plugged
Yifan Hong932190b2017-10-11 11:00:51 -0700337 && mHealthInfo.legacy.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
338 && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700339 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
340 }
341
Jeff Browna4d82042012-10-02 19:11:19 -0700342 private void shutdownIfNoPowerLocked() {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400343 // shut down gracefully if our battery is critically low and we are not powered.
344 // wait until the system has booted before attempting to display the shutdown dialog.
Yifan Hong932190b2017-10-11 11:00:51 -0700345 if (mHealthInfo.legacy.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
Jeff Brown605ea692012-10-05 16:33:10 -0700346 mHandler.post(new Runnable() {
347 @Override
348 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700349 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700350 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
351 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
Sudheer Shanka292637f2017-09-25 10:36:23 -0700352 intent.putExtra(Intent.EXTRA_REASON,
353 PowerManager.SHUTDOWN_LOW_BATTERY);
Jeff Brown605ea692012-10-05 16:33:10 -0700354 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
355 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
356 }
357 }
358 });
Mike Lockwood07a500f2009-08-12 09:56:44 -0400359 }
360 }
361
Jeff Browna4d82042012-10-02 19:11:19 -0700362 private void shutdownIfOverTempLocked() {
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700363 // shut down gracefully if temperature is too high (> 68.0C by default)
364 // wait until the system has booted before attempting to display the
365 // shutdown dialog.
Yifan Hong932190b2017-10-11 11:00:51 -0700366 if (mHealthInfo.legacy.batteryTemperature > mShutdownBatteryTemperature) {
Jeff Brown605ea692012-10-05 16:33:10 -0700367 mHandler.post(new Runnable() {
368 @Override
369 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700370 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700371 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
372 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
Sudheer Shanka292637f2017-09-25 10:36:23 -0700373 intent.putExtra(Intent.EXTRA_REASON,
374 PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE);
Jeff Brown605ea692012-10-05 16:33:10 -0700375 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
376 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
377 }
378 }
379 });
Eric Olsen6a362a92010-03-26 15:38:41 -0700380 }
381 }
382
Yifan Hong89d55c12017-10-11 11:29:01 -0700383 private void update(HealthInfo info) {
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700384 traceBegin("HealthInfoUpdate");
Todd Poynor26faecc2013-05-22 18:54:48 -0700385 synchronized (mLock) {
386 if (!mUpdatesStopped) {
Yifan Hong89d55c12017-10-11 11:29:01 -0700387 mHealthInfo = info;
Todd Poynor26faecc2013-05-22 18:54:48 -0700388 // Process the new values.
Dianne Hackborn14272302014-06-10 23:13:02 -0700389 processValuesLocked(false);
Yifan Hong89d55c12017-10-11 11:29:01 -0700390 mLock.notifyAll(); // for any waiters on new info
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800391 } else {
Yifan Hong89d55c12017-10-11 11:29:01 -0700392 copy(mLastHealthInfo, info);
Todd Poynor26faecc2013-05-22 18:54:48 -0700393 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700394 }
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700395 traceEnd();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800397
Yifan Hong932190b2017-10-11 11:00:51 -0700398 private static void copy(HealthInfo dst, HealthInfo src) {
399 dst.legacy.chargerAcOnline = src.legacy.chargerAcOnline;
400 dst.legacy.chargerUsbOnline = src.legacy.chargerUsbOnline;
401 dst.legacy.chargerWirelessOnline = src.legacy.chargerWirelessOnline;
402 dst.legacy.maxChargingCurrent = src.legacy.maxChargingCurrent;
403 dst.legacy.maxChargingVoltage = src.legacy.maxChargingVoltage;
404 dst.legacy.batteryStatus = src.legacy.batteryStatus;
405 dst.legacy.batteryHealth = src.legacy.batteryHealth;
406 dst.legacy.batteryPresent = src.legacy.batteryPresent;
407 dst.legacy.batteryLevel = src.legacy.batteryLevel;
408 dst.legacy.batteryVoltage = src.legacy.batteryVoltage;
409 dst.legacy.batteryTemperature = src.legacy.batteryTemperature;
410 dst.legacy.batteryCurrent = src.legacy.batteryCurrent;
411 dst.legacy.batteryCycleCount = src.legacy.batteryCycleCount;
412 dst.legacy.batteryFullCharge = src.legacy.batteryFullCharge;
413 dst.legacy.batteryChargeCounter = src.legacy.batteryChargeCounter;
414 dst.legacy.batteryTechnology = src.legacy.batteryTechnology;
415 dst.batteryCurrentAverage = src.batteryCurrentAverage;
416 dst.batteryCapacity = src.batteryCapacity;
417 dst.energyCounter = src.energyCounter;
418 }
419
Dianne Hackborn14272302014-06-10 23:13:02 -0700420 private void processValuesLocked(boolean force) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700421 boolean logOutlier = false;
422 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700423
Yifan Hong932190b2017-10-11 11:00:51 -0700424 mBatteryLevelCritical = (mHealthInfo.legacy.batteryLevel <= mCriticalBatteryLevel);
425 if (mHealthInfo.legacy.chargerAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
Yifan Hong932190b2017-10-11 11:00:51 -0700427 } else if (mHealthInfo.legacy.chargerUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800428 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
Yifan Hong932190b2017-10-11 11:00:51 -0700429 } else if (mHealthInfo.legacy.chargerWirelessOnline) {
Brian Muramatsu37a37f42012-08-14 15:21:02 -0700430 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800431 } else {
432 mPlugType = BATTERY_PLUGGED_NONE;
433 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700434
Jeff Browna4d82042012-10-02 19:11:19 -0700435 if (DEBUG) {
436 Slog.d(TAG, "Processing new values: "
Yifan Hong932190b2017-10-11 11:00:51 -0700437 + "info=" + mHealthInfo
Jeff Browna4d82042012-10-02 19:11:19 -0700438 + ", mBatteryLevelCritical=" + mBatteryLevelCritical
439 + ", mPlugType=" + mPlugType);
440 }
441
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700442 // Let the battery stats keep track of the current level.
443 try {
Yifan Hong932190b2017-10-11 11:00:51 -0700444 mBatteryStats.setBatteryState(mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth,
445 mPlugType, mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryTemperature,
446 mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryChargeCounter,
447 mHealthInfo.legacy.batteryFullCharge);
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700448 } catch (RemoteException e) {
449 // Should never happen.
450 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700451
Jeff Browna4d82042012-10-02 19:11:19 -0700452 shutdownIfNoPowerLocked();
453 shutdownIfOverTempLocked();
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700454
Yifan Hong932190b2017-10-11 11:00:51 -0700455 if (force || (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
456 mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
457 mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
458 mHealthInfo.legacy.batteryLevel != mLastBatteryLevel ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 mPlugType != mLastPlugType ||
Yifan Hong932190b2017-10-11 11:00:51 -0700460 mHealthInfo.legacy.batteryVoltage != mLastBatteryVoltage ||
461 mHealthInfo.legacy.batteryTemperature != mLastBatteryTemperature ||
462 mHealthInfo.legacy.maxChargingCurrent != mLastMaxChargingCurrent ||
463 mHealthInfo.legacy.maxChargingVoltage != mLastMaxChargingVoltage ||
464 mHealthInfo.legacy.batteryChargeCounter != mLastChargeCounter ||
Dianne Hackborn14272302014-06-10 23:13:02 -0700465 mInvalidCharger != mLastInvalidCharger)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800466
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800467 if (mPlugType != mLastPlugType) {
468 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
469 // discharging -> charging
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800470
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800471 // There's no value in this data unless we've discharged at least once and the
472 // battery level has changed; so don't log until it does.
Yifan Hong932190b2017-10-11 11:00:51 -0700473 if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.legacy.batteryLevel) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700474 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
475 logOutlier = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800476 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
Yifan Hong932190b2017-10-11 11:00:51 -0700477 mDischargeStartLevel, mHealthInfo.legacy.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800478 // make sure we see a discharge event before logging again
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800479 mDischargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 }
481 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
482 // charging -> discharging or we just powered up
483 mDischargeStartTime = SystemClock.elapsedRealtime();
Yifan Hong932190b2017-10-11 11:00:51 -0700484 mDischargeStartLevel = mHealthInfo.legacy.batteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800485 }
486 }
Yifan Hong932190b2017-10-11 11:00:51 -0700487 if (mHealthInfo.legacy.batteryStatus != mLastBatteryStatus ||
488 mHealthInfo.legacy.batteryHealth != mLastBatteryHealth ||
489 mHealthInfo.legacy.batteryPresent != mLastBatteryPresent ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800490 mPlugType != mLastPlugType) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800491 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
Yifan Hong932190b2017-10-11 11:00:51 -0700492 mHealthInfo.legacy.batteryStatus, mHealthInfo.legacy.batteryHealth, mHealthInfo.legacy.batteryPresent ? 1 : 0,
493 mPlugType, mHealthInfo.legacy.batteryTechnology);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 }
Yifan Hong932190b2017-10-11 11:00:51 -0700495 if (mHealthInfo.legacy.batteryLevel != mLastBatteryLevel) {
Dianne Hackborncf1171642013-07-12 17:26:02 -0700496 // Don't do this just from voltage or temperature changes, that is
497 // too noisy.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800498 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
Yifan Hong932190b2017-10-11 11:00:51 -0700499 mHealthInfo.legacy.batteryLevel, mHealthInfo.legacy.batteryVoltage, mHealthInfo.legacy.batteryTemperature);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800500 }
501 if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
502 mPlugType == BATTERY_PLUGGED_NONE) {
503 // We want to make sure we log discharge cycle outliers
504 // if the battery is about to die.
The Android Open Source Project10592532009-03-18 17:39:46 -0700505 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
506 logOutlier = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800507 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800508
Dianne Hackborn14272302014-06-10 23:13:02 -0700509 if (!mBatteryLevelLow) {
510 // Should we now switch in to low battery mode?
511 if (mPlugType == BATTERY_PLUGGED_NONE
Yifan Hong932190b2017-10-11 11:00:51 -0700512 && mHealthInfo.legacy.batteryLevel <= mLowBatteryWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700513 mBatteryLevelLow = true;
514 }
515 } else {
516 // Should we now switch out of low battery mode?
517 if (mPlugType != BATTERY_PLUGGED_NONE) {
518 mBatteryLevelLow = false;
Yifan Hong932190b2017-10-11 11:00:51 -0700519 } else if (mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700520 mBatteryLevelLow = false;
Yifan Hong932190b2017-10-11 11:00:51 -0700521 } else if (force && mHealthInfo.legacy.batteryLevel >= mLowBatteryWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700522 // If being forced, the previous state doesn't matter, we will just
523 // absolutely check to see if we are now above the warning level.
524 mBatteryLevelLow = false;
525 }
526 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800527
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800528 mSequence++;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800529
Christopher Tate06ba5542009-04-09 16:03:56 -0700530 // Separate broadcast is sent for power connected / not connected
531 // since the standard intent will not wake any applications and some
532 // applications may want to have smart behavior based on this.
533 if (mPlugType != 0 && mLastPlugType == 0) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800534 final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
535 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
536 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700537 mHandler.post(new Runnable() {
538 @Override
539 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700540 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
541 }
542 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700543 }
544 else if (mPlugType == 0 && mLastPlugType != 0) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800545 final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
546 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
547 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700548 mHandler.post(new Runnable() {
549 @Override
550 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700551 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
552 }
553 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700554 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200555
Dianne Hackborn14272302014-06-10 23:13:02 -0700556 if (shouldSendBatteryLowLocked()) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700557 mSentLowBatteryBroadcast = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800558 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
559 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
560 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700561 mHandler.post(new Runnable() {
562 @Override
563 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700564 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
565 }
566 });
Dianne Hackborn532ea262017-03-17 17:50:55 -0700567 } else if (mSentLowBatteryBroadcast &&
Yifan Hong932190b2017-10-11 11:00:51 -0700568 mHealthInfo.legacy.batteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700569 mSentLowBatteryBroadcast = false;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800570 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
571 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
572 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700573 mHandler.post(new Runnable() {
574 @Override
575 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700576 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
577 }
578 });
Mihai Predaa82842f2009-04-29 15:05:56 +0200579 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800580
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800581 // We are doing this after sending the above broadcasts, so anything processing
582 // them will get the new sequence number at that point. (See for example how testing
583 // of JobScheduler's BatteryController works.)
584 sendIntentLocked();
585
Joe Onoratode1b3592010-10-25 20:36:47 -0700586 // Update the battery LED
587 mLed.updateLightsLocked();
588
The Android Open Source Project10592532009-03-18 17:39:46 -0700589 // This needs to be done after sendIntent() so that we get the lastest battery stats.
590 if (logOutlier && dischargeDuration != 0) {
Jeff Browna4d82042012-10-02 19:11:19 -0700591 logOutlierLocked(dischargeDuration);
The Android Open Source Project10592532009-03-18 17:39:46 -0700592 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800593
Yifan Hong932190b2017-10-11 11:00:51 -0700594 mLastBatteryStatus = mHealthInfo.legacy.batteryStatus;
595 mLastBatteryHealth = mHealthInfo.legacy.batteryHealth;
596 mLastBatteryPresent = mHealthInfo.legacy.batteryPresent;
597 mLastBatteryLevel = mHealthInfo.legacy.batteryLevel;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700598 mLastPlugType = mPlugType;
Yifan Hong932190b2017-10-11 11:00:51 -0700599 mLastBatteryVoltage = mHealthInfo.legacy.batteryVoltage;
600 mLastBatteryTemperature = mHealthInfo.legacy.batteryTemperature;
601 mLastMaxChargingCurrent = mHealthInfo.legacy.maxChargingCurrent;
602 mLastMaxChargingVoltage = mHealthInfo.legacy.maxChargingVoltage;
603 mLastChargeCounter = mHealthInfo.legacy.batteryChargeCounter;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700604 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400605 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800606 }
607 }
608
Jeff Browna4d82042012-10-02 19:11:19 -0700609 private void sendIntentLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 // Pack up the values and broadcast them to everyone
Jeff Brown605ea692012-10-05 16:33:10 -0700611 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800612 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
613 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800614
Yifan Hong932190b2017-10-11 11:00:51 -0700615 int icon = getIconLocked(mHealthInfo.legacy.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800617 intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Yifan Hong932190b2017-10-11 11:00:51 -0700618 intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.legacy.batteryStatus);
619 intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.legacy.batteryHealth);
620 intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.legacy.batteryPresent);
621 intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.legacy.batteryLevel);
Dianne Hackbornedd93162009-09-19 14:03:05 -0700622 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
623 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
624 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
Yifan Hong932190b2017-10-11 11:00:51 -0700625 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.legacy.batteryVoltage);
626 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
627 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400628 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
Yifan Hong932190b2017-10-11 11:00:51 -0700629 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
630 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
631 intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
Jeff Browna4d82042012-10-02 19:11:19 -0700632 if (DEBUG) {
Yifan Hong932190b2017-10-11 11:00:51 -0700633 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
634 + ", info:" + mHealthInfo.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 }
636
Jeff Brown605ea692012-10-05 16:33:10 -0700637 mHandler.post(new Runnable() {
638 @Override
639 public void run() {
Sudheer Shankadc589ac2016-11-10 15:30:17 -0800640 ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL);
Jeff Brown605ea692012-10-05 16:33:10 -0700641 }
642 });
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800643 }
644
Jeff Browna4d82042012-10-02 19:11:19 -0700645 private void logBatteryStatsLocked() {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700646 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800647 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648
Dan Egnor18e93962010-02-10 19:27:58 -0800649 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
650 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
651
652 File dumpFile = null;
653 FileOutputStream dumpStream = null;
654 try {
655 // dump the service to a file
Dianne Hackborn8c841092013-06-24 13:46:13 -0700656 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
Dan Egnor18e93962010-02-10 19:27:58 -0800657 dumpStream = new FileOutputStream(dumpFile);
658 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -0700659 FileUtils.sync(dumpStream);
Dan Egnor18e93962010-02-10 19:27:58 -0800660
661 // add dump file to drop box
662 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
663 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800664 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800665 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800666 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800667 } finally {
668 // make sure we clean up
669 if (dumpStream != null) {
670 try {
671 dumpStream.close();
672 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800673 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800674 }
Dan Egnor18e93962010-02-10 19:27:58 -0800675 }
676 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800677 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800678 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 }
680 }
681 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800682
Jeff Browna4d82042012-10-02 19:11:19 -0700683 private void logOutlierLocked(long duration) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 ContentResolver cr = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -0700685 String dischargeThresholdString = Settings.Global.getString(cr,
686 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
687 String durationThresholdString = Settings.Global.getString(cr,
688 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 if (dischargeThresholdString != null && durationThresholdString != null) {
691 try {
692 long durationThreshold = Long.parseLong(durationThresholdString);
693 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800694 if (duration <= durationThreshold &&
Yifan Hong932190b2017-10-11 11:00:51 -0700695 mDischargeStartLevel - mHealthInfo.legacy.batteryLevel >= dischargeThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800696 // If the discharge cycle is bad enough we want to know about it.
Jeff Browna4d82042012-10-02 19:11:19 -0700697 logBatteryStatsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
Jeff Browna4d82042012-10-02 19:11:19 -0700699 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800700 " discharge threshold: " + dischargeThreshold);
Jeff Browna4d82042012-10-02 19:11:19 -0700701 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
Yifan Hong932190b2017-10-11 11:00:51 -0700702 (mDischargeStartLevel - mHealthInfo.legacy.batteryLevel));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800704 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800705 durationThresholdString + " or " + dischargeThresholdString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800706 }
707 }
708 }
709
Jeff Browna4d82042012-10-02 19:11:19 -0700710 private int getIconLocked(int level) {
Yifan Hong932190b2017-10-11 11:00:51 -0700711 if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800712 return com.android.internal.R.drawable.stat_sys_battery_charge;
Yifan Hong932190b2017-10-11 11:00:51 -0700713 } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800714 return com.android.internal.R.drawable.stat_sys_battery;
Yifan Hong932190b2017-10-11 11:00:51 -0700715 } else if (mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
716 || mHealthInfo.legacy.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
Jeff Browna4d82042012-10-02 19:11:19 -0700717 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
Yifan Hong932190b2017-10-11 11:00:51 -0700718 && mHealthInfo.legacy.batteryLevel >= 100) {
Joe Onorato794be402010-11-21 19:22:25 -0800719 return com.android.internal.R.drawable.stat_sys_battery_charge;
720 } else {
721 return com.android.internal.R.drawable.stat_sys_battery;
722 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800723 } else {
724 return com.android.internal.R.drawable.stat_sys_battery_unknown;
725 }
726 }
727
Dianne Hackborn2e441072015-10-28 18:00:57 -0700728 class Shell extends ShellCommand {
729 @Override
730 public int onCommand(String cmd) {
731 return onShellCommand(this, cmd);
732 }
733
734 @Override
735 public void onHelp() {
736 PrintWriter pw = getOutPrintWriter();
737 dumpHelp(pw);
738 }
739 }
740
741 static void dumpHelp(PrintWriter pw) {
742 pw.println("Battery service (battery) commands:");
743 pw.println(" help");
744 pw.println(" Print this help text.");
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700745 pw.println(" set [-f] [ac|usb|wireless|status|level|temp|present|invalid] <value>");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700746 pw.println(" Force a battery property value, freezing battery state.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800747 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
748 pw.println(" unplug [-f]");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700749 pw.println(" Force battery unplugged, freezing battery state.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800750 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
751 pw.println(" reset [-f]");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700752 pw.println(" Unfreeze battery state, returning to current hardware values.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800753 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
754 }
755
756 static final int OPTION_FORCE_UPDATE = 1<<0;
757
758 int parseOptions(Shell shell) {
759 String opt;
760 int opts = 0;
761 while ((opt = shell.getNextOption()) != null) {
762 if ("-f".equals(opt)) {
763 opts |= OPTION_FORCE_UPDATE;
764 }
765 }
766 return opts;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700767 }
768
769 int onShellCommand(Shell shell, String cmd) {
770 if (cmd == null) {
771 return shell.handleDefaultCommands(cmd);
772 }
773 PrintWriter pw = shell.getOutPrintWriter();
774 switch (cmd) {
775 case "unplug": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800776 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700777 getContext().enforceCallingOrSelfPermission(
778 android.Manifest.permission.DEVICE_POWER, null);
779 if (!mUpdatesStopped) {
Yifan Hong932190b2017-10-11 11:00:51 -0700780 copy(mLastHealthInfo, mHealthInfo);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700781 }
Yifan Hong932190b2017-10-11 11:00:51 -0700782 mHealthInfo.legacy.chargerAcOnline = false;
783 mHealthInfo.legacy.chargerUsbOnline = false;
784 mHealthInfo.legacy.chargerWirelessOnline = false;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700785 long ident = Binder.clearCallingIdentity();
786 try {
787 mUpdatesStopped = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800788 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700789 } finally {
790 Binder.restoreCallingIdentity(ident);
791 }
792 } break;
793 case "set": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800794 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700795 getContext().enforceCallingOrSelfPermission(
796 android.Manifest.permission.DEVICE_POWER, null);
797 final String key = shell.getNextArg();
798 if (key == null) {
799 pw.println("No property specified");
800 return -1;
801
802 }
803 final String value = shell.getNextArg();
804 if (value == null) {
805 pw.println("No value specified");
806 return -1;
807
808 }
809 try {
810 if (!mUpdatesStopped) {
Yifan Hong932190b2017-10-11 11:00:51 -0700811 copy(mLastHealthInfo, mHealthInfo);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700812 }
813 boolean update = true;
814 switch (key) {
Christopher Tate630d98b2017-03-07 14:12:26 -0800815 case "present":
Yifan Hong932190b2017-10-11 11:00:51 -0700816 mHealthInfo.legacy.batteryPresent = Integer.parseInt(value) != 0;
Christopher Tate630d98b2017-03-07 14:12:26 -0800817 break;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700818 case "ac":
Yifan Hong932190b2017-10-11 11:00:51 -0700819 mHealthInfo.legacy.chargerAcOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700820 break;
821 case "usb":
Yifan Hong932190b2017-10-11 11:00:51 -0700822 mHealthInfo.legacy.chargerUsbOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700823 break;
824 case "wireless":
Yifan Hong932190b2017-10-11 11:00:51 -0700825 mHealthInfo.legacy.chargerWirelessOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700826 break;
827 case "status":
Yifan Hong932190b2017-10-11 11:00:51 -0700828 mHealthInfo.legacy.batteryStatus = Integer.parseInt(value);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700829 break;
830 case "level":
Yifan Hong932190b2017-10-11 11:00:51 -0700831 mHealthInfo.legacy.batteryLevel = Integer.parseInt(value);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700832 break;
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700833 case "temp":
Yifan Hong932190b2017-10-11 11:00:51 -0700834 mHealthInfo.legacy.batteryTemperature = Integer.parseInt(value);
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700835 break;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700836 case "invalid":
837 mInvalidCharger = Integer.parseInt(value);
838 break;
839 default:
840 pw.println("Unknown set option: " + key);
841 update = false;
842 break;
843 }
844 if (update) {
845 long ident = Binder.clearCallingIdentity();
846 try {
847 mUpdatesStopped = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800848 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700849 } finally {
850 Binder.restoreCallingIdentity(ident);
851 }
852 }
853 } catch (NumberFormatException ex) {
854 pw.println("Bad value: " + value);
855 return -1;
856 }
857 } break;
858 case "reset": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800859 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700860 getContext().enforceCallingOrSelfPermission(
861 android.Manifest.permission.DEVICE_POWER, null);
862 long ident = Binder.clearCallingIdentity();
863 try {
864 if (mUpdatesStopped) {
865 mUpdatesStopped = false;
Yifan Hong932190b2017-10-11 11:00:51 -0700866 copy(mHealthInfo, mLastHealthInfo);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800867 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700868 }
869 } finally {
870 Binder.restoreCallingIdentity(ident);
871 }
872 } break;
873 default:
874 return shell.handleDefaultCommands(cmd);
875 }
876 return 0;
877 }
878
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800879 private void processValuesFromShellLocked(PrintWriter pw, int opts) {
880 processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
881 if ((opts & OPTION_FORCE_UPDATE) != 0) {
882 pw.println(mSequence);
883 }
884 }
885
Dianne Hackborn2e441072015-10-28 18:00:57 -0700886 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna4d82042012-10-02 19:11:19 -0700887 synchronized (mLock) {
888 if (args == null || args.length == 0 || "-a".equals(args[0])) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700889 pw.println("Current Battery Service state:");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700890 if (mUpdatesStopped) {
891 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
892 }
Yifan Hong932190b2017-10-11 11:00:51 -0700893 pw.println(" AC powered: " + mHealthInfo.legacy.chargerAcOnline);
894 pw.println(" USB powered: " + mHealthInfo.legacy.chargerUsbOnline);
895 pw.println(" Wireless powered: " + mHealthInfo.legacy.chargerWirelessOnline);
896 pw.println(" Max charging current: " + mHealthInfo.legacy.maxChargingCurrent);
897 pw.println(" Max charging voltage: " + mHealthInfo.legacy.maxChargingVoltage);
898 pw.println(" Charge counter: " + mHealthInfo.legacy.batteryChargeCounter);
899 pw.println(" status: " + mHealthInfo.legacy.batteryStatus);
900 pw.println(" health: " + mHealthInfo.legacy.batteryHealth);
901 pw.println(" present: " + mHealthInfo.legacy.batteryPresent);
902 pw.println(" level: " + mHealthInfo.legacy.batteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700903 pw.println(" scale: " + BATTERY_SCALE);
Yifan Hong932190b2017-10-11 11:00:51 -0700904 pw.println(" voltage: " + mHealthInfo.legacy.batteryVoltage);
905 pw.println(" temperature: " + mHealthInfo.legacy.batteryTemperature);
906 pw.println(" technology: " + mHealthInfo.legacy.batteryTechnology);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700907 } else {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700908 Shell shell = new Shell();
Dianne Hackborn354736e2016-08-22 17:00:05 -0700909 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700910 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800911 }
912 }
Joe Onoratode1b3592010-10-25 20:36:47 -0700913
Netta Pe2a3cd82017-01-26 18:03:51 -0800914 private void dumpProto(FileDescriptor fd) {
915 final ProtoOutputStream proto = new ProtoOutputStream(fd);
916
917 synchronized (mLock) {
918 proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
Kweku Adamse6b00c22017-10-23 16:46:45 -0700919 int batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_NONE;
Yifan Hong932190b2017-10-11 11:00:51 -0700920 if (mHealthInfo.legacy.chargerAcOnline) {
Kweku Adamse6b00c22017-10-23 16:46:45 -0700921 batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_AC;
Yifan Hong932190b2017-10-11 11:00:51 -0700922 } else if (mHealthInfo.legacy.chargerUsbOnline) {
Kweku Adamse6b00c22017-10-23 16:46:45 -0700923 batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_USB;
Yifan Hong932190b2017-10-11 11:00:51 -0700924 } else if (mHealthInfo.legacy.chargerWirelessOnline) {
Kweku Adamse6b00c22017-10-23 16:46:45 -0700925 batteryPluggedValue = BatteryManagerProto.PLUG_TYPE_WIRELESS;
Netta Pe2a3cd82017-01-26 18:03:51 -0800926 }
927 proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
Yifan Hong932190b2017-10-11 11:00:51 -0700928 proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.legacy.maxChargingCurrent);
929 proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.legacy.maxChargingVoltage);
930 proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.legacy.batteryChargeCounter);
931 proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.legacy.batteryStatus);
932 proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.legacy.batteryHealth);
933 proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.legacy.batteryPresent);
934 proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.legacy.batteryLevel);
Netta Pe2a3cd82017-01-26 18:03:51 -0800935 proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
Yifan Hong932190b2017-10-11 11:00:51 -0700936 proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.legacy.batteryVoltage);
937 proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.legacy.batteryTemperature);
938 proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.legacy.batteryTechnology);
Netta Pe2a3cd82017-01-26 18:03:51 -0800939 }
940 proto.flush();
941 }
942
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700943 private static void traceBegin(String name) {
944 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
945 }
946
947 private static void traceEnd() {
948 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
949 }
950
Jeff Browna4d82042012-10-02 19:11:19 -0700951 private final class Led {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800952 private final Light mBatteryLight;
Joe Onoratode1b3592010-10-25 20:36:47 -0700953
Jeff Browna4d82042012-10-02 19:11:19 -0700954 private final int mBatteryLowARGB;
955 private final int mBatteryMediumARGB;
956 private final int mBatteryFullARGB;
957 private final int mBatteryLedOn;
958 private final int mBatteryLedOff;
959
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800960 public Led(Context context, LightsManager lights) {
961 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
Joe Onoratode1b3592010-10-25 20:36:47 -0700962
Jeff Browna4d82042012-10-02 19:11:19 -0700963 mBatteryLowARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700964 com.android.internal.R.integer.config_notificationsBatteryLowARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700965 mBatteryMediumARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700966 com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700967 mBatteryFullARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700968 com.android.internal.R.integer.config_notificationsBatteryFullARGB);
Jeff Browna4d82042012-10-02 19:11:19 -0700969 mBatteryLedOn = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700970 com.android.internal.R.integer.config_notificationsBatteryLedOn);
Jeff Browna4d82042012-10-02 19:11:19 -0700971 mBatteryLedOff = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -0700972 com.android.internal.R.integer.config_notificationsBatteryLedOff);
973 }
974
975 /**
976 * Synchronize on BatteryService.
977 */
Jeff Browna4d82042012-10-02 19:11:19 -0700978 public void updateLightsLocked() {
Yifan Hong932190b2017-10-11 11:00:51 -0700979 final int level = mHealthInfo.legacy.batteryLevel;
980 final int status = mHealthInfo.legacy.batteryStatus;
Joe Onoratode1b3592010-10-25 20:36:47 -0700981 if (level < mLowBatteryWarningLevel) {
982 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
983 // Solid red when battery is charging
984 mBatteryLight.setColor(mBatteryLowARGB);
985 } else {
986 // Flash red when battery is low and not charging
Adam Lesinskief2ea1f2013-12-05 16:48:06 -0800987 mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
Joe Onoratode1b3592010-10-25 20:36:47 -0700988 mBatteryLedOn, mBatteryLedOff);
989 }
990 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
991 || status == BatteryManager.BATTERY_STATUS_FULL) {
992 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
993 // Solid green when full or charging and nearly full
994 mBatteryLight.setColor(mBatteryFullARGB);
995 } else {
996 // Solid orange when charging and halfway full
997 mBatteryLight.setColor(mBatteryMediumARGB);
998 }
999 } else {
1000 // No lights if not charging and not low
1001 mBatteryLight.turnOff();
1002 }
1003 }
1004 }
Todd Poynor26faecc2013-05-22 18:54:48 -07001005
Yifan Hong89d55c12017-10-11 11:29:01 -07001006 private final class HealthHalCallback extends IHealthInfoCallback.Stub
1007 implements HealthServiceWrapper.Callback {
1008 @Override public void healthInfoChanged(HealthInfo props) {
1009 BatteryService.this.update(props);
1010 }
1011 // on new service registered
1012 @Override public void onRegistration(IHealth oldService, IHealth newService,
1013 String instance) {
1014 if (newService == null) return;
1015
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001016 traceBegin("HealthUnregisterCallback");
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001017 try {
Yifan Hong89d55c12017-10-11 11:29:01 -07001018 if (oldService != null) {
1019 int r = oldService.unregisterCallback(this);
1020 if (r != Result.SUCCESS) {
1021 Slog.w(TAG, "health: cannot unregister previous callback: " +
1022 Result.toString(r));
1023 }
1024 }
1025 } catch (RemoteException ex) {
1026 Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
1027 + ex.getMessage());
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001028 } finally {
1029 traceEnd();
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001030 }
Yifan Hong89d55c12017-10-11 11:29:01 -07001031
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001032 traceBegin("HealthRegisterCallback");
Yifan Hong89d55c12017-10-11 11:29:01 -07001033 try {
1034 int r = newService.registerCallback(this);
1035 if (r != Result.SUCCESS) {
1036 Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
1037 return;
1038 }
1039 // registerCallback does NOT guarantee that update is called
1040 // immediately, so request a manual update here.
1041 newService.update();
1042 } catch (RemoteException ex) {
1043 Slog.e(TAG, "health: cannot register callback (transaction error): "
1044 + ex.getMessage());
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001045 } finally {
1046 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -07001047 }
1048 }
Todd Poynor26faecc2013-05-22 18:54:48 -07001049 }
Jeff Brown21392762014-06-13 19:00:36 -07001050
1051 private final class BinderService extends Binder {
Dianne Hackborn2e441072015-10-28 18:00:57 -07001052 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001053 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown21392762014-06-13 19:00:36 -07001054
Netta Pe2a3cd82017-01-26 18:03:51 -08001055 if (args.length > 0 && "--proto".equals(args[0])) {
1056 dumpProto(fd);
1057 } else {
1058 dumpInternal(fd, pw, args);
1059 }
Dianne Hackborn2e441072015-10-28 18:00:57 -07001060 }
1061
1062 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001063 FileDescriptor err, String[] args, ShellCallback callback,
1064 ResultReceiver resultReceiver) {
1065 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Jeff Brown21392762014-06-13 19:00:36 -07001066 }
1067 }
1068
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001069 // Reduced IBatteryPropertiesRegistrar that only implements getProperty for usage
1070 // in BatteryManager.
1071 private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {
1072 public void registerListener(IBatteryPropertiesListener listener) {
1073 Slog.e(TAG, "health: must not call registerListener on battery properties");
1074 }
1075 public void unregisterListener(IBatteryPropertiesListener listener) {
1076 Slog.e(TAG, "health: must not call unregisterListener on battery properties");
1077 }
1078 public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001079 traceBegin("HealthGetProperty");
1080 try {
1081 IHealth service = mHealthServiceWrapper.getLastService();
1082 if (service == null) throw new RemoteException("no health service");
1083 final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
1084 switch(id) {
1085 case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
1086 service.getChargeCounter((int result, int value) -> {
1087 outResult.value = result;
1088 if (result == Result.SUCCESS) prop.setLong(value);
1089 });
1090 break;
1091 case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
1092 service.getCurrentNow((int result, int value) -> {
1093 outResult.value = result;
1094 if (result == Result.SUCCESS) prop.setLong(value);
1095 });
1096 break;
1097 case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
1098 service.getCurrentAverage((int result, int value) -> {
1099 outResult.value = result;
1100 if (result == Result.SUCCESS) prop.setLong(value);
1101 });
1102 break;
1103 case BatteryManager.BATTERY_PROPERTY_CAPACITY:
1104 service.getCapacity((int result, int value) -> {
1105 outResult.value = result;
1106 if (result == Result.SUCCESS) prop.setLong(value);
1107 });
1108 break;
1109 case BatteryManager.BATTERY_PROPERTY_STATUS:
1110 service.getChargeStatus((int result, int value) -> {
1111 outResult.value = result;
1112 if (result == Result.SUCCESS) prop.setLong(value);
1113 });
1114 break;
1115 case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
1116 service.getEnergyCounter((int result, long value) -> {
1117 outResult.value = result;
1118 if (result == Result.SUCCESS) prop.setLong(value);
1119 });
1120 break;
1121 }
1122 return outResult.value;
1123 } finally {
1124 traceEnd();
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001125 }
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001126 }
Yifan Hong7838fcb2017-10-24 16:06:27 -07001127 public void scheduleUpdate() throws RemoteException {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001128 traceBegin("HealthScheduleUpdate");
1129 try {
1130 IHealth service = mHealthServiceWrapper.getLastService();
1131 if (service == null) throw new RemoteException("no health service");
1132 service.update();
1133 } finally {
1134 traceEnd();
1135 }
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001136 }
1137 }
1138
Jeff Brown21392762014-06-13 19:00:36 -07001139 private final class LocalService extends BatteryManagerInternal {
1140 @Override
1141 public boolean isPowered(int plugTypeSet) {
1142 synchronized (mLock) {
1143 return isPoweredLocked(plugTypeSet);
1144 }
1145 }
1146
1147 @Override
1148 public int getPlugType() {
1149 synchronized (mLock) {
1150 return mPlugType;
1151 }
1152 }
1153
1154 @Override
1155 public int getBatteryLevel() {
1156 synchronized (mLock) {
Yifan Hong932190b2017-10-11 11:00:51 -07001157 return mHealthInfo.legacy.batteryLevel;
Jeff Brown21392762014-06-13 19:00:36 -07001158 }
1159 }
1160
1161 @Override
1162 public boolean getBatteryLevelLow() {
1163 synchronized (mLock) {
1164 return mBatteryLevelLow;
1165 }
1166 }
1167
1168 @Override
1169 public int getInvalidCharger() {
1170 synchronized (mLock) {
1171 return mInvalidCharger;
1172 }
1173 }
1174 }
Yifan Hong98852792017-10-12 11:35:14 -07001175
1176 /**
1177 * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
1178 * necessary.
1179 *
1180 * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
1181 * the internal service is refreshed.
1182 * On death of an existing IHealth service, the internal service is NOT cleared to avoid
1183 * race condition between death notification and new service notification. Hence,
1184 * a caller must check for transaction errors when calling into the service.
1185 *
1186 * @hide Should only be used internally.
1187 */
1188 @VisibleForTesting
1189 static final class HealthServiceWrapper {
1190 private static final String TAG = "HealthServiceWrapper";
1191 public static final String INSTANCE_HEALTHD = "backup";
1192 public static final String INSTANCE_VENDOR = "default";
1193 // All interesting instances, sorted by priority high -> low.
1194 private static final List<String> sAllInstances =
1195 Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
1196
1197 private final IServiceNotification mNotification = new Notification();
Yifan Hong1fff9842017-10-27 13:53:10 -07001198 // These variables are fixed after init.
Yifan Hong98852792017-10-12 11:35:14 -07001199 private Callback mCallback;
1200 private IHealthSupplier mHealthSupplier;
Yifan Hong1fff9842017-10-27 13:53:10 -07001201 private String mInstanceName;
Yifan Hong98852792017-10-12 11:35:14 -07001202
Yifan Hong89d55c12017-10-11 11:29:01 -07001203 private final Object mLastServiceSetLock = new Object();
1204 // Last IHealth service received.
1205 // set must be also be guarded with mLastServiceSetLock to ensure ordering.
1206 private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
1207
Yifan Hong98852792017-10-12 11:35:14 -07001208 /**
1209 * init should be called after constructor. For testing purposes, init is not called by
1210 * constructor.
1211 */
1212 HealthServiceWrapper() {
1213 }
1214
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001215 IHealth getLastService() {
1216 return mLastService.get();
1217 }
1218
Yifan Hong98852792017-10-12 11:35:14 -07001219 /**
1220 * Start monitoring registration of new IHealth services. Only instances that are in
1221 * {@code sAllInstances} and in device / framework manifest are used. This function should
1222 * only be called once.
1223 * @throws RemoteException transaction error when talking to IServiceManager
1224 * @throws NoSuchElementException if one of the following cases:
1225 * - No service manager;
1226 * - none of {@code sAllInstances} are in manifests (i.e. not
1227 * available on this device), or none of these instances are available to current
1228 * process.
1229 * @throws NullPointerException when callback is null or supplier is null
1230 */
1231 void init(Callback callback,
1232 IServiceManagerSupplier managerSupplier,
1233 IHealthSupplier healthSupplier)
1234 throws RemoteException, NoSuchElementException, NullPointerException {
1235 if (callback == null || managerSupplier == null || healthSupplier == null)
1236 throw new NullPointerException();
1237
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001238 IServiceManager manager;
1239
Yifan Hong98852792017-10-12 11:35:14 -07001240 mCallback = callback;
1241 mHealthSupplier = healthSupplier;
1242
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001243 traceBegin("HealthInitGetManager");
1244 try {
1245 manager = managerSupplier.get();
1246 } finally {
1247 traceEnd();
1248 }
Yifan Hong98852792017-10-12 11:35:14 -07001249 for (String name : sAllInstances) {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001250 traceBegin("HealthInitGetTransport_" + name);
1251 try {
1252 if (manager.getTransport(IHealth.kInterfaceName, name) !=
1253 IServiceManager.Transport.EMPTY) {
1254 mInstanceName = name;
1255 break;
1256 }
1257 } finally {
1258 traceEnd();
Yifan Hong98852792017-10-12 11:35:14 -07001259 }
Yifan Hong98852792017-10-12 11:35:14 -07001260 }
1261
Yifan Hong1fff9842017-10-27 13:53:10 -07001262 if (mInstanceName == null) {
1263 throw new NoSuchElementException(String.format(
1264 "No IHealth service instance among %s is available. Perhaps no permission?",
1265 sAllInstances.toString()));
1266 }
1267
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001268 traceBegin("HealthInitRegisterNotification");
1269 try {
1270 manager.registerForNotifications(IHealth.kInterfaceName, mInstanceName, mNotification);
1271 } finally {
1272 traceEnd();
1273 }
Yifan Hong1fff9842017-10-27 13:53:10 -07001274 Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
Yifan Hong98852792017-10-12 11:35:14 -07001275 }
1276
1277 interface Callback {
1278 /**
1279 * This function is invoked asynchronously when a new and related IServiceNotification
1280 * is received.
1281 * @param service the recently retrieved service from IServiceManager.
1282 * Can be a dead service before service notification of a new service is delivered.
1283 * Implementation must handle cases for {@link RemoteException}s when calling
1284 * into service.
1285 * @param instance instance name.
1286 */
Yifan Hong89d55c12017-10-11 11:29:01 -07001287 void onRegistration(IHealth oldService, IHealth newService, String instance);
Yifan Hong98852792017-10-12 11:35:14 -07001288 }
1289
1290 /**
1291 * Supplier of services.
1292 * Must not return null; throw {@link NoSuchElementException} if a service is not available.
1293 */
1294 interface IServiceManagerSupplier {
Yifan Hong89d55c12017-10-11 11:29:01 -07001295 default IServiceManager get() throws NoSuchElementException, RemoteException {
1296 return IServiceManager.getService();
1297 }
Yifan Hong98852792017-10-12 11:35:14 -07001298 }
1299 /**
1300 * Supplier of services.
1301 * Must not return null; throw {@link NoSuchElementException} if a service is not available.
1302 */
1303 interface IHealthSupplier {
Yifan Hong89d55c12017-10-11 11:29:01 -07001304 default IHealth get(String name) throws NoSuchElementException, RemoteException {
1305 return IHealth.getService(name);
1306 }
Yifan Hong98852792017-10-12 11:35:14 -07001307 }
1308
1309 private class Notification extends IServiceNotification.Stub {
1310 @Override
1311 public final void onRegistration(String interfaceName, String instanceName,
1312 boolean preexisting) {
1313 if (!IHealth.kInterfaceName.equals(interfaceName)) return;
Yifan Hong1fff9842017-10-27 13:53:10 -07001314 if (!mInstanceName.equals(instanceName)) return;
Yifan Hong98852792017-10-12 11:35:14 -07001315 try {
Yifan Hong89d55c12017-10-11 11:29:01 -07001316 // ensures the order of multiple onRegistration on different threads.
1317 synchronized (mLastServiceSetLock) {
1318 IHealth newService = mHealthSupplier.get(instanceName);
1319 IHealth oldService = mLastService.getAndSet(newService);
1320 Slog.i(TAG, "health: new instance registered " + instanceName);
1321 mCallback.onRegistration(oldService, newService, instanceName);
1322 }
Yifan Hong98852792017-10-12 11:35:14 -07001323 } catch (NoSuchElementException | RemoteException ex) {
1324 Slog.e(TAG, "health: Cannot get instance '" + instanceName + "': " +
1325 ex.getMessage() + ". Perhaps no permission?");
1326 }
1327 }
1328 }
1329 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001330}