blob: a85b69b528ddb15b026a1c161ecda962014a0180 [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
Beverlyc4eb9342018-05-10 15:46:03 -040019import static com.android.internal.logging.nano.MetricsProto.MetricsEvent;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080020
Sudheer Shankadc589ac2016-11-10 15:30:17 -080021import android.app.ActivityManager;
Beverlyc4eb9342018-05-10 15:46:03 -040022import android.app.ActivityManagerInternal;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023import android.content.ContentResolver;
24import android.content.Context;
25import android.content.Intent;
Beverlyc4eb9342018-05-10 15:46:03 -040026import android.database.ContentObserver;
27import android.hardware.health.V1_0.HealthInfo;
28import android.hardware.health.V2_0.IHealth;
29import android.hardware.health.V2_0.IHealthInfoCallback;
30import android.hardware.health.V2_0.Result;
Yifan Hong98852792017-10-12 11:35:14 -070031import android.hidl.manager.V1_0.IServiceManager;
32import android.hidl.manager.V1_0.IServiceNotification;
Beverlyc4eb9342018-05-10 15:46:03 -040033import android.metrics.LogMaker;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034import android.os.BatteryManager;
Jeff Brown21392762014-06-13 19:00:36 -070035import android.os.BatteryManagerInternal;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070036import android.os.BatteryProperty;
Beverlyc4eb9342018-05-10 15:46:03 -040037import android.os.BatteryStats;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080038import android.os.Binder;
Beverlyc4eb9342018-05-10 15:46:03 -040039import android.os.Bundle;
Bookatz1a1b0462018-01-12 11:47:03 -080040import android.os.DropBoxManager;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070041import android.os.FileUtils;
Jeff Brown605ea692012-10-05 16:33:10 -070042import android.os.Handler;
Yifan Hongcf9a8b22017-11-02 18:43:06 -070043import android.os.HandlerThread;
Todd Poynor26faecc2013-05-22 18:54:48 -070044import android.os.IBatteryPropertiesRegistrar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080045import android.os.IBinder;
Bookatz1a1b0462018-01-12 11:47:03 -080046import android.os.OsProtoEnums;
Beverlyc4eb9342018-05-10 15:46:03 -040047import android.os.PowerManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.RemoteException;
Beverlyc4eb9342018-05-10 15:46:03 -040049import android.os.ResultReceiver;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080050import android.os.ServiceManager;
Beverlyc4eb9342018-05-10 15:46:03 -040051import android.os.ShellCallback;
52import android.os.ShellCommand;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053import android.os.SystemClock;
Yifan Hong8cc18ef2017-10-31 12:27:47 -070054import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070056import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.provider.Settings;
Netta Pe2a3cd82017-01-26 18:03:51 -080058import android.service.battery.BatteryServiceDumpProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080059import android.util.EventLog;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070060import android.util.MutableInt;
Joe Onorato8a9b2202010-02-26 18:56:32 -080061import android.util.Slog;
Netta Pe2a3cd82017-01-26 18:03:51 -080062import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063
Beverlyc4eb9342018-05-10 15:46:03 -040064import com.android.internal.annotations.VisibleForTesting;
65import com.android.internal.app.IBatteryStats;
66import com.android.internal.logging.MetricsLogger;
67import com.android.internal.util.DumpUtils;
68import com.android.server.am.BatteryStatsService;
69import com.android.server.lights.Light;
70import com.android.server.lights.LightsManager;
71
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import java.io.File;
73import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074import java.io.FileOutputStream;
75import java.io.IOException;
76import java.io.PrintWriter;
Fyodor Kupolov70e75432018-03-01 18:29:06 -080077import java.util.ArrayDeque;
78import java.util.ArrayList;
Yifan Hong98852792017-10-12 11:35:14 -070079import java.util.Arrays;
80import java.util.List;
81import java.util.NoSuchElementException;
Yifan Hongcf9a8b22017-11-02 18:43:06 -070082import java.util.Objects;
Yifan Hong89d55c12017-10-11 11:29:01 -070083import java.util.concurrent.atomic.AtomicReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084
85/**
86 * <p>BatteryService monitors the charging status, and charge level of the device
87 * battery. When these values change this service broadcasts the new values
88 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
89 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
90 * BATTERY_CHANGED} action.</p>
91 * <p>The new values are stored in the Intent data and can be retrieved by
92 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
93 * following keys:</p>
94 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
95 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
96 * <p>&quot;status&quot; - String, the current charging status.<br />
97 * <p>&quot;health&quot; - String, the current battery health.<br />
98 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
99 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
100 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
101 * into an AC power adapter; 2 if plugged in via USB.</p>
102 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
103 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
104 * a degree Centigrade</p>
105 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
Jeff Brown605ea692012-10-05 16:33:10 -0700106 *
107 * <p>
108 * The battery service may be called by the power manager while holding its locks so
109 * we take care to post all outcalls into the activity manager to a handler.
110 *
111 * FIXME: Ideally the power manager would perform all of its calls into the battery
112 * service asynchronously itself.
113 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800114 */
Jeff Brown21392762014-06-13 19:00:36 -0700115public final class BatteryService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800117
Jeff Browna4d82042012-10-02 19:11:19 -0700118 private static final boolean DEBUG = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800119
Jeff Browna4d82042012-10-02 19:11:19 -0700120 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800121
Yifan Hong89d55c12017-10-11 11:29:01 -0700122 private static final long HEALTH_HAL_WAIT_MS = 1000;
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800123 private static final long BATTERY_LEVEL_CHANGE_THROTTLE_MS = 60_000;
124 private static final int MAX_BATTERY_LEVELS_QUEUE_SIZE = 100;
Yifan Hong89d55c12017-10-11 11:29:01 -0700125
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800126 // Used locally for determining when to make a last ditch effort to log
127 // discharge stats before the device dies.
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700128 private int mCriticalBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
Jeff Sharkeyec43a6b2013-04-30 13:33:18 -0700130 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800131
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800132 private static final String DUMPSYS_DATA_PATH = "/data/system/";
133
134 // This should probably be exposed in the API, though it's not critical
Bookatz1a1b0462018-01-12 11:47:03 -0800135 private static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800136
137 private final Context mContext;
138 private final IBatteryStats mBatteryStats;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700139 BinderService mBinderService;
Jeff Brown605ea692012-10-05 16:33:10 -0700140 private final Handler mHandler;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800141
Jeff Browna4d82042012-10-02 19:11:19 -0700142 private final Object mLock = new Object();
143
Yifan Hong932190b2017-10-11 11:00:51 -0700144 private HealthInfo mHealthInfo;
145 private final HealthInfo mLastHealthInfo = new HealthInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 private boolean mBatteryLevelCritical;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800147 private int mLastBatteryStatus;
148 private int mLastBatteryHealth;
149 private boolean mLastBatteryPresent;
150 private int mLastBatteryLevel;
151 private int mLastBatteryVoltage;
152 private int mLastBatteryTemperature;
153 private boolean mLastBatteryLevelCritical;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700154 private int mLastMaxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700155 private int mLastMaxChargingVoltage;
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700156 private int mLastChargeCounter;
Jeff Browna4d82042012-10-02 19:11:19 -0700157
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800158 private int mSequence = 1;
159
Jeff Browna4d82042012-10-02 19:11:19 -0700160 private int mInvalidCharger;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700161 private int mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400162
163 private int mLowBatteryWarningLevel;
164 private int mLowBatteryCloseWarningLevel;
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700165 private int mShutdownBatteryTemperature;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 private int mPlugType;
168 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800169
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700170 private boolean mBatteryLevelLow;
171
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800172 private long mDischargeStartTime;
173 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800174
Beverlyc4eb9342018-05-10 15:46:03 -0400175 private long mChargeStartTime;
176 private int mChargeStartLevel;
177
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700178 private boolean mUpdatesStopped;
179
Joe Onoratode1b3592010-10-25 20:36:47 -0700180 private Led mLed;
181
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700182 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800183
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700184 private ActivityManagerInternal mActivityManagerInternal;
185
Yifan Hong89d55c12017-10-11 11:29:01 -0700186 private HealthServiceWrapper mHealthServiceWrapper;
187 private HealthHalCallback mHealthHalCallback;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -0700188 private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800189 private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
190 private long mLastBatteryLevelChangedSentMs;
Yifan Hong89d55c12017-10-11 11:29:01 -0700191
Beverlyc4eb9342018-05-10 15:46:03 -0400192 private MetricsLogger mMetricsLogger;
193
Jeff Brown21392762014-06-13 19:00:36 -0700194 public BatteryService(Context context) {
195 super(context);
196
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197 mContext = context;
Jeff Brown605ea692012-10-05 16:33:10 -0700198 mHandler = new Handler(true /*async*/);
Jeff Brown21392762014-06-13 19:00:36 -0700199 mLed = new Led(context, getLocalService(LightsManager.class));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 mBatteryStats = BatteryStatsService.getService();
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700201 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700203 mCriticalBatteryLevel = mContext.getResources().getInteger(
204 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400205 mLowBatteryWarningLevel = mContext.getResources().getInteger(
206 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Dianne Hackborn14272302014-06-10 23:13:02 -0700207 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
208 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700209 mShutdownBatteryTemperature = mContext.getResources().getInteger(
210 com.android.internal.R.integer.config_shutdownBatteryTemperature);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400211
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800212 mBatteryLevelsEventQueue = new ArrayDeque<>();
Beverlyc4eb9342018-05-10 15:46:03 -0400213 mMetricsLogger = new MetricsLogger();
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800214
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400215 // watch for invalid charger messages if the invalid_charger switch exists
216 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700217 UEventObserver invalidChargerObserver = new UEventObserver() {
218 @Override
219 public void onUEvent(UEvent event) {
220 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
221 synchronized (mLock) {
222 if (mInvalidCharger != invalidCharger) {
223 mInvalidCharger = invalidCharger;
224 }
225 }
226 }
227 };
228 invalidChargerObserver.startObserving(
Jeff Browna4d82042012-10-02 19:11:19 -0700229 "DEVPATH=/devices/virtual/switch/invalid_charger");
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400230 }
Jeff Brown21392762014-06-13 19:00:36 -0700231 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800232
Jeff Brown21392762014-06-13 19:00:36 -0700233 @Override
234 public void onStart() {
Yifan Hong89d55c12017-10-11 11:29:01 -0700235 registerHealthCallback();
Jeff Brown21392762014-06-13 19:00:36 -0700236
Dianne Hackborn2e441072015-10-28 18:00:57 -0700237 mBinderService = new BinderService();
238 publishBinderService("battery", mBinderService);
Yifan Hong1fd86f4c2017-10-09 16:50:33 -0700239 mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
240 publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);
Jeff Brown21392762014-06-13 19:00:36 -0700241 publishLocalService(BatteryManagerInternal.class, new LocalService());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800242 }
243
Jeff Brown21392762014-06-13 19:00:36 -0700244 @Override
245 public void onBootPhase(int phase) {
246 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
247 // check our power situation now that it is safe to display the shutdown dialog.
248 synchronized (mLock) {
249 ContentObserver obs = new ContentObserver(mHandler) {
250 @Override
251 public void onChange(boolean selfChange) {
252 synchronized (mLock) {
253 updateBatteryWarningLevelLocked();
254 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700255 }
Jeff Brown21392762014-06-13 19:00:36 -0700256 };
257 final ContentResolver resolver = mContext.getContentResolver();
258 resolver.registerContentObserver(Settings.Global.getUriFor(
259 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
260 false, obs, UserHandle.USER_ALL);
261 updateBatteryWarningLevelLocked();
262 }
Jeff Browna4d82042012-10-02 19:11:19 -0700263 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800264 }
265
Yifan Hong89d55c12017-10-11 11:29:01 -0700266 private void registerHealthCallback() {
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700267 traceBegin("HealthInitWrapper");
Yifan Hong89d55c12017-10-11 11:29:01 -0700268 mHealthServiceWrapper = new HealthServiceWrapper();
269 mHealthHalCallback = new HealthHalCallback();
270 // IHealth is lazily retrieved.
271 try {
272 mHealthServiceWrapper.init(mHealthHalCallback,
273 new HealthServiceWrapper.IServiceManagerSupplier() {},
274 new HealthServiceWrapper.IHealthSupplier() {});
Yifan Hong78e8af12017-10-26 15:57:19 -0700275 } catch (RemoteException ex) {
276 Slog.e(TAG, "health: cannot register callback. (RemoteException)");
277 throw ex.rethrowFromSystemServer();
278 } catch (NoSuchElementException ex) {
279 Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");
280 throw ex;
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700281 } finally {
282 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -0700283 }
284
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700285 traceBegin("HealthInitWaitUpdate");
Yifan Hong89d55c12017-10-11 11:29:01 -0700286 // init register for new service notifications, and IServiceManager should return the
287 // existing service in a near future. Wait for this.update() to instantiate
288 // the initial mHealthInfo.
Yifan Hong78e8af12017-10-26 15:57:19 -0700289 long beforeWait = SystemClock.uptimeMillis();
Yifan Hong89d55c12017-10-11 11:29:01 -0700290 synchronized (mLock) {
Yifan Hong78e8af12017-10-26 15:57:19 -0700291 while (mHealthInfo == null) {
292 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) +
293 "ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms...");
Yifan Hong89d55c12017-10-11 11:29:01 -0700294 try {
Yifan Hong78e8af12017-10-26 15:57:19 -0700295 mLock.wait(HEALTH_HAL_WAIT_MS);
Yifan Hong89d55c12017-10-11 11:29:01 -0700296 } catch (InterruptedException ex) {
Yifan Hong78e8af12017-10-26 15:57:19 -0700297 Slog.i(TAG, "health: InterruptedException when waiting for update. "
298 + " Continuing...");
Yifan Hong89d55c12017-10-11 11:29:01 -0700299 }
300 }
Yifan Hong89d55c12017-10-11 11:29:01 -0700301 }
302
Yifan Hong78e8af12017-10-26 15:57:19 -0700303 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)
304 + "ms and received the update.");
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700305 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -0700306 }
307
Jeff Brown21392762014-06-13 19:00:36 -0700308 private void updateBatteryWarningLevelLocked() {
Dianne Hackborn14272302014-06-10 23:13:02 -0700309 final ContentResolver resolver = mContext.getContentResolver();
310 int defWarnLevel = mContext.getResources().getInteger(
311 com.android.internal.R.integer.config_lowBatteryWarningLevel);
312 mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
313 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
314 if (mLowBatteryWarningLevel == 0) {
315 mLowBatteryWarningLevel = defWarnLevel;
316 }
317 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
318 mLowBatteryWarningLevel = mCriticalBatteryLevel;
319 }
320 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
321 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
322 processValuesLocked(true);
323 }
324
Jeff Browna4d82042012-10-02 19:11:19 -0700325 private boolean isPoweredLocked(int plugTypeSet) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 // assume we are powered if battery state is unknown so
327 // the "stay on while plugged in" option will work.
Yifan Honge41e9392017-11-06 12:56:59 -0800328 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 return true;
330 }
Yifan Honge41e9392017-11-06 12:56:59 -0800331 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.chargerAcOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700332 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800333 }
Yifan Honge41e9392017-11-06 12:56:59 -0800334 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.chargerUsbOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700335 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800336 }
Yifan Honge41e9392017-11-06 12:56:59 -0800337 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.chargerWirelessOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700338 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 }
Jeff Browna4d82042012-10-02 19:11:19 -0700340 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800341 }
342
Jeff Brown21392762014-06-13 19:00:36 -0700343 private boolean shouldSendBatteryLowLocked() {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700344 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
345 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
346
347 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
348 * - is just un-plugged (previously was plugged) and battery level is
349 * less than or equal to WARNING, or
350 * - is not plugged and battery level falls to WARNING boundary
351 * (becomes <= mLowBatteryWarningLevel).
352 */
353 return !plugged
Yifan Honge41e9392017-11-06 12:56:59 -0800354 && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
355 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700356 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
357 }
358
Jeff Browna4d82042012-10-02 19:11:19 -0700359 private void shutdownIfNoPowerLocked() {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400360 // shut down gracefully if our battery is critically low and we are not powered.
361 // wait until the system has booted before attempting to display the shutdown dialog.
Yifan Honge41e9392017-11-06 12:56:59 -0800362 if (mHealthInfo.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
Jeff Brown605ea692012-10-05 16:33:10 -0700363 mHandler.post(new Runnable() {
364 @Override
365 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700366 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700367 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
368 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
Sudheer Shanka292637f2017-09-25 10:36:23 -0700369 intent.putExtra(Intent.EXTRA_REASON,
370 PowerManager.SHUTDOWN_LOW_BATTERY);
Jeff Brown605ea692012-10-05 16:33:10 -0700371 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
372 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
373 }
374 }
375 });
Mike Lockwood07a500f2009-08-12 09:56:44 -0400376 }
377 }
378
Jeff Browna4d82042012-10-02 19:11:19 -0700379 private void shutdownIfOverTempLocked() {
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700380 // shut down gracefully if temperature is too high (> 68.0C by default)
381 // wait until the system has booted before attempting to display the
382 // shutdown dialog.
Yifan Honge41e9392017-11-06 12:56:59 -0800383 if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {
Jeff Brown605ea692012-10-05 16:33:10 -0700384 mHandler.post(new Runnable() {
385 @Override
386 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700387 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700388 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
389 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
Sudheer Shanka292637f2017-09-25 10:36:23 -0700390 intent.putExtra(Intent.EXTRA_REASON,
391 PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE);
Jeff Brown605ea692012-10-05 16:33:10 -0700392 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
393 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
394 }
395 }
396 });
Eric Olsen6a362a92010-03-26 15:38:41 -0700397 }
398 }
399
Hridya Valsarajua09fa902018-01-17 23:04:46 -0800400 private void update(android.hardware.health.V2_0.HealthInfo info) {
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700401 traceBegin("HealthInfoUpdate");
Kweku Adamse06e97b42018-08-22 17:25:37 -0700402
403 Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryChargeCounter",
404 info.legacy.batteryChargeCounter);
405 Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent",
406 info.legacy.batteryCurrent);
407
Todd Poynor26faecc2013-05-22 18:54:48 -0700408 synchronized (mLock) {
409 if (!mUpdatesStopped) {
Hridya Valsarajua09fa902018-01-17 23:04:46 -0800410 mHealthInfo = info.legacy;
Todd Poynor26faecc2013-05-22 18:54:48 -0700411 // Process the new values.
Dianne Hackborn14272302014-06-10 23:13:02 -0700412 processValuesLocked(false);
Yifan Hong89d55c12017-10-11 11:29:01 -0700413 mLock.notifyAll(); // for any waiters on new info
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800414 } else {
Hridya Valsarajua09fa902018-01-17 23:04:46 -0800415 copy(mLastHealthInfo, info.legacy);
Todd Poynor26faecc2013-05-22 18:54:48 -0700416 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700417 }
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700418 traceEnd();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700419 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420
Yifan Hong932190b2017-10-11 11:00:51 -0700421 private static void copy(HealthInfo dst, HealthInfo src) {
Yifan Honge41e9392017-11-06 12:56:59 -0800422 dst.chargerAcOnline = src.chargerAcOnline;
423 dst.chargerUsbOnline = src.chargerUsbOnline;
424 dst.chargerWirelessOnline = src.chargerWirelessOnline;
425 dst.maxChargingCurrent = src.maxChargingCurrent;
426 dst.maxChargingVoltage = src.maxChargingVoltage;
427 dst.batteryStatus = src.batteryStatus;
428 dst.batteryHealth = src.batteryHealth;
429 dst.batteryPresent = src.batteryPresent;
430 dst.batteryLevel = src.batteryLevel;
431 dst.batteryVoltage = src.batteryVoltage;
432 dst.batteryTemperature = src.batteryTemperature;
433 dst.batteryCurrent = src.batteryCurrent;
434 dst.batteryCycleCount = src.batteryCycleCount;
435 dst.batteryFullCharge = src.batteryFullCharge;
436 dst.batteryChargeCounter = src.batteryChargeCounter;
437 dst.batteryTechnology = src.batteryTechnology;
Yifan Hong932190b2017-10-11 11:00:51 -0700438 }
439
Dianne Hackborn14272302014-06-10 23:13:02 -0700440 private void processValuesLocked(boolean force) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700441 boolean logOutlier = false;
442 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700443
Todd Poynorb41df4422017-12-08 10:44:40 -0800444 mBatteryLevelCritical =
445 mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
446 && mHealthInfo.batteryLevel <= mCriticalBatteryLevel;
Yifan Honge41e9392017-11-06 12:56:59 -0800447 if (mHealthInfo.chargerAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800448 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
Yifan Honge41e9392017-11-06 12:56:59 -0800449 } else if (mHealthInfo.chargerUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
Yifan Honge41e9392017-11-06 12:56:59 -0800451 } else if (mHealthInfo.chargerWirelessOnline) {
Brian Muramatsu37a37f42012-08-14 15:21:02 -0700452 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800453 } else {
454 mPlugType = BATTERY_PLUGGED_NONE;
455 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700456
Jeff Browna4d82042012-10-02 19:11:19 -0700457 if (DEBUG) {
458 Slog.d(TAG, "Processing new values: "
Yifan Hong932190b2017-10-11 11:00:51 -0700459 + "info=" + mHealthInfo
Jeff Browna4d82042012-10-02 19:11:19 -0700460 + ", mBatteryLevelCritical=" + mBatteryLevelCritical
461 + ", mPlugType=" + mPlugType);
462 }
463
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700464 // Let the battery stats keep track of the current level.
465 try {
Yifan Honge41e9392017-11-06 12:56:59 -0800466 mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
467 mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
468 mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
469 mHealthInfo.batteryFullCharge);
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700470 } catch (RemoteException e) {
471 // Should never happen.
472 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700473
Jeff Browna4d82042012-10-02 19:11:19 -0700474 shutdownIfNoPowerLocked();
475 shutdownIfOverTempLocked();
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700476
Yifan Honge41e9392017-11-06 12:56:59 -0800477 if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||
478 mHealthInfo.batteryHealth != mLastBatteryHealth ||
479 mHealthInfo.batteryPresent != mLastBatteryPresent ||
480 mHealthInfo.batteryLevel != mLastBatteryLevel ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800481 mPlugType != mLastPlugType ||
Yifan Honge41e9392017-11-06 12:56:59 -0800482 mHealthInfo.batteryVoltage != mLastBatteryVoltage ||
483 mHealthInfo.batteryTemperature != mLastBatteryTemperature ||
484 mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||
485 mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||
486 mHealthInfo.batteryChargeCounter != mLastChargeCounter ||
Dianne Hackborn14272302014-06-10 23:13:02 -0700487 mInvalidCharger != mLastInvalidCharger)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800488
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 if (mPlugType != mLastPlugType) {
490 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
491 // discharging -> charging
Beverlyc4eb9342018-05-10 15:46:03 -0400492 mChargeStartLevel = mHealthInfo.batteryLevel;
493 mChargeStartTime = SystemClock.elapsedRealtime();
494
495 final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);
496 builder.setType(MetricsEvent.TYPE_ACTION);
497 builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mPlugType);
498 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,
499 mHealthInfo.batteryLevel);
500 mMetricsLogger.write(builder);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800501
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800502 // There's no value in this data unless we've discharged at least once and the
503 // battery level has changed; so don't log until it does.
Yifan Honge41e9392017-11-06 12:56:59 -0800504 if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.batteryLevel) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700505 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
506 logOutlier = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800507 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
Yifan Honge41e9392017-11-06 12:56:59 -0800508 mDischargeStartLevel, mHealthInfo.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 // make sure we see a discharge event before logging again
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800510 mDischargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800511 }
512 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
513 // charging -> discharging or we just powered up
514 mDischargeStartTime = SystemClock.elapsedRealtime();
Yifan Honge41e9392017-11-06 12:56:59 -0800515 mDischargeStartLevel = mHealthInfo.batteryLevel;
Beverlyc4eb9342018-05-10 15:46:03 -0400516
517 long chargeDuration = SystemClock.elapsedRealtime() - mChargeStartTime;
518 if (mChargeStartTime != 0 && chargeDuration != 0) {
519 final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE);
520 builder.setType(MetricsEvent.TYPE_DISMISS);
521 builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastPlugType);
522 builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS,
523 chargeDuration);
524 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START,
525 mChargeStartLevel);
526 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_END,
527 mHealthInfo.batteryLevel);
528 mMetricsLogger.write(builder);
529 }
530 mChargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 }
532 }
Yifan Honge41e9392017-11-06 12:56:59 -0800533 if (mHealthInfo.batteryStatus != mLastBatteryStatus ||
534 mHealthInfo.batteryHealth != mLastBatteryHealth ||
535 mHealthInfo.batteryPresent != mLastBatteryPresent ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800536 mPlugType != mLastPlugType) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800537 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
Yifan Honge41e9392017-11-06 12:56:59 -0800538 mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0,
539 mPlugType, mHealthInfo.batteryTechnology);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800540 }
Yifan Honge41e9392017-11-06 12:56:59 -0800541 if (mHealthInfo.batteryLevel != mLastBatteryLevel) {
Dianne Hackborncf1171642013-07-12 17:26:02 -0700542 // Don't do this just from voltage or temperature changes, that is
543 // too noisy.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800544 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
Yifan Honge41e9392017-11-06 12:56:59 -0800545 mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800546 }
547 if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
548 mPlugType == BATTERY_PLUGGED_NONE) {
549 // We want to make sure we log discharge cycle outliers
550 // if the battery is about to die.
The Android Open Source Project10592532009-03-18 17:39:46 -0700551 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
552 logOutlier = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800553 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800554
Dianne Hackborn14272302014-06-10 23:13:02 -0700555 if (!mBatteryLevelLow) {
556 // Should we now switch in to low battery mode?
557 if (mPlugType == BATTERY_PLUGGED_NONE
Todd Poynorb41df4422017-12-08 10:44:40 -0800558 && mHealthInfo.batteryStatus !=
559 BatteryManager.BATTERY_STATUS_UNKNOWN
Yifan Honge41e9392017-11-06 12:56:59 -0800560 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700561 mBatteryLevelLow = true;
562 }
563 } else {
564 // Should we now switch out of low battery mode?
565 if (mPlugType != BATTERY_PLUGGED_NONE) {
566 mBatteryLevelLow = false;
Yifan Honge41e9392017-11-06 12:56:59 -0800567 } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700568 mBatteryLevelLow = false;
Yifan Honge41e9392017-11-06 12:56:59 -0800569 } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700570 // If being forced, the previous state doesn't matter, we will just
571 // absolutely check to see if we are now above the warning level.
572 mBatteryLevelLow = false;
573 }
574 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800575
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800576 mSequence++;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800577
Christopher Tate06ba5542009-04-09 16:03:56 -0700578 // Separate broadcast is sent for power connected / not connected
579 // since the standard intent will not wake any applications and some
580 // applications may want to have smart behavior based on this.
581 if (mPlugType != 0 && mLastPlugType == 0) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800582 final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
583 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
584 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700585 mHandler.post(new Runnable() {
586 @Override
587 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700588 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
589 }
590 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700591 }
592 else if (mPlugType == 0 && mLastPlugType != 0) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800593 final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
594 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
595 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700596 mHandler.post(new Runnable() {
597 @Override
598 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700599 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
600 }
601 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700602 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200603
Dianne Hackborn14272302014-06-10 23:13:02 -0700604 if (shouldSendBatteryLowLocked()) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700605 mSentLowBatteryBroadcast = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800606 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
607 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
608 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700609 mHandler.post(new Runnable() {
610 @Override
611 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700612 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
613 }
614 });
Dianne Hackborn532ea262017-03-17 17:50:55 -0700615 } else if (mSentLowBatteryBroadcast &&
Yifan Honge41e9392017-11-06 12:56:59 -0800616 mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700617 mSentLowBatteryBroadcast = false;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800618 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
619 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
620 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700621 mHandler.post(new Runnable() {
622 @Override
623 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700624 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
625 }
626 });
Mihai Predaa82842f2009-04-29 15:05:56 +0200627 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800628
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800629 // We are doing this after sending the above broadcasts, so anything processing
630 // them will get the new sequence number at that point. (See for example how testing
631 // of JobScheduler's BatteryController works.)
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800632 sendBatteryChangedIntentLocked();
Suprabh Shukla8046ba62018-08-08 18:16:22 -0700633 if (mLastBatteryLevel != mHealthInfo.batteryLevel || mLastPlugType != mPlugType) {
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800634 sendBatteryLevelChangedIntentLocked();
635 }
636
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800637
Joe Onoratode1b3592010-10-25 20:36:47 -0700638 // Update the battery LED
639 mLed.updateLightsLocked();
640
The Android Open Source Project10592532009-03-18 17:39:46 -0700641 // This needs to be done after sendIntent() so that we get the lastest battery stats.
642 if (logOutlier && dischargeDuration != 0) {
Jeff Browna4d82042012-10-02 19:11:19 -0700643 logOutlierLocked(dischargeDuration);
The Android Open Source Project10592532009-03-18 17:39:46 -0700644 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800645
Yifan Honge41e9392017-11-06 12:56:59 -0800646 mLastBatteryStatus = mHealthInfo.batteryStatus;
647 mLastBatteryHealth = mHealthInfo.batteryHealth;
648 mLastBatteryPresent = mHealthInfo.batteryPresent;
649 mLastBatteryLevel = mHealthInfo.batteryLevel;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700650 mLastPlugType = mPlugType;
Yifan Honge41e9392017-11-06 12:56:59 -0800651 mLastBatteryVoltage = mHealthInfo.batteryVoltage;
652 mLastBatteryTemperature = mHealthInfo.batteryTemperature;
653 mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;
654 mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;
655 mLastChargeCounter = mHealthInfo.batteryChargeCounter;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700656 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400657 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800658 }
659 }
660
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800661 private void sendBatteryChangedIntentLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 // Pack up the values and broadcast them to everyone
Jeff Brown605ea692012-10-05 16:33:10 -0700663 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800664 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
665 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800666
Yifan Honge41e9392017-11-06 12:56:59 -0800667 int icon = getIconLocked(mHealthInfo.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800668
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800669 intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Yifan Honge41e9392017-11-06 12:56:59 -0800670 intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
671 intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
672 intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
673 intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
Dianne Hackborn74ed6ec2017-11-21 16:33:44 -0800674 intent.putExtra(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
Dianne Hackbornedd93162009-09-19 14:03:05 -0700675 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
676 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
677 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
Yifan Honge41e9392017-11-06 12:56:59 -0800678 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
679 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
680 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400681 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
Yifan Honge41e9392017-11-06 12:56:59 -0800682 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
683 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
684 intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
Jeff Browna4d82042012-10-02 19:11:19 -0700685 if (DEBUG) {
Yifan Hong932190b2017-10-11 11:00:51 -0700686 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
687 + ", info:" + mHealthInfo.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800688 }
689
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800690 mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL));
691 }
692
693 private void sendBatteryLevelChangedIntentLocked() {
694 Bundle event = new Bundle();
695 long now = SystemClock.elapsedRealtime();
696 event.putInt(BatteryManager.EXTRA_SEQUENCE, mSequence);
697 event.putInt(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
698 event.putInt(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
699 event.putBoolean(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
700 event.putInt(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
701 event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
702 event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
703 event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
704 event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
705 event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
706
707 boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
708 mBatteryLevelsEventQueue.add(event);
709 // Make sure queue is bounded and doesn't exceed intent payload limits
710 if (mBatteryLevelsEventQueue.size() > MAX_BATTERY_LEVELS_QUEUE_SIZE) {
711 mBatteryLevelsEventQueue.removeFirst();
712 }
713
714 if (queueWasEmpty) {
715 // send now if last event was before throttle interval, otherwise delay
716 long delay = now - mLastBatteryLevelChangedSentMs > BATTERY_LEVEL_CHANGE_THROTTLE_MS
717 ? 0 : mLastBatteryLevelChangedSentMs + BATTERY_LEVEL_CHANGE_THROTTLE_MS - now;
718 mHandler.postDelayed(this::sendEnqueuedBatteryLevelChangedEvents, delay);
719 }
720 }
721
722 private void sendEnqueuedBatteryLevelChangedEvents() {
723 ArrayList<Bundle> events;
724 synchronized (mLock) {
725 events = new ArrayList<>(mBatteryLevelsEventQueue);
726 mBatteryLevelsEventQueue.clear();
727 }
728 final Intent intent = new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED);
729 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
730 intent.putParcelableArrayListExtra(BatteryManager.EXTRA_EVENTS, events);
731
732 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
733 android.Manifest.permission.BATTERY_STATS);
734 mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800735 }
736
Jeff Browna4d82042012-10-02 19:11:19 -0700737 private void logBatteryStatsLocked() {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700738 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800739 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740
Dan Egnor18e93962010-02-10 19:27:58 -0800741 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
742 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
743
744 File dumpFile = null;
745 FileOutputStream dumpStream = null;
746 try {
747 // dump the service to a file
Dianne Hackborn8c841092013-06-24 13:46:13 -0700748 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
Dan Egnor18e93962010-02-10 19:27:58 -0800749 dumpStream = new FileOutputStream(dumpFile);
750 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -0700751 FileUtils.sync(dumpStream);
Dan Egnor18e93962010-02-10 19:27:58 -0800752
753 // add dump file to drop box
754 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
755 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800756 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800757 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800758 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800759 } finally {
760 // make sure we clean up
761 if (dumpStream != null) {
762 try {
763 dumpStream.close();
764 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800765 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800766 }
Dan Egnor18e93962010-02-10 19:27:58 -0800767 }
768 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800769 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800770 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800771 }
772 }
773 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800774
Jeff Browna4d82042012-10-02 19:11:19 -0700775 private void logOutlierLocked(long duration) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800776 ContentResolver cr = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -0700777 String dischargeThresholdString = Settings.Global.getString(cr,
778 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
779 String durationThresholdString = Settings.Global.getString(cr,
780 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800781
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 if (dischargeThresholdString != null && durationThresholdString != null) {
783 try {
784 long durationThreshold = Long.parseLong(durationThresholdString);
785 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800786 if (duration <= durationThreshold &&
Yifan Honge41e9392017-11-06 12:56:59 -0800787 mDischargeStartLevel - mHealthInfo.batteryLevel >= dischargeThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800788 // If the discharge cycle is bad enough we want to know about it.
Jeff Browna4d82042012-10-02 19:11:19 -0700789 logBatteryStatsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800790 }
Jeff Browna4d82042012-10-02 19:11:19 -0700791 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 " discharge threshold: " + dischargeThreshold);
Jeff Browna4d82042012-10-02 19:11:19 -0700793 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
Yifan Honge41e9392017-11-06 12:56:59 -0800794 (mDischargeStartLevel - mHealthInfo.batteryLevel));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800795 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800796 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800797 durationThresholdString + " or " + dischargeThresholdString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800798 }
799 }
800 }
801
Jeff Browna4d82042012-10-02 19:11:19 -0700802 private int getIconLocked(int level) {
Yifan Honge41e9392017-11-06 12:56:59 -0800803 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800804 return com.android.internal.R.drawable.stat_sys_battery_charge;
Yifan Honge41e9392017-11-06 12:56:59 -0800805 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800806 return com.android.internal.R.drawable.stat_sys_battery;
Yifan Honge41e9392017-11-06 12:56:59 -0800807 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
808 || mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
Jeff Browna4d82042012-10-02 19:11:19 -0700809 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
Yifan Honge41e9392017-11-06 12:56:59 -0800810 && mHealthInfo.batteryLevel >= 100) {
Joe Onorato794be402010-11-21 19:22:25 -0800811 return com.android.internal.R.drawable.stat_sys_battery_charge;
812 } else {
813 return com.android.internal.R.drawable.stat_sys_battery;
814 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800815 } else {
816 return com.android.internal.R.drawable.stat_sys_battery_unknown;
817 }
818 }
819
Dianne Hackborn2e441072015-10-28 18:00:57 -0700820 class Shell extends ShellCommand {
821 @Override
822 public int onCommand(String cmd) {
823 return onShellCommand(this, cmd);
824 }
825
826 @Override
827 public void onHelp() {
828 PrintWriter pw = getOutPrintWriter();
829 dumpHelp(pw);
830 }
831 }
832
833 static void dumpHelp(PrintWriter pw) {
834 pw.println("Battery service (battery) commands:");
835 pw.println(" help");
836 pw.println(" Print this help text.");
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700837 pw.println(" set [-f] [ac|usb|wireless|status|level|temp|present|invalid] <value>");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700838 pw.println(" Force a battery property value, freezing battery state.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800839 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
840 pw.println(" unplug [-f]");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700841 pw.println(" Force battery unplugged, freezing battery state.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800842 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
843 pw.println(" reset [-f]");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700844 pw.println(" Unfreeze battery state, returning to current hardware values.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800845 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
846 }
847
848 static final int OPTION_FORCE_UPDATE = 1<<0;
849
850 int parseOptions(Shell shell) {
851 String opt;
852 int opts = 0;
853 while ((opt = shell.getNextOption()) != null) {
854 if ("-f".equals(opt)) {
855 opts |= OPTION_FORCE_UPDATE;
856 }
857 }
858 return opts;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700859 }
860
861 int onShellCommand(Shell shell, String cmd) {
862 if (cmd == null) {
863 return shell.handleDefaultCommands(cmd);
864 }
865 PrintWriter pw = shell.getOutPrintWriter();
866 switch (cmd) {
867 case "unplug": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800868 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700869 getContext().enforceCallingOrSelfPermission(
870 android.Manifest.permission.DEVICE_POWER, null);
871 if (!mUpdatesStopped) {
Yifan Hong932190b2017-10-11 11:00:51 -0700872 copy(mLastHealthInfo, mHealthInfo);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700873 }
Yifan Honge41e9392017-11-06 12:56:59 -0800874 mHealthInfo.chargerAcOnline = false;
875 mHealthInfo.chargerUsbOnline = false;
876 mHealthInfo.chargerWirelessOnline = false;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700877 long ident = Binder.clearCallingIdentity();
878 try {
879 mUpdatesStopped = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800880 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700881 } finally {
882 Binder.restoreCallingIdentity(ident);
883 }
884 } break;
885 case "set": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800886 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700887 getContext().enforceCallingOrSelfPermission(
888 android.Manifest.permission.DEVICE_POWER, null);
889 final String key = shell.getNextArg();
890 if (key == null) {
891 pw.println("No property specified");
892 return -1;
893
894 }
895 final String value = shell.getNextArg();
896 if (value == null) {
897 pw.println("No value specified");
898 return -1;
899
900 }
901 try {
902 if (!mUpdatesStopped) {
Yifan Hong932190b2017-10-11 11:00:51 -0700903 copy(mLastHealthInfo, mHealthInfo);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700904 }
905 boolean update = true;
906 switch (key) {
Christopher Tate630d98b2017-03-07 14:12:26 -0800907 case "present":
Yifan Honge41e9392017-11-06 12:56:59 -0800908 mHealthInfo.batteryPresent = Integer.parseInt(value) != 0;
Christopher Tate630d98b2017-03-07 14:12:26 -0800909 break;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700910 case "ac":
Yifan Honge41e9392017-11-06 12:56:59 -0800911 mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700912 break;
913 case "usb":
Yifan Honge41e9392017-11-06 12:56:59 -0800914 mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700915 break;
916 case "wireless":
Yifan Honge41e9392017-11-06 12:56:59 -0800917 mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700918 break;
919 case "status":
Yifan Honge41e9392017-11-06 12:56:59 -0800920 mHealthInfo.batteryStatus = Integer.parseInt(value);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700921 break;
922 case "level":
Yifan Honge41e9392017-11-06 12:56:59 -0800923 mHealthInfo.batteryLevel = Integer.parseInt(value);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700924 break;
Makoto Onuki076218b2018-01-26 10:26:36 -0800925 case "counter":
926 mHealthInfo.batteryChargeCounter = Integer.parseInt(value);
927 break;
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700928 case "temp":
Yifan Honge41e9392017-11-06 12:56:59 -0800929 mHealthInfo.batteryTemperature = Integer.parseInt(value);
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700930 break;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700931 case "invalid":
932 mInvalidCharger = Integer.parseInt(value);
933 break;
934 default:
935 pw.println("Unknown set option: " + key);
936 update = false;
937 break;
938 }
939 if (update) {
940 long ident = Binder.clearCallingIdentity();
941 try {
942 mUpdatesStopped = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800943 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700944 } finally {
945 Binder.restoreCallingIdentity(ident);
946 }
947 }
948 } catch (NumberFormatException ex) {
949 pw.println("Bad value: " + value);
950 return -1;
951 }
952 } break;
953 case "reset": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800954 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700955 getContext().enforceCallingOrSelfPermission(
956 android.Manifest.permission.DEVICE_POWER, null);
957 long ident = Binder.clearCallingIdentity();
958 try {
959 if (mUpdatesStopped) {
960 mUpdatesStopped = false;
Yifan Hong932190b2017-10-11 11:00:51 -0700961 copy(mHealthInfo, mLastHealthInfo);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800962 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700963 }
964 } finally {
965 Binder.restoreCallingIdentity(ident);
966 }
967 } break;
968 default:
969 return shell.handleDefaultCommands(cmd);
970 }
971 return 0;
972 }
973
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800974 private void processValuesFromShellLocked(PrintWriter pw, int opts) {
975 processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
976 if ((opts & OPTION_FORCE_UPDATE) != 0) {
977 pw.println(mSequence);
978 }
979 }
980
Dianne Hackborn2e441072015-10-28 18:00:57 -0700981 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna4d82042012-10-02 19:11:19 -0700982 synchronized (mLock) {
983 if (args == null || args.length == 0 || "-a".equals(args[0])) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700984 pw.println("Current Battery Service state:");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700985 if (mUpdatesStopped) {
986 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
987 }
Yifan Honge41e9392017-11-06 12:56:59 -0800988 pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
989 pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
990 pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
991 pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
992 pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
993 pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
994 pw.println(" status: " + mHealthInfo.batteryStatus);
995 pw.println(" health: " + mHealthInfo.batteryHealth);
996 pw.println(" present: " + mHealthInfo.batteryPresent);
997 pw.println(" level: " + mHealthInfo.batteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700998 pw.println(" scale: " + BATTERY_SCALE);
Yifan Honge41e9392017-11-06 12:56:59 -0800999 pw.println(" voltage: " + mHealthInfo.batteryVoltage);
1000 pw.println(" temperature: " + mHealthInfo.batteryTemperature);
1001 pw.println(" technology: " + mHealthInfo.batteryTechnology);
Dianne Hackbornc428aae2012-10-03 16:38:22 -07001002 } else {
Dianne Hackborn2e441072015-10-28 18:00:57 -07001003 Shell shell = new Shell();
Dianne Hackborn354736e2016-08-22 17:00:05 -07001004 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -07001005 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001006 }
1007 }
Joe Onoratode1b3592010-10-25 20:36:47 -07001008
Netta Pe2a3cd82017-01-26 18:03:51 -08001009 private void dumpProto(FileDescriptor fd) {
1010 final ProtoOutputStream proto = new ProtoOutputStream(fd);
1011
1012 synchronized (mLock) {
1013 proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
Bookatz1a1b0462018-01-12 11:47:03 -08001014 int batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_NONE;
Yifan Honge41e9392017-11-06 12:56:59 -08001015 if (mHealthInfo.chargerAcOnline) {
Bookatz1a1b0462018-01-12 11:47:03 -08001016 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_AC;
Yifan Honge41e9392017-11-06 12:56:59 -08001017 } else if (mHealthInfo.chargerUsbOnline) {
Bookatz1a1b0462018-01-12 11:47:03 -08001018 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_USB;
Yifan Honge41e9392017-11-06 12:56:59 -08001019 } else if (mHealthInfo.chargerWirelessOnline) {
Bookatz1a1b0462018-01-12 11:47:03 -08001020 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS;
Netta Pe2a3cd82017-01-26 18:03:51 -08001021 }
1022 proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
Yifan Honge41e9392017-11-06 12:56:59 -08001023 proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
1024 proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
1025 proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
1026 proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus);
1027 proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth);
1028 proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent);
1029 proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel);
Netta Pe2a3cd82017-01-26 18:03:51 -08001030 proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
Yifan Honge41e9392017-11-06 12:56:59 -08001031 proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage);
1032 proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature);
1033 proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology);
Netta Pe2a3cd82017-01-26 18:03:51 -08001034 }
1035 proto.flush();
1036 }
1037
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001038 private static void traceBegin(String name) {
1039 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
1040 }
1041
1042 private static void traceEnd() {
1043 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
1044 }
1045
Jeff Browna4d82042012-10-02 19:11:19 -07001046 private final class Led {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001047 private final Light mBatteryLight;
Joe Onoratode1b3592010-10-25 20:36:47 -07001048
Jeff Browna4d82042012-10-02 19:11:19 -07001049 private final int mBatteryLowARGB;
1050 private final int mBatteryMediumARGB;
1051 private final int mBatteryFullARGB;
1052 private final int mBatteryLedOn;
1053 private final int mBatteryLedOff;
1054
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001055 public Led(Context context, LightsManager lights) {
1056 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
Joe Onoratode1b3592010-10-25 20:36:47 -07001057
Jeff Browna4d82042012-10-02 19:11:19 -07001058 mBatteryLowARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001059 com.android.internal.R.integer.config_notificationsBatteryLowARGB);
Jeff Browna4d82042012-10-02 19:11:19 -07001060 mBatteryMediumARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001061 com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
Jeff Browna4d82042012-10-02 19:11:19 -07001062 mBatteryFullARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001063 com.android.internal.R.integer.config_notificationsBatteryFullARGB);
Jeff Browna4d82042012-10-02 19:11:19 -07001064 mBatteryLedOn = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001065 com.android.internal.R.integer.config_notificationsBatteryLedOn);
Jeff Browna4d82042012-10-02 19:11:19 -07001066 mBatteryLedOff = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001067 com.android.internal.R.integer.config_notificationsBatteryLedOff);
1068 }
1069
1070 /**
1071 * Synchronize on BatteryService.
1072 */
Jeff Browna4d82042012-10-02 19:11:19 -07001073 public void updateLightsLocked() {
Yifan Honge41e9392017-11-06 12:56:59 -08001074 final int level = mHealthInfo.batteryLevel;
1075 final int status = mHealthInfo.batteryStatus;
Joe Onoratode1b3592010-10-25 20:36:47 -07001076 if (level < mLowBatteryWarningLevel) {
1077 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
1078 // Solid red when battery is charging
1079 mBatteryLight.setColor(mBatteryLowARGB);
1080 } else {
1081 // Flash red when battery is low and not charging
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001082 mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
Joe Onoratode1b3592010-10-25 20:36:47 -07001083 mBatteryLedOn, mBatteryLedOff);
1084 }
1085 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
1086 || status == BatteryManager.BATTERY_STATUS_FULL) {
1087 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
1088 // Solid green when full or charging and nearly full
1089 mBatteryLight.setColor(mBatteryFullARGB);
1090 } else {
1091 // Solid orange when charging and halfway full
1092 mBatteryLight.setColor(mBatteryMediumARGB);
1093 }
1094 } else {
1095 // No lights if not charging and not low
1096 mBatteryLight.turnOff();
1097 }
1098 }
1099 }
Todd Poynor26faecc2013-05-22 18:54:48 -07001100
Yifan Hong89d55c12017-10-11 11:29:01 -07001101 private final class HealthHalCallback extends IHealthInfoCallback.Stub
1102 implements HealthServiceWrapper.Callback {
Hridya Valsarajua09fa902018-01-17 23:04:46 -08001103 @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
Yifan Hong89d55c12017-10-11 11:29:01 -07001104 BatteryService.this.update(props);
1105 }
1106 // on new service registered
1107 @Override public void onRegistration(IHealth oldService, IHealth newService,
1108 String instance) {
1109 if (newService == null) return;
1110
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001111 traceBegin("HealthUnregisterCallback");
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001112 try {
Yifan Hong89d55c12017-10-11 11:29:01 -07001113 if (oldService != null) {
1114 int r = oldService.unregisterCallback(this);
1115 if (r != Result.SUCCESS) {
1116 Slog.w(TAG, "health: cannot unregister previous callback: " +
1117 Result.toString(r));
1118 }
1119 }
1120 } catch (RemoteException ex) {
1121 Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
1122 + ex.getMessage());
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001123 } finally {
1124 traceEnd();
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001125 }
Yifan Hong89d55c12017-10-11 11:29:01 -07001126
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001127 traceBegin("HealthRegisterCallback");
Yifan Hong89d55c12017-10-11 11:29:01 -07001128 try {
1129 int r = newService.registerCallback(this);
1130 if (r != Result.SUCCESS) {
1131 Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
1132 return;
1133 }
1134 // registerCallback does NOT guarantee that update is called
1135 // immediately, so request a manual update here.
1136 newService.update();
1137 } catch (RemoteException ex) {
1138 Slog.e(TAG, "health: cannot register callback (transaction error): "
1139 + ex.getMessage());
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001140 } finally {
1141 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -07001142 }
1143 }
Todd Poynor26faecc2013-05-22 18:54:48 -07001144 }
Jeff Brown21392762014-06-13 19:00:36 -07001145
1146 private final class BinderService extends Binder {
Dianne Hackborn2e441072015-10-28 18:00:57 -07001147 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001148 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown21392762014-06-13 19:00:36 -07001149
Netta Pe2a3cd82017-01-26 18:03:51 -08001150 if (args.length > 0 && "--proto".equals(args[0])) {
1151 dumpProto(fd);
1152 } else {
1153 dumpInternal(fd, pw, args);
1154 }
Dianne Hackborn2e441072015-10-28 18:00:57 -07001155 }
1156
1157 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001158 FileDescriptor err, String[] args, ShellCallback callback,
1159 ResultReceiver resultReceiver) {
1160 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Jeff Brown21392762014-06-13 19:00:36 -07001161 }
1162 }
1163
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001164 // Reduced IBatteryPropertiesRegistrar that only implements getProperty for usage
1165 // in BatteryManager.
1166 private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {
Yifan Hong58faaa02018-05-04 13:48:31 -07001167 @Override
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001168 public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001169 traceBegin("HealthGetProperty");
1170 try {
1171 IHealth service = mHealthServiceWrapper.getLastService();
1172 if (service == null) throw new RemoteException("no health service");
1173 final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
1174 switch(id) {
1175 case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
1176 service.getChargeCounter((int result, int value) -> {
1177 outResult.value = result;
1178 if (result == Result.SUCCESS) prop.setLong(value);
1179 });
1180 break;
1181 case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
1182 service.getCurrentNow((int result, int value) -> {
1183 outResult.value = result;
1184 if (result == Result.SUCCESS) prop.setLong(value);
1185 });
1186 break;
1187 case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
1188 service.getCurrentAverage((int result, int value) -> {
1189 outResult.value = result;
1190 if (result == Result.SUCCESS) prop.setLong(value);
1191 });
1192 break;
1193 case BatteryManager.BATTERY_PROPERTY_CAPACITY:
1194 service.getCapacity((int result, int value) -> {
1195 outResult.value = result;
1196 if (result == Result.SUCCESS) prop.setLong(value);
1197 });
1198 break;
1199 case BatteryManager.BATTERY_PROPERTY_STATUS:
1200 service.getChargeStatus((int result, int value) -> {
1201 outResult.value = result;
1202 if (result == Result.SUCCESS) prop.setLong(value);
1203 });
1204 break;
1205 case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
1206 service.getEnergyCounter((int result, long value) -> {
1207 outResult.value = result;
1208 if (result == Result.SUCCESS) prop.setLong(value);
1209 });
1210 break;
1211 }
1212 return outResult.value;
1213 } finally {
1214 traceEnd();
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001215 }
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001216 }
Yifan Hong58faaa02018-05-04 13:48:31 -07001217 @Override
Yifan Hong7838fcb2017-10-24 16:06:27 -07001218 public void scheduleUpdate() throws RemoteException {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001219 traceBegin("HealthScheduleUpdate");
1220 try {
1221 IHealth service = mHealthServiceWrapper.getLastService();
1222 if (service == null) throw new RemoteException("no health service");
1223 service.update();
1224 } finally {
1225 traceEnd();
1226 }
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001227 }
1228 }
1229
Jeff Brown21392762014-06-13 19:00:36 -07001230 private final class LocalService extends BatteryManagerInternal {
1231 @Override
1232 public boolean isPowered(int plugTypeSet) {
1233 synchronized (mLock) {
1234 return isPoweredLocked(plugTypeSet);
1235 }
1236 }
1237
1238 @Override
1239 public int getPlugType() {
1240 synchronized (mLock) {
1241 return mPlugType;
1242 }
1243 }
1244
1245 @Override
1246 public int getBatteryLevel() {
1247 synchronized (mLock) {
Yifan Honge41e9392017-11-06 12:56:59 -08001248 return mHealthInfo.batteryLevel;
Jeff Brown21392762014-06-13 19:00:36 -07001249 }
1250 }
1251
1252 @Override
Makoto Onuki076218b2018-01-26 10:26:36 -08001253 public int getBatteryChargeCounter() {
1254 synchronized (mLock) {
1255 return mHealthInfo.batteryChargeCounter;
1256 }
1257 }
1258
1259 @Override
1260 public int getBatteryFullCharge() {
1261 synchronized (mLock) {
1262 return mHealthInfo.batteryFullCharge;
1263 }
1264 }
1265
1266 @Override
Jeff Brown21392762014-06-13 19:00:36 -07001267 public boolean getBatteryLevelLow() {
1268 synchronized (mLock) {
1269 return mBatteryLevelLow;
1270 }
1271 }
1272
1273 @Override
1274 public int getInvalidCharger() {
1275 synchronized (mLock) {
1276 return mInvalidCharger;
1277 }
1278 }
1279 }
Yifan Hong98852792017-10-12 11:35:14 -07001280
1281 /**
1282 * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
1283 * necessary.
1284 *
1285 * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
1286 * the internal service is refreshed.
1287 * On death of an existing IHealth service, the internal service is NOT cleared to avoid
1288 * race condition between death notification and new service notification. Hence,
1289 * a caller must check for transaction errors when calling into the service.
1290 *
1291 * @hide Should only be used internally.
1292 */
1293 @VisibleForTesting
1294 static final class HealthServiceWrapper {
1295 private static final String TAG = "HealthServiceWrapper";
1296 public static final String INSTANCE_HEALTHD = "backup";
1297 public static final String INSTANCE_VENDOR = "default";
1298 // All interesting instances, sorted by priority high -> low.
1299 private static final List<String> sAllInstances =
1300 Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
1301
1302 private final IServiceNotification mNotification = new Notification();
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001303 private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceRefresh");
Yifan Hong1fff9842017-10-27 13:53:10 -07001304 // These variables are fixed after init.
Yifan Hong98852792017-10-12 11:35:14 -07001305 private Callback mCallback;
1306 private IHealthSupplier mHealthSupplier;
Yifan Hong1fff9842017-10-27 13:53:10 -07001307 private String mInstanceName;
Yifan Hong98852792017-10-12 11:35:14 -07001308
Yifan Hong89d55c12017-10-11 11:29:01 -07001309 // Last IHealth service received.
Yifan Hong89d55c12017-10-11 11:29:01 -07001310 private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
1311
Yifan Hong98852792017-10-12 11:35:14 -07001312 /**
1313 * init should be called after constructor. For testing purposes, init is not called by
1314 * constructor.
1315 */
1316 HealthServiceWrapper() {
1317 }
1318
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001319 IHealth getLastService() {
1320 return mLastService.get();
1321 }
1322
Yifan Hong98852792017-10-12 11:35:14 -07001323 /**
1324 * Start monitoring registration of new IHealth services. Only instances that are in
1325 * {@code sAllInstances} and in device / framework manifest are used. This function should
1326 * only be called once.
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001327 *
1328 * mCallback.onRegistration() is called synchronously (aka in init thread) before
1329 * this method returns.
1330 *
Yifan Hong98852792017-10-12 11:35:14 -07001331 * @throws RemoteException transaction error when talking to IServiceManager
1332 * @throws NoSuchElementException if one of the following cases:
1333 * - No service manager;
1334 * - none of {@code sAllInstances} are in manifests (i.e. not
1335 * available on this device), or none of these instances are available to current
1336 * process.
1337 * @throws NullPointerException when callback is null or supplier is null
1338 */
1339 void init(Callback callback,
1340 IServiceManagerSupplier managerSupplier,
1341 IHealthSupplier healthSupplier)
1342 throws RemoteException, NoSuchElementException, NullPointerException {
1343 if (callback == null || managerSupplier == null || healthSupplier == null)
1344 throw new NullPointerException();
1345
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001346 IServiceManager manager;
1347
Yifan Hong98852792017-10-12 11:35:14 -07001348 mCallback = callback;
1349 mHealthSupplier = healthSupplier;
1350
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001351 // Initialize mLastService and call callback for the first time (in init thread)
1352 IHealth newService = null;
Yifan Hong98852792017-10-12 11:35:14 -07001353 for (String name : sAllInstances) {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001354 traceBegin("HealthInitGetService_" + name);
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001355 try {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001356 newService = healthSupplier.get(name);
1357 } catch (NoSuchElementException ex) {
1358 /* ignored, handled below */
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001359 } finally {
1360 traceEnd();
Yifan Hong98852792017-10-12 11:35:14 -07001361 }
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001362 if (newService != null) {
1363 mInstanceName = name;
1364 mLastService.set(newService);
1365 break;
1366 }
Yifan Hong98852792017-10-12 11:35:14 -07001367 }
1368
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001369 if (mInstanceName == null || newService == null) {
Yifan Hong1fff9842017-10-27 13:53:10 -07001370 throw new NoSuchElementException(String.format(
1371 "No IHealth service instance among %s is available. Perhaps no permission?",
1372 sAllInstances.toString()));
1373 }
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001374 mCallback.onRegistration(null, newService, mInstanceName);
Yifan Hong1fff9842017-10-27 13:53:10 -07001375
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001376 // Register for future service registrations
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001377 traceBegin("HealthInitRegisterNotification");
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001378 mHandlerThread.start();
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001379 try {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001380 managerSupplier.get().registerForNotifications(
1381 IHealth.kInterfaceName, mInstanceName, mNotification);
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001382 } finally {
1383 traceEnd();
1384 }
Yifan Hong1fff9842017-10-27 13:53:10 -07001385 Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
Yifan Hong98852792017-10-12 11:35:14 -07001386 }
1387
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001388 @VisibleForTesting
1389 HandlerThread getHandlerThread() {
1390 return mHandlerThread;
1391 }
1392
Yifan Hong98852792017-10-12 11:35:14 -07001393 interface Callback {
1394 /**
1395 * This function is invoked asynchronously when a new and related IServiceNotification
1396 * is received.
1397 * @param service the recently retrieved service from IServiceManager.
1398 * Can be a dead service before service notification of a new service is delivered.
1399 * Implementation must handle cases for {@link RemoteException}s when calling
1400 * into service.
1401 * @param instance instance name.
1402 */
Yifan Hong89d55c12017-10-11 11:29:01 -07001403 void onRegistration(IHealth oldService, IHealth newService, String instance);
Yifan Hong98852792017-10-12 11:35:14 -07001404 }
1405
1406 /**
1407 * Supplier of services.
1408 * Must not return null; throw {@link NoSuchElementException} if a service is not available.
1409 */
1410 interface IServiceManagerSupplier {
Yifan Hong89d55c12017-10-11 11:29:01 -07001411 default IServiceManager get() throws NoSuchElementException, RemoteException {
1412 return IServiceManager.getService();
1413 }
Yifan Hong98852792017-10-12 11:35:14 -07001414 }
1415 /**
1416 * Supplier of services.
1417 * Must not return null; throw {@link NoSuchElementException} if a service is not available.
1418 */
1419 interface IHealthSupplier {
Yifan Hong89d55c12017-10-11 11:29:01 -07001420 default IHealth get(String name) throws NoSuchElementException, RemoteException {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001421 return IHealth.getService(name, true /* retry */);
Yifan Hong89d55c12017-10-11 11:29:01 -07001422 }
Yifan Hong98852792017-10-12 11:35:14 -07001423 }
1424
1425 private class Notification extends IServiceNotification.Stub {
1426 @Override
1427 public final void onRegistration(String interfaceName, String instanceName,
1428 boolean preexisting) {
1429 if (!IHealth.kInterfaceName.equals(interfaceName)) return;
Yifan Hong1fff9842017-10-27 13:53:10 -07001430 if (!mInstanceName.equals(instanceName)) return;
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001431
1432 // This runnable only runs on mHandlerThread and ordering is ensured, hence
1433 // no locking is needed inside the runnable.
1434 mHandlerThread.getThreadHandler().post(new Runnable() {
1435 @Override
1436 public void run() {
1437 try {
1438 IHealth newService = mHealthSupplier.get(mInstanceName);
1439 IHealth oldService = mLastService.getAndSet(newService);
1440
1441 // preexisting may be inaccurate (race). Check for equality here.
1442 if (Objects.equals(newService, oldService)) return;
1443
1444 Slog.i(TAG, "health: new instance registered " + mInstanceName);
1445 mCallback.onRegistration(oldService, newService, mInstanceName);
1446 } catch (NoSuchElementException | RemoteException ex) {
1447 Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
1448 + "': " + ex.getMessage() + ". Perhaps no permission?");
1449 }
Yifan Hong89d55c12017-10-11 11:29:01 -07001450 }
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001451 });
Yifan Hong98852792017-10-12 11:35:14 -07001452 }
1453 }
1454 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001455}