blob: d31a605eac6f1174473132f0856a618708bd07ae [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
Fyodor Kupolov70e75432018-03-01 18:29:06 -080023import android.os.Bundle;
Sudheer Shanka292637f2017-09-25 10:36:23 -070024import android.os.PowerManager;
Dianne Hackborn2e441072015-10-28 18:00:57 -070025import android.os.ResultReceiver;
Dianne Hackborn354736e2016-08-22 17:00:05 -070026import android.os.ShellCallback;
Dianne Hackborn2e441072015-10-28 18:00:57 -070027import android.os.ShellCommand;
Yifan Hong98852792017-10-12 11:35:14 -070028import com.android.internal.annotations.VisibleForTesting;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029import com.android.internal.app.IBatteryStats;
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -060030import com.android.internal.util.DumpUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080031import com.android.server.am.BatteryStatsService;
Adam Lesinskief2ea1f2013-12-05 16:48:06 -080032import com.android.server.lights.Light;
33import com.android.server.lights.LightsManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080034
Sudheer Shankadc589ac2016-11-10 15:30:17 -080035import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.ContentResolver;
37import android.content.Context;
38import android.content.Intent;
Yifan Hong98852792017-10-12 11:35:14 -070039import android.hidl.manager.V1_0.IServiceManager;
40import android.hidl.manager.V1_0.IServiceNotification;
Yifan Honge41e9392017-11-06 12:56:59 -080041import android.hardware.health.V1_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;
Jeff Brown21392762014-06-13 19:00:36 -070046import android.os.BatteryManagerInternal;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070047import android.os.BatteryProperty;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080048import android.os.Binder;
Bookatz1a1b0462018-01-12 11:47:03 -080049import android.os.DropBoxManager;
Dianne Hackborn8bdf5932010-10-15 12:54:40 -070050import android.os.FileUtils;
Jeff Brown605ea692012-10-05 16:33:10 -070051import android.os.Handler;
Yifan Hongcf9a8b22017-11-02 18:43:06 -070052import android.os.HandlerThread;
Todd Poynor26faecc2013-05-22 18:54:48 -070053import android.os.IBatteryPropertiesListener;
54import android.os.IBatteryPropertiesRegistrar;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080055import android.os.IBinder;
Bookatz1a1b0462018-01-12 11:47:03 -080056import android.os.OsProtoEnums;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057import android.os.RemoteException;
58import android.os.ServiceManager;
59import android.os.SystemClock;
Yifan Hong8cc18ef2017-10-31 12:27:47 -070060import android.os.Trace;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080061import android.os.UEventObserver;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070062import android.os.UserHandle;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080063import android.provider.Settings;
Netta Pe2a3cd82017-01-26 18:03:51 -080064import android.service.battery.BatteryServiceDumpProto;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.util.EventLog;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -070066import android.util.MutableInt;
Joe Onorato8a9b2202010-02-26 18:56:32 -080067import android.util.Slog;
Netta Pe2a3cd82017-01-26 18:03:51 -080068import android.util.proto.ProtoOutputStream;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080069
70import java.io.File;
71import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import java.io.FileOutputStream;
73import java.io.IOException;
74import java.io.PrintWriter;
75
Fyodor Kupolov70e75432018-03-01 18:29:06 -080076import java.util.ArrayDeque;
77import java.util.ArrayList;
Yifan Hong98852792017-10-12 11:35:14 -070078import java.util.Arrays;
79import java.util.List;
80import java.util.NoSuchElementException;
Yifan Hongcf9a8b22017-11-02 18:43:06 -070081import java.util.Objects;
Yifan Hong89d55c12017-10-11 11:29:01 -070082import java.util.concurrent.atomic.AtomicReference;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080083
84/**
85 * <p>BatteryService monitors the charging status, and charge level of the device
86 * battery. When these values change this service broadcasts the new values
87 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are
88 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED
89 * BATTERY_CHANGED} action.</p>
90 * <p>The new values are stored in the Intent data and can be retrieved by
91 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the
92 * following keys:</p>
93 * <p>&quot;scale&quot; - int, the maximum value for the charge level</p>
94 * <p>&quot;level&quot; - int, charge level, from 0 through &quot;scale&quot; inclusive</p>
95 * <p>&quot;status&quot; - String, the current charging status.<br />
96 * <p>&quot;health&quot; - String, the current battery health.<br />
97 * <p>&quot;present&quot; - boolean, true if the battery is present<br />
98 * <p>&quot;icon-small&quot; - int, suggested small icon to use for this state</p>
99 * <p>&quot;plugged&quot; - int, 0 if the device is not plugged in; 1 if plugged
100 * into an AC power adapter; 2 if plugged in via USB.</p>
101 * <p>&quot;voltage&quot; - int, current battery voltage in millivolts</p>
102 * <p>&quot;temperature&quot; - int, current battery temperature in tenths of
103 * a degree Centigrade</p>
104 * <p>&quot;technology&quot; - String, the type of battery installed, e.g. "Li-ion"</p>
Jeff Brown605ea692012-10-05 16:33:10 -0700105 *
106 * <p>
107 * The battery service may be called by the power manager while holding its locks so
108 * we take care to post all outcalls into the activity manager to a handler.
109 *
110 * FIXME: Ideally the power manager would perform all of its calls into the battery
111 * service asynchronously itself.
112 * </p>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800113 */
Jeff Brown21392762014-06-13 19:00:36 -0700114public final class BatteryService extends SystemService {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115 private static final String TAG = BatteryService.class.getSimpleName();
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800116
Jeff Browna4d82042012-10-02 19:11:19 -0700117 private static final boolean DEBUG = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800118
Jeff Browna4d82042012-10-02 19:11:19 -0700119 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800120
Yifan Hong89d55c12017-10-11 11:29:01 -0700121 private static final long HEALTH_HAL_WAIT_MS = 1000;
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800122 private static final long BATTERY_LEVEL_CHANGE_THROTTLE_MS = 60_000;
123 private static final int MAX_BATTERY_LEVELS_QUEUE_SIZE = 100;
Yifan Hong89d55c12017-10-11 11:29:01 -0700124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 // Used locally for determining when to make a last ditch effort to log
126 // discharge stats before the device dies.
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700127 private int mCriticalBatteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128
Jeff Sharkeyec43a6b2013-04-30 13:33:18 -0700129 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" };
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800130
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800131 private static final String DUMPSYS_DATA_PATH = "/data/system/";
132
133 // This should probably be exposed in the API, though it's not critical
Bookatz1a1b0462018-01-12 11:47:03 -0800134 private static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800135
136 private final Context mContext;
137 private final IBatteryStats mBatteryStats;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700138 BinderService mBinderService;
Jeff Brown605ea692012-10-05 16:33:10 -0700139 private final Handler mHandler;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800140
Jeff Browna4d82042012-10-02 19:11:19 -0700141 private final Object mLock = new Object();
142
Yifan Hong932190b2017-10-11 11:00:51 -0700143 private HealthInfo mHealthInfo;
144 private final HealthInfo mLastHealthInfo = new HealthInfo();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800145 private boolean mBatteryLevelCritical;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800146 private int mLastBatteryStatus;
147 private int mLastBatteryHealth;
148 private boolean mLastBatteryPresent;
149 private int mLastBatteryLevel;
150 private int mLastBatteryVoltage;
151 private int mLastBatteryTemperature;
152 private boolean mLastBatteryLevelCritical;
Adrian Roos76dc5a52015-07-21 16:20:36 -0700153 private int mLastMaxChargingCurrent;
Badhri Jagan Sridharanf92fcfe2015-10-27 13:59:34 -0700154 private int mLastMaxChargingVoltage;
Ruchi Kandoi6361e222016-04-07 11:28:30 -0700155 private int mLastChargeCounter;
Jeff Browna4d82042012-10-02 19:11:19 -0700156
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800157 private int mSequence = 1;
158
Jeff Browna4d82042012-10-02 19:11:19 -0700159 private int mInvalidCharger;
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700160 private int mLastInvalidCharger;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400161
162 private int mLowBatteryWarningLevel;
163 private int mLowBatteryCloseWarningLevel;
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700164 private int mShutdownBatteryTemperature;
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400165
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800166 private int mPlugType;
167 private int mLastPlugType = -1; // Extra state so we can detect first run
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800168
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700169 private boolean mBatteryLevelLow;
170
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800171 private long mDischargeStartTime;
172 private int mDischargeStartLevel;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800173
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700174 private boolean mUpdatesStopped;
175
Joe Onoratode1b3592010-10-25 20:36:47 -0700176 private Led mLed;
177
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700178 private boolean mSentLowBatteryBroadcast = false;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800179
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700180 private ActivityManagerInternal mActivityManagerInternal;
181
Yifan Hong89d55c12017-10-11 11:29:01 -0700182 private HealthServiceWrapper mHealthServiceWrapper;
183 private HealthHalCallback mHealthHalCallback;
Yifan Hong1fd86f4c2017-10-09 16:50:33 -0700184 private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800185 private ArrayDeque<Bundle> mBatteryLevelsEventQueue;
186 private long mLastBatteryLevelChangedSentMs;
Yifan Hong89d55c12017-10-11 11:29:01 -0700187
Jeff Brown21392762014-06-13 19:00:36 -0700188 public BatteryService(Context context) {
189 super(context);
190
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800191 mContext = context;
Jeff Brown605ea692012-10-05 16:33:10 -0700192 mHandler = new Handler(true /*async*/);
Jeff Brown21392762014-06-13 19:00:36 -0700193 mLed = new Led(context, getLocalService(LightsManager.class));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800194 mBatteryStats = BatteryStatsService.getService();
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700195 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800196
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700197 mCriticalBatteryLevel = mContext.getResources().getInteger(
198 com.android.internal.R.integer.config_criticalBatteryWarningLevel);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400199 mLowBatteryWarningLevel = mContext.getResources().getInteger(
200 com.android.internal.R.integer.config_lowBatteryWarningLevel);
Dianne Hackborn14272302014-06-10 23:13:02 -0700201 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
202 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700203 mShutdownBatteryTemperature = mContext.getResources().getInteger(
204 com.android.internal.R.integer.config_shutdownBatteryTemperature);
Mike Lockwoodd81b1f42009-09-25 09:32:19 -0400205
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800206 mBatteryLevelsEventQueue = new ArrayDeque<>();
207
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400208 // watch for invalid charger messages if the invalid_charger switch exists
209 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700210 UEventObserver invalidChargerObserver = new UEventObserver() {
211 @Override
212 public void onUEvent(UEvent event) {
213 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0;
214 synchronized (mLock) {
215 if (mInvalidCharger != invalidCharger) {
216 mInvalidCharger = invalidCharger;
217 }
218 }
219 }
220 };
221 invalidChargerObserver.startObserving(
Jeff Browna4d82042012-10-02 19:11:19 -0700222 "DEVPATH=/devices/virtual/switch/invalid_charger");
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400223 }
Jeff Brown21392762014-06-13 19:00:36 -0700224 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225
Jeff Brown21392762014-06-13 19:00:36 -0700226 @Override
227 public void onStart() {
Yifan Hong89d55c12017-10-11 11:29:01 -0700228 registerHealthCallback();
Jeff Brown21392762014-06-13 19:00:36 -0700229
Dianne Hackborn2e441072015-10-28 18:00:57 -0700230 mBinderService = new BinderService();
231 publishBinderService("battery", mBinderService);
Yifan Hong1fd86f4c2017-10-09 16:50:33 -0700232 mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar();
233 publishBinderService("batteryproperties", mBatteryPropertiesRegistrar);
Jeff Brown21392762014-06-13 19:00:36 -0700234 publishLocalService(BatteryManagerInternal.class, new LocalService());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800235 }
236
Jeff Brown21392762014-06-13 19:00:36 -0700237 @Override
238 public void onBootPhase(int phase) {
239 if (phase == PHASE_ACTIVITY_MANAGER_READY) {
240 // check our power situation now that it is safe to display the shutdown dialog.
241 synchronized (mLock) {
242 ContentObserver obs = new ContentObserver(mHandler) {
243 @Override
244 public void onChange(boolean selfChange) {
245 synchronized (mLock) {
246 updateBatteryWarningLevelLocked();
247 }
Dianne Hackborn14272302014-06-10 23:13:02 -0700248 }
Jeff Brown21392762014-06-13 19:00:36 -0700249 };
250 final ContentResolver resolver = mContext.getContentResolver();
251 resolver.registerContentObserver(Settings.Global.getUriFor(
252 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL),
253 false, obs, UserHandle.USER_ALL);
254 updateBatteryWarningLevelLocked();
255 }
Jeff Browna4d82042012-10-02 19:11:19 -0700256 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800257 }
258
Yifan Hong89d55c12017-10-11 11:29:01 -0700259 private void registerHealthCallback() {
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700260 traceBegin("HealthInitWrapper");
Yifan Hong89d55c12017-10-11 11:29:01 -0700261 mHealthServiceWrapper = new HealthServiceWrapper();
262 mHealthHalCallback = new HealthHalCallback();
263 // IHealth is lazily retrieved.
264 try {
265 mHealthServiceWrapper.init(mHealthHalCallback,
266 new HealthServiceWrapper.IServiceManagerSupplier() {},
267 new HealthServiceWrapper.IHealthSupplier() {});
Yifan Hong78e8af12017-10-26 15:57:19 -0700268 } catch (RemoteException ex) {
269 Slog.e(TAG, "health: cannot register callback. (RemoteException)");
270 throw ex.rethrowFromSystemServer();
271 } catch (NoSuchElementException ex) {
272 Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)");
273 throw ex;
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700274 } finally {
275 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -0700276 }
277
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700278 traceBegin("HealthInitWaitUpdate");
Yifan Hong89d55c12017-10-11 11:29:01 -0700279 // init register for new service notifications, and IServiceManager should return the
280 // existing service in a near future. Wait for this.update() to instantiate
281 // the initial mHealthInfo.
Yifan Hong78e8af12017-10-26 15:57:19 -0700282 long beforeWait = SystemClock.uptimeMillis();
Yifan Hong89d55c12017-10-11 11:29:01 -0700283 synchronized (mLock) {
Yifan Hong78e8af12017-10-26 15:57:19 -0700284 while (mHealthInfo == null) {
285 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) +
286 "ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms...");
Yifan Hong89d55c12017-10-11 11:29:01 -0700287 try {
Yifan Hong78e8af12017-10-26 15:57:19 -0700288 mLock.wait(HEALTH_HAL_WAIT_MS);
Yifan Hong89d55c12017-10-11 11:29:01 -0700289 } catch (InterruptedException ex) {
Yifan Hong78e8af12017-10-26 15:57:19 -0700290 Slog.i(TAG, "health: InterruptedException when waiting for update. "
291 + " Continuing...");
Yifan Hong89d55c12017-10-11 11:29:01 -0700292 }
293 }
Yifan Hong89d55c12017-10-11 11:29:01 -0700294 }
295
Yifan Hong78e8af12017-10-26 15:57:19 -0700296 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait)
297 + "ms and received the update.");
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700298 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -0700299 }
300
Jeff Brown21392762014-06-13 19:00:36 -0700301 private void updateBatteryWarningLevelLocked() {
Dianne Hackborn14272302014-06-10 23:13:02 -0700302 final ContentResolver resolver = mContext.getContentResolver();
303 int defWarnLevel = mContext.getResources().getInteger(
304 com.android.internal.R.integer.config_lowBatteryWarningLevel);
305 mLowBatteryWarningLevel = Settings.Global.getInt(resolver,
306 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel);
307 if (mLowBatteryWarningLevel == 0) {
308 mLowBatteryWarningLevel = defWarnLevel;
309 }
310 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) {
311 mLowBatteryWarningLevel = mCriticalBatteryLevel;
312 }
313 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger(
314 com.android.internal.R.integer.config_lowBatteryCloseWarningBump);
315 processValuesLocked(true);
316 }
317
Jeff Browna4d82042012-10-02 19:11:19 -0700318 private boolean isPoweredLocked(int plugTypeSet) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800319 // assume we are powered if battery state is unknown so
320 // the "stay on while plugged in" option will work.
Yifan Honge41e9392017-11-06 12:56:59 -0800321 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800322 return true;
323 }
Yifan Honge41e9392017-11-06 12:56:59 -0800324 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 && mHealthInfo.chargerAcOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700325 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800326 }
Yifan Honge41e9392017-11-06 12:56:59 -0800327 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 && mHealthInfo.chargerUsbOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700328 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800329 }
Yifan Honge41e9392017-11-06 12:56:59 -0800330 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 && mHealthInfo.chargerWirelessOnline) {
Jeff Browna4d82042012-10-02 19:11:19 -0700331 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800332 }
Jeff Browna4d82042012-10-02 19:11:19 -0700333 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 }
335
Jeff Brown21392762014-06-13 19:00:36 -0700336 private boolean shouldSendBatteryLowLocked() {
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700337 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE;
338 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE;
339
340 /* The ACTION_BATTERY_LOW broadcast is sent in these situations:
341 * - is just un-plugged (previously was plugged) and battery level is
342 * less than or equal to WARNING, or
343 * - is not plugged and battery level falls to WARNING boundary
344 * (becomes <= mLowBatteryWarningLevel).
345 */
346 return !plugged
Yifan Honge41e9392017-11-06 12:56:59 -0800347 && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
348 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel
Dianne Hackborneb94fa72014-06-03 17:48:12 -0700349 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
350 }
351
Jeff Browna4d82042012-10-02 19:11:19 -0700352 private void shutdownIfNoPowerLocked() {
Mike Lockwood07a500f2009-08-12 09:56:44 -0400353 // shut down gracefully if our battery is critically low and we are not powered.
354 // wait until the system has booted before attempting to display the shutdown dialog.
Yifan Honge41e9392017-11-06 12:56:59 -0800355 if (mHealthInfo.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
Jeff Brown605ea692012-10-05 16:33:10 -0700356 mHandler.post(new Runnable() {
357 @Override
358 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700359 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700360 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
361 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
Sudheer Shanka292637f2017-09-25 10:36:23 -0700362 intent.putExtra(Intent.EXTRA_REASON,
363 PowerManager.SHUTDOWN_LOW_BATTERY);
Jeff Brown605ea692012-10-05 16:33:10 -0700364 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
365 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
366 }
367 }
368 });
Mike Lockwood07a500f2009-08-12 09:56:44 -0400369 }
370 }
371
Jeff Browna4d82042012-10-02 19:11:19 -0700372 private void shutdownIfOverTempLocked() {
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700373 // shut down gracefully if temperature is too high (> 68.0C by default)
374 // wait until the system has booted before attempting to display the
375 // shutdown dialog.
Yifan Honge41e9392017-11-06 12:56:59 -0800376 if (mHealthInfo.batteryTemperature > mShutdownBatteryTemperature) {
Jeff Brown605ea692012-10-05 16:33:10 -0700377 mHandler.post(new Runnable() {
378 @Override
379 public void run() {
Sudheer Shankafc46e9b2016-10-21 17:55:27 -0700380 if (mActivityManagerInternal.isSystemReady()) {
Jeff Brown605ea692012-10-05 16:33:10 -0700381 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
382 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
Sudheer Shanka292637f2017-09-25 10:36:23 -0700383 intent.putExtra(Intent.EXTRA_REASON,
384 PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE);
Jeff Brown605ea692012-10-05 16:33:10 -0700385 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
386 mContext.startActivityAsUser(intent, UserHandle.CURRENT);
387 }
388 }
389 });
Eric Olsen6a362a92010-03-26 15:38:41 -0700390 }
391 }
392
Hridya Valsarajua09fa902018-01-17 23:04:46 -0800393 private void update(android.hardware.health.V2_0.HealthInfo info) {
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700394 traceBegin("HealthInfoUpdate");
Todd Poynor26faecc2013-05-22 18:54:48 -0700395 synchronized (mLock) {
396 if (!mUpdatesStopped) {
Hridya Valsarajua09fa902018-01-17 23:04:46 -0800397 mHealthInfo = info.legacy;
Todd Poynor26faecc2013-05-22 18:54:48 -0700398 // Process the new values.
Dianne Hackborn14272302014-06-10 23:13:02 -0700399 processValuesLocked(false);
Yifan Hong89d55c12017-10-11 11:29:01 -0700400 mLock.notifyAll(); // for any waiters on new info
Dianne Hackborna1f1a3c2014-02-24 18:12:28 -0800401 } else {
Hridya Valsarajua09fa902018-01-17 23:04:46 -0800402 copy(mLastHealthInfo, info.legacy);
Todd Poynor26faecc2013-05-22 18:54:48 -0700403 }
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700404 }
Yifan Hong8cc18ef2017-10-31 12:27:47 -0700405 traceEnd();
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700406 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800407
Yifan Hong932190b2017-10-11 11:00:51 -0700408 private static void copy(HealthInfo dst, HealthInfo src) {
Yifan Honge41e9392017-11-06 12:56:59 -0800409 dst.chargerAcOnline = src.chargerAcOnline;
410 dst.chargerUsbOnline = src.chargerUsbOnline;
411 dst.chargerWirelessOnline = src.chargerWirelessOnline;
412 dst.maxChargingCurrent = src.maxChargingCurrent;
413 dst.maxChargingVoltage = src.maxChargingVoltage;
414 dst.batteryStatus = src.batteryStatus;
415 dst.batteryHealth = src.batteryHealth;
416 dst.batteryPresent = src.batteryPresent;
417 dst.batteryLevel = src.batteryLevel;
418 dst.batteryVoltage = src.batteryVoltage;
419 dst.batteryTemperature = src.batteryTemperature;
420 dst.batteryCurrent = src.batteryCurrent;
421 dst.batteryCycleCount = src.batteryCycleCount;
422 dst.batteryFullCharge = src.batteryFullCharge;
423 dst.batteryChargeCounter = src.batteryChargeCounter;
424 dst.batteryTechnology = src.batteryTechnology;
Yifan Hong932190b2017-10-11 11:00:51 -0700425 }
426
Dianne Hackborn14272302014-06-10 23:13:02 -0700427 private void processValuesLocked(boolean force) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700428 boolean logOutlier = false;
429 long dischargeDuration = 0;
Joe Onoratoa7e4cf9b2009-07-28 18:18:20 -0700430
Todd Poynorb41df4422017-12-08 10:44:40 -0800431 mBatteryLevelCritical =
432 mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN
433 && mHealthInfo.batteryLevel <= mCriticalBatteryLevel;
Yifan Honge41e9392017-11-06 12:56:59 -0800434 if (mHealthInfo.chargerAcOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800435 mPlugType = BatteryManager.BATTERY_PLUGGED_AC;
Yifan Honge41e9392017-11-06 12:56:59 -0800436 } else if (mHealthInfo.chargerUsbOnline) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 mPlugType = BatteryManager.BATTERY_PLUGGED_USB;
Yifan Honge41e9392017-11-06 12:56:59 -0800438 } else if (mHealthInfo.chargerWirelessOnline) {
Brian Muramatsu37a37f42012-08-14 15:21:02 -0700439 mPlugType = BatteryManager.BATTERY_PLUGGED_WIRELESS;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440 } else {
441 mPlugType = BATTERY_PLUGGED_NONE;
442 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700443
Jeff Browna4d82042012-10-02 19:11:19 -0700444 if (DEBUG) {
445 Slog.d(TAG, "Processing new values: "
Yifan Hong932190b2017-10-11 11:00:51 -0700446 + "info=" + mHealthInfo
Jeff Browna4d82042012-10-02 19:11:19 -0700447 + ", mBatteryLevelCritical=" + mBatteryLevelCritical
448 + ", mPlugType=" + mPlugType);
449 }
450
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700451 // Let the battery stats keep track of the current level.
452 try {
Yifan Honge41e9392017-11-06 12:56:59 -0800453 mBatteryStats.setBatteryState(mHealthInfo.batteryStatus, mHealthInfo.batteryHealth,
454 mPlugType, mHealthInfo.batteryLevel, mHealthInfo.batteryTemperature,
455 mHealthInfo.batteryVoltage, mHealthInfo.batteryChargeCounter,
456 mHealthInfo.batteryFullCharge);
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700457 } catch (RemoteException e) {
458 // Should never happen.
459 }
Brian Muramatsuf3c74f32012-08-31 15:14:48 -0700460
Jeff Browna4d82042012-10-02 19:11:19 -0700461 shutdownIfNoPowerLocked();
462 shutdownIfOverTempLocked();
Dianne Hackborn6b7b4842010-06-14 17:17:44 -0700463
Yifan Honge41e9392017-11-06 12:56:59 -0800464 if (force || (mHealthInfo.batteryStatus != mLastBatteryStatus ||
465 mHealthInfo.batteryHealth != mLastBatteryHealth ||
466 mHealthInfo.batteryPresent != mLastBatteryPresent ||
467 mHealthInfo.batteryLevel != mLastBatteryLevel ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 mPlugType != mLastPlugType ||
Yifan Honge41e9392017-11-06 12:56:59 -0800469 mHealthInfo.batteryVoltage != mLastBatteryVoltage ||
470 mHealthInfo.batteryTemperature != mLastBatteryTemperature ||
471 mHealthInfo.maxChargingCurrent != mLastMaxChargingCurrent ||
472 mHealthInfo.maxChargingVoltage != mLastMaxChargingVoltage ||
473 mHealthInfo.batteryChargeCounter != mLastChargeCounter ||
Dianne Hackborn14272302014-06-10 23:13:02 -0700474 mInvalidCharger != mLastInvalidCharger)) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800475
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800476 if (mPlugType != mLastPlugType) {
477 if (mLastPlugType == BATTERY_PLUGGED_NONE) {
478 // discharging -> charging
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800479
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800480 // There's no value in this data unless we've discharged at least once and the
481 // battery level has changed; so don't log until it does.
Yifan Honge41e9392017-11-06 12:56:59 -0800482 if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.batteryLevel) {
The Android Open Source Project10592532009-03-18 17:39:46 -0700483 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
484 logOutlier = true;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800485 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration,
Yifan Honge41e9392017-11-06 12:56:59 -0800486 mDischargeStartLevel, mHealthInfo.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800487 // make sure we see a discharge event before logging again
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800488 mDischargeStartTime = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800489 }
490 } else if (mPlugType == BATTERY_PLUGGED_NONE) {
491 // charging -> discharging or we just powered up
492 mDischargeStartTime = SystemClock.elapsedRealtime();
Yifan Honge41e9392017-11-06 12:56:59 -0800493 mDischargeStartLevel = mHealthInfo.batteryLevel;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800494 }
495 }
Yifan Honge41e9392017-11-06 12:56:59 -0800496 if (mHealthInfo.batteryStatus != mLastBatteryStatus ||
497 mHealthInfo.batteryHealth != mLastBatteryHealth ||
498 mHealthInfo.batteryPresent != mLastBatteryPresent ||
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800499 mPlugType != mLastPlugType) {
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800500 EventLog.writeEvent(EventLogTags.BATTERY_STATUS,
Yifan Honge41e9392017-11-06 12:56:59 -0800501 mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0,
502 mPlugType, mHealthInfo.batteryTechnology);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800503 }
Yifan Honge41e9392017-11-06 12:56:59 -0800504 if (mHealthInfo.batteryLevel != mLastBatteryLevel) {
Dianne Hackborncf1171642013-07-12 17:26:02 -0700505 // Don't do this just from voltage or temperature changes, that is
506 // too noisy.
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800507 EventLog.writeEvent(EventLogTags.BATTERY_LEVEL,
Yifan Honge41e9392017-11-06 12:56:59 -0800508 mHealthInfo.batteryLevel, mHealthInfo.batteryVoltage, mHealthInfo.batteryTemperature);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800509 }
510 if (mBatteryLevelCritical && !mLastBatteryLevelCritical &&
511 mPlugType == BATTERY_PLUGGED_NONE) {
512 // We want to make sure we log discharge cycle outliers
513 // if the battery is about to die.
The Android Open Source Project10592532009-03-18 17:39:46 -0700514 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime;
515 logOutlier = true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800516 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800517
Dianne Hackborn14272302014-06-10 23:13:02 -0700518 if (!mBatteryLevelLow) {
519 // Should we now switch in to low battery mode?
520 if (mPlugType == BATTERY_PLUGGED_NONE
Todd Poynorb41df4422017-12-08 10:44:40 -0800521 && mHealthInfo.batteryStatus !=
522 BatteryManager.BATTERY_STATUS_UNKNOWN
Yifan Honge41e9392017-11-06 12:56:59 -0800523 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700524 mBatteryLevelLow = true;
525 }
526 } else {
527 // Should we now switch out of low battery mode?
528 if (mPlugType != BATTERY_PLUGGED_NONE) {
529 mBatteryLevelLow = false;
Yifan Honge41e9392017-11-06 12:56:59 -0800530 } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700531 mBatteryLevelLow = false;
Yifan Honge41e9392017-11-06 12:56:59 -0800532 } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) {
Dianne Hackborn14272302014-06-10 23:13:02 -0700533 // If being forced, the previous state doesn't matter, we will just
534 // absolutely check to see if we are now above the warning level.
535 mBatteryLevelLow = false;
536 }
537 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800538
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800539 mSequence++;
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800540
Christopher Tate06ba5542009-04-09 16:03:56 -0700541 // Separate broadcast is sent for power connected / not connected
542 // since the standard intent will not wake any applications and some
543 // applications may want to have smart behavior based on this.
544 if (mPlugType != 0 && mLastPlugType == 0) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800545 final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED);
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 }
555 else if (mPlugType == 0 && mLastPlugType != 0) {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800556 final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED);
557 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
558 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700559 mHandler.post(new Runnable() {
560 @Override
561 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700562 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
563 }
564 });
Christopher Tate06ba5542009-04-09 16:03:56 -0700565 }
Mihai Predaa82842f2009-04-29 15:05:56 +0200566
Dianne Hackborn14272302014-06-10 23:13:02 -0700567 if (shouldSendBatteryLowLocked()) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700568 mSentLowBatteryBroadcast = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800569 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW);
570 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
571 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700572 mHandler.post(new Runnable() {
573 @Override
574 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700575 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
576 }
577 });
Dianne Hackborn532ea262017-03-17 17:50:55 -0700578 } else if (mSentLowBatteryBroadcast &&
Yifan Honge41e9392017-11-06 12:56:59 -0800579 mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) {
Dianne Hackborn8ec5b832009-07-01 21:19:35 -0700580 mSentLowBatteryBroadcast = false;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800581 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY);
582 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
583 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Jeff Brown605ea692012-10-05 16:33:10 -0700584 mHandler.post(new Runnable() {
585 @Override
586 public void run() {
Jeff Brown605ea692012-10-05 16:33:10 -0700587 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL);
588 }
589 });
Mihai Predaa82842f2009-04-29 15:05:56 +0200590 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800591
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800592 // We are doing this after sending the above broadcasts, so anything processing
593 // them will get the new sequence number at that point. (See for example how testing
594 // of JobScheduler's BatteryController works.)
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800595 sendBatteryChangedIntentLocked();
596 if (mLastBatteryLevel != mHealthInfo.batteryLevel) {
597 sendBatteryLevelChangedIntentLocked();
598 }
599
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800600
Joe Onoratode1b3592010-10-25 20:36:47 -0700601 // Update the battery LED
602 mLed.updateLightsLocked();
603
The Android Open Source Project10592532009-03-18 17:39:46 -0700604 // This needs to be done after sendIntent() so that we get the lastest battery stats.
605 if (logOutlier && dischargeDuration != 0) {
Jeff Browna4d82042012-10-02 19:11:19 -0700606 logOutlierLocked(dischargeDuration);
The Android Open Source Project10592532009-03-18 17:39:46 -0700607 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800608
Yifan Honge41e9392017-11-06 12:56:59 -0800609 mLastBatteryStatus = mHealthInfo.batteryStatus;
610 mLastBatteryHealth = mHealthInfo.batteryHealth;
611 mLastBatteryPresent = mHealthInfo.batteryPresent;
612 mLastBatteryLevel = mHealthInfo.batteryLevel;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700613 mLastPlugType = mPlugType;
Yifan Honge41e9392017-11-06 12:56:59 -0800614 mLastBatteryVoltage = mHealthInfo.batteryVoltage;
615 mLastBatteryTemperature = mHealthInfo.batteryTemperature;
616 mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrent;
617 mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltage;
618 mLastChargeCounter = mHealthInfo.batteryChargeCounter;
Dianne Hackborn99f7eb452009-09-22 17:27:53 -0700619 mLastBatteryLevelCritical = mBatteryLevelCritical;
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400620 mLastInvalidCharger = mInvalidCharger;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800621 }
622 }
623
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800624 private void sendBatteryChangedIntentLocked() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800625 // Pack up the values and broadcast them to everyone
Jeff Brown605ea692012-10-05 16:33:10 -0700626 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -0800627 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
628 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800629
Yifan Honge41e9392017-11-06 12:56:59 -0800630 int icon = getIconLocked(mHealthInfo.batteryLevel);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800631
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800632 intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence);
Yifan Honge41e9392017-11-06 12:56:59 -0800633 intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
634 intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
635 intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
636 intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
Dianne Hackborn74ed6ec2017-11-21 16:33:44 -0800637 intent.putExtra(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
Dianne Hackbornedd93162009-09-19 14:03:05 -0700638 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
639 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon);
640 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType);
Yifan Honge41e9392017-11-06 12:56:59 -0800641 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
642 intent.putExtra(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperature);
643 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology);
Mike Lockwooddeff9c82010-09-04 10:29:17 -0400644 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger);
Yifan Honge41e9392017-11-06 12:56:59 -0800645 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
646 intent.putExtra(BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
647 intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
Jeff Browna4d82042012-10-02 19:11:19 -0700648 if (DEBUG) {
Yifan Hong932190b2017-10-11 11:00:51 -0700649 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE
650 + ", info:" + mHealthInfo.toString());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800651 }
652
Fyodor Kupolov70e75432018-03-01 18:29:06 -0800653 mHandler.post(() -> ActivityManager.broadcastStickyIntent(intent, UserHandle.USER_ALL));
654 }
655
656 private void sendBatteryLevelChangedIntentLocked() {
657 Bundle event = new Bundle();
658 long now = SystemClock.elapsedRealtime();
659 event.putInt(BatteryManager.EXTRA_SEQUENCE, mSequence);
660 event.putInt(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus);
661 event.putInt(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth);
662 event.putBoolean(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent);
663 event.putInt(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel);
664 event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast);
665 event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE);
666 event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType);
667 event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltage);
668 event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now);
669
670 boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty();
671 mBatteryLevelsEventQueue.add(event);
672 // Make sure queue is bounded and doesn't exceed intent payload limits
673 if (mBatteryLevelsEventQueue.size() > MAX_BATTERY_LEVELS_QUEUE_SIZE) {
674 mBatteryLevelsEventQueue.removeFirst();
675 }
676
677 if (queueWasEmpty) {
678 // send now if last event was before throttle interval, otherwise delay
679 long delay = now - mLastBatteryLevelChangedSentMs > BATTERY_LEVEL_CHANGE_THROTTLE_MS
680 ? 0 : mLastBatteryLevelChangedSentMs + BATTERY_LEVEL_CHANGE_THROTTLE_MS - now;
681 mHandler.postDelayed(this::sendEnqueuedBatteryLevelChangedEvents, delay);
682 }
683 }
684
685 private void sendEnqueuedBatteryLevelChangedEvents() {
686 ArrayList<Bundle> events;
687 synchronized (mLock) {
688 events = new ArrayList<>(mBatteryLevelsEventQueue);
689 mBatteryLevelsEventQueue.clear();
690 }
691 final Intent intent = new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED);
692 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
693 intent.putParcelableArrayListExtra(BatteryManager.EXTRA_EVENTS, events);
694
695 mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
696 android.Manifest.permission.BATTERY_STATS);
697 mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800698 }
699
Jeff Browna4d82042012-10-02 19:11:19 -0700700 private void logBatteryStatsLocked() {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700701 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME);
Dan Egnor18e93962010-02-10 19:27:58 -0800702 if (batteryInfoService == null) return;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800703
Dan Egnor18e93962010-02-10 19:27:58 -0800704 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE);
705 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return;
706
707 File dumpFile = null;
708 FileOutputStream dumpStream = null;
709 try {
710 // dump the service to a file
Dianne Hackborn8c841092013-06-24 13:46:13 -0700711 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump");
Dan Egnor18e93962010-02-10 19:27:58 -0800712 dumpStream = new FileOutputStream(dumpFile);
713 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS);
Dianne Hackborn8bdf5932010-10-15 12:54:40 -0700714 FileUtils.sync(dumpStream);
Dan Egnor18e93962010-02-10 19:27:58 -0800715
716 // add dump file to drop box
717 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT);
718 } catch (RemoteException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800719 Slog.e(TAG, "failed to dump battery service", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800720 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800721 Slog.e(TAG, "failed to write dumpsys file", e);
Dan Egnor18e93962010-02-10 19:27:58 -0800722 } finally {
723 // make sure we clean up
724 if (dumpStream != null) {
725 try {
726 dumpStream.close();
727 } catch (IOException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800728 Slog.e(TAG, "failed to close dumpsys output stream");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800729 }
Dan Egnor18e93962010-02-10 19:27:58 -0800730 }
731 if (dumpFile != null && !dumpFile.delete()) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800732 Slog.e(TAG, "failed to delete temporary dumpsys file: "
Dan Egnor18e93962010-02-10 19:27:58 -0800733 + dumpFile.getAbsolutePath());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800734 }
735 }
736 }
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800737
Jeff Browna4d82042012-10-02 19:11:19 -0700738 private void logOutlierLocked(long duration) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800739 ContentResolver cr = mContext.getContentResolver();
Jeff Sharkey625239a2012-09-26 22:03:49 -0700740 String dischargeThresholdString = Settings.Global.getString(cr,
741 Settings.Global.BATTERY_DISCHARGE_THRESHOLD);
742 String durationThresholdString = Settings.Global.getString(cr,
743 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800744
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 if (dischargeThresholdString != null && durationThresholdString != null) {
746 try {
747 long durationThreshold = Long.parseLong(durationThresholdString);
748 int dischargeThreshold = Integer.parseInt(dischargeThresholdString);
Doug Zongkerab5c49c2009-12-04 10:31:43 -0800749 if (duration <= durationThreshold &&
Yifan Honge41e9392017-11-06 12:56:59 -0800750 mDischargeStartLevel - mHealthInfo.batteryLevel >= dischargeThreshold) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 // If the discharge cycle is bad enough we want to know about it.
Jeff Browna4d82042012-10-02 19:11:19 -0700752 logBatteryStatsLocked();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800753 }
Jeff Browna4d82042012-10-02 19:11:19 -0700754 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800755 " discharge threshold: " + dischargeThreshold);
Jeff Browna4d82042012-10-02 19:11:19 -0700756 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " +
Yifan Honge41e9392017-11-06 12:56:59 -0800757 (mDischargeStartLevel - mHealthInfo.batteryLevel));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800758 } catch (NumberFormatException e) {
Joe Onorato8a9b2202010-02-26 18:56:32 -0800759 Slog.e(TAG, "Invalid DischargeThresholds GService string: " +
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 durationThresholdString + " or " + dischargeThresholdString);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800761 }
762 }
763 }
764
Jeff Browna4d82042012-10-02 19:11:19 -0700765 private int getIconLocked(int level) {
Yifan Honge41e9392017-11-06 12:56:59 -0800766 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 return com.android.internal.R.drawable.stat_sys_battery_charge;
Yifan Honge41e9392017-11-06 12:56:59 -0800768 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800769 return com.android.internal.R.drawable.stat_sys_battery;
Yifan Honge41e9392017-11-06 12:56:59 -0800770 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING
771 || mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) {
Jeff Browna4d82042012-10-02 19:11:19 -0700772 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)
Yifan Honge41e9392017-11-06 12:56:59 -0800773 && mHealthInfo.batteryLevel >= 100) {
Joe Onorato794be402010-11-21 19:22:25 -0800774 return com.android.internal.R.drawable.stat_sys_battery_charge;
775 } else {
776 return com.android.internal.R.drawable.stat_sys_battery;
777 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800778 } else {
779 return com.android.internal.R.drawable.stat_sys_battery_unknown;
780 }
781 }
782
Dianne Hackborn2e441072015-10-28 18:00:57 -0700783 class Shell extends ShellCommand {
784 @Override
785 public int onCommand(String cmd) {
786 return onShellCommand(this, cmd);
787 }
788
789 @Override
790 public void onHelp() {
791 PrintWriter pw = getOutPrintWriter();
792 dumpHelp(pw);
793 }
794 }
795
796 static void dumpHelp(PrintWriter pw) {
797 pw.println("Battery service (battery) commands:");
798 pw.println(" help");
799 pw.println(" Print this help text.");
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700800 pw.println(" set [-f] [ac|usb|wireless|status|level|temp|present|invalid] <value>");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700801 pw.println(" Force a battery property value, freezing battery state.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800802 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
803 pw.println(" unplug [-f]");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700804 pw.println(" Force battery unplugged, freezing battery state.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800805 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
806 pw.println(" reset [-f]");
Dianne Hackborn2e441072015-10-28 18:00:57 -0700807 pw.println(" Unfreeze battery state, returning to current hardware values.");
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800808 pw.println(" -f: force a battery change broadcast be sent, prints new sequence.");
809 }
810
811 static final int OPTION_FORCE_UPDATE = 1<<0;
812
813 int parseOptions(Shell shell) {
814 String opt;
815 int opts = 0;
816 while ((opt = shell.getNextOption()) != null) {
817 if ("-f".equals(opt)) {
818 opts |= OPTION_FORCE_UPDATE;
819 }
820 }
821 return opts;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700822 }
823
824 int onShellCommand(Shell shell, String cmd) {
825 if (cmd == null) {
826 return shell.handleDefaultCommands(cmd);
827 }
828 PrintWriter pw = shell.getOutPrintWriter();
829 switch (cmd) {
830 case "unplug": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800831 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700832 getContext().enforceCallingOrSelfPermission(
833 android.Manifest.permission.DEVICE_POWER, null);
834 if (!mUpdatesStopped) {
Yifan Hong932190b2017-10-11 11:00:51 -0700835 copy(mLastHealthInfo, mHealthInfo);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700836 }
Yifan Honge41e9392017-11-06 12:56:59 -0800837 mHealthInfo.chargerAcOnline = false;
838 mHealthInfo.chargerUsbOnline = false;
839 mHealthInfo.chargerWirelessOnline = false;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700840 long ident = Binder.clearCallingIdentity();
841 try {
842 mUpdatesStopped = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800843 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700844 } finally {
845 Binder.restoreCallingIdentity(ident);
846 }
847 } break;
848 case "set": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800849 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700850 getContext().enforceCallingOrSelfPermission(
851 android.Manifest.permission.DEVICE_POWER, null);
852 final String key = shell.getNextArg();
853 if (key == null) {
854 pw.println("No property specified");
855 return -1;
856
857 }
858 final String value = shell.getNextArg();
859 if (value == null) {
860 pw.println("No value specified");
861 return -1;
862
863 }
864 try {
865 if (!mUpdatesStopped) {
Yifan Hong932190b2017-10-11 11:00:51 -0700866 copy(mLastHealthInfo, mHealthInfo);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700867 }
868 boolean update = true;
869 switch (key) {
Christopher Tate630d98b2017-03-07 14:12:26 -0800870 case "present":
Yifan Honge41e9392017-11-06 12:56:59 -0800871 mHealthInfo.batteryPresent = Integer.parseInt(value) != 0;
Christopher Tate630d98b2017-03-07 14:12:26 -0800872 break;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700873 case "ac":
Yifan Honge41e9392017-11-06 12:56:59 -0800874 mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700875 break;
876 case "usb":
Yifan Honge41e9392017-11-06 12:56:59 -0800877 mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700878 break;
879 case "wireless":
Yifan Honge41e9392017-11-06 12:56:59 -0800880 mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700881 break;
882 case "status":
Yifan Honge41e9392017-11-06 12:56:59 -0800883 mHealthInfo.batteryStatus = Integer.parseInt(value);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700884 break;
885 case "level":
Yifan Honge41e9392017-11-06 12:56:59 -0800886 mHealthInfo.batteryLevel = Integer.parseInt(value);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700887 break;
Makoto Onuki076218b2018-01-26 10:26:36 -0800888 case "counter":
889 mHealthInfo.batteryChargeCounter = Integer.parseInt(value);
890 break;
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700891 case "temp":
Yifan Honge41e9392017-11-06 12:56:59 -0800892 mHealthInfo.batteryTemperature = Integer.parseInt(value);
Adam Lesinski29ddfe52017-03-29 19:29:00 -0700893 break;
Dianne Hackborn2e441072015-10-28 18:00:57 -0700894 case "invalid":
895 mInvalidCharger = Integer.parseInt(value);
896 break;
897 default:
898 pw.println("Unknown set option: " + key);
899 update = false;
900 break;
901 }
902 if (update) {
903 long ident = Binder.clearCallingIdentity();
904 try {
905 mUpdatesStopped = true;
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800906 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700907 } finally {
908 Binder.restoreCallingIdentity(ident);
909 }
910 }
911 } catch (NumberFormatException ex) {
912 pw.println("Bad value: " + value);
913 return -1;
914 }
915 } break;
916 case "reset": {
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800917 int opts = parseOptions(shell);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700918 getContext().enforceCallingOrSelfPermission(
919 android.Manifest.permission.DEVICE_POWER, null);
920 long ident = Binder.clearCallingIdentity();
921 try {
922 if (mUpdatesStopped) {
923 mUpdatesStopped = false;
Yifan Hong932190b2017-10-11 11:00:51 -0700924 copy(mHealthInfo, mLastHealthInfo);
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800925 processValuesFromShellLocked(pw, opts);
Dianne Hackborn2e441072015-10-28 18:00:57 -0700926 }
927 } finally {
928 Binder.restoreCallingIdentity(ident);
929 }
930 } break;
931 default:
932 return shell.handleDefaultCommands(cmd);
933 }
934 return 0;
935 }
936
Dianne Hackborna06ec6a2017-02-13 10:08:42 -0800937 private void processValuesFromShellLocked(PrintWriter pw, int opts) {
938 processValuesLocked((opts & OPTION_FORCE_UPDATE) != 0);
939 if ((opts & OPTION_FORCE_UPDATE) != 0) {
940 pw.println(mSequence);
941 }
942 }
943
Dianne Hackborn2e441072015-10-28 18:00:57 -0700944 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Browna4d82042012-10-02 19:11:19 -0700945 synchronized (mLock) {
946 if (args == null || args.length == 0 || "-a".equals(args[0])) {
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700947 pw.println("Current Battery Service state:");
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700948 if (mUpdatesStopped) {
949 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)");
950 }
Yifan Honge41e9392017-11-06 12:56:59 -0800951 pw.println(" AC powered: " + mHealthInfo.chargerAcOnline);
952 pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline);
953 pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline);
954 pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrent);
955 pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltage);
956 pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounter);
957 pw.println(" status: " + mHealthInfo.batteryStatus);
958 pw.println(" health: " + mHealthInfo.batteryHealth);
959 pw.println(" present: " + mHealthInfo.batteryPresent);
960 pw.println(" level: " + mHealthInfo.batteryLevel);
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700961 pw.println(" scale: " + BATTERY_SCALE);
Yifan Honge41e9392017-11-06 12:56:59 -0800962 pw.println(" voltage: " + mHealthInfo.batteryVoltage);
963 pw.println(" temperature: " + mHealthInfo.batteryTemperature);
964 pw.println(" technology: " + mHealthInfo.batteryTechnology);
Dianne Hackbornc428aae2012-10-03 16:38:22 -0700965 } else {
Dianne Hackborn2e441072015-10-28 18:00:57 -0700966 Shell shell = new Shell();
Dianne Hackborn354736e2016-08-22 17:00:05 -0700967 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null));
Joe Onorato4ca7f1e2010-10-27 15:32:23 -0700968 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800969 }
970 }
Joe Onoratode1b3592010-10-25 20:36:47 -0700971
Netta Pe2a3cd82017-01-26 18:03:51 -0800972 private void dumpProto(FileDescriptor fd) {
973 final ProtoOutputStream proto = new ProtoOutputStream(fd);
974
975 synchronized (mLock) {
976 proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped);
Bookatz1a1b0462018-01-12 11:47:03 -0800977 int batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_NONE;
Yifan Honge41e9392017-11-06 12:56:59 -0800978 if (mHealthInfo.chargerAcOnline) {
Bookatz1a1b0462018-01-12 11:47:03 -0800979 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_AC;
Yifan Honge41e9392017-11-06 12:56:59 -0800980 } else if (mHealthInfo.chargerUsbOnline) {
Bookatz1a1b0462018-01-12 11:47:03 -0800981 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_USB;
Yifan Honge41e9392017-11-06 12:56:59 -0800982 } else if (mHealthInfo.chargerWirelessOnline) {
Bookatz1a1b0462018-01-12 11:47:03 -0800983 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS;
Netta Pe2a3cd82017-01-26 18:03:51 -0800984 }
985 proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue);
Yifan Honge41e9392017-11-06 12:56:59 -0800986 proto.write(BatteryServiceDumpProto.MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrent);
987 proto.write(BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, mHealthInfo.maxChargingVoltage);
988 proto.write(BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounter);
989 proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus);
990 proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth);
991 proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent);
992 proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel);
Netta Pe2a3cd82017-01-26 18:03:51 -0800993 proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE);
Yifan Honge41e9392017-11-06 12:56:59 -0800994 proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltage);
995 proto.write(BatteryServiceDumpProto.TEMPERATURE, mHealthInfo.batteryTemperature);
996 proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology);
Netta Pe2a3cd82017-01-26 18:03:51 -0800997 }
998 proto.flush();
999 }
1000
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001001 private static void traceBegin(String name) {
1002 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name);
1003 }
1004
1005 private static void traceEnd() {
1006 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
1007 }
1008
Jeff Browna4d82042012-10-02 19:11:19 -07001009 private final class Led {
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001010 private final Light mBatteryLight;
Joe Onoratode1b3592010-10-25 20:36:47 -07001011
Jeff Browna4d82042012-10-02 19:11:19 -07001012 private final int mBatteryLowARGB;
1013 private final int mBatteryMediumARGB;
1014 private final int mBatteryFullARGB;
1015 private final int mBatteryLedOn;
1016 private final int mBatteryLedOff;
1017
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001018 public Led(Context context, LightsManager lights) {
1019 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY);
Joe Onoratode1b3592010-10-25 20:36:47 -07001020
Jeff Browna4d82042012-10-02 19:11:19 -07001021 mBatteryLowARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001022 com.android.internal.R.integer.config_notificationsBatteryLowARGB);
Jeff Browna4d82042012-10-02 19:11:19 -07001023 mBatteryMediumARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001024 com.android.internal.R.integer.config_notificationsBatteryMediumARGB);
Jeff Browna4d82042012-10-02 19:11:19 -07001025 mBatteryFullARGB = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001026 com.android.internal.R.integer.config_notificationsBatteryFullARGB);
Jeff Browna4d82042012-10-02 19:11:19 -07001027 mBatteryLedOn = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001028 com.android.internal.R.integer.config_notificationsBatteryLedOn);
Jeff Browna4d82042012-10-02 19:11:19 -07001029 mBatteryLedOff = context.getResources().getInteger(
Joe Onoratode1b3592010-10-25 20:36:47 -07001030 com.android.internal.R.integer.config_notificationsBatteryLedOff);
1031 }
1032
1033 /**
1034 * Synchronize on BatteryService.
1035 */
Jeff Browna4d82042012-10-02 19:11:19 -07001036 public void updateLightsLocked() {
Yifan Honge41e9392017-11-06 12:56:59 -08001037 final int level = mHealthInfo.batteryLevel;
1038 final int status = mHealthInfo.batteryStatus;
Joe Onoratode1b3592010-10-25 20:36:47 -07001039 if (level < mLowBatteryWarningLevel) {
1040 if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
1041 // Solid red when battery is charging
1042 mBatteryLight.setColor(mBatteryLowARGB);
1043 } else {
1044 // Flash red when battery is low and not charging
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001045 mBatteryLight.setFlashing(mBatteryLowARGB, Light.LIGHT_FLASH_TIMED,
Joe Onoratode1b3592010-10-25 20:36:47 -07001046 mBatteryLedOn, mBatteryLedOff);
1047 }
1048 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING
1049 || status == BatteryManager.BATTERY_STATUS_FULL) {
1050 if (status == BatteryManager.BATTERY_STATUS_FULL || level >= 90) {
1051 // Solid green when full or charging and nearly full
1052 mBatteryLight.setColor(mBatteryFullARGB);
1053 } else {
1054 // Solid orange when charging and halfway full
1055 mBatteryLight.setColor(mBatteryMediumARGB);
1056 }
1057 } else {
1058 // No lights if not charging and not low
1059 mBatteryLight.turnOff();
1060 }
1061 }
1062 }
Todd Poynor26faecc2013-05-22 18:54:48 -07001063
Yifan Hong89d55c12017-10-11 11:29:01 -07001064 private final class HealthHalCallback extends IHealthInfoCallback.Stub
1065 implements HealthServiceWrapper.Callback {
Hridya Valsarajua09fa902018-01-17 23:04:46 -08001066 @Override public void healthInfoChanged(android.hardware.health.V2_0.HealthInfo props) {
Yifan Hong89d55c12017-10-11 11:29:01 -07001067 BatteryService.this.update(props);
1068 }
1069 // on new service registered
1070 @Override public void onRegistration(IHealth oldService, IHealth newService,
1071 String instance) {
1072 if (newService == null) return;
1073
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001074 traceBegin("HealthUnregisterCallback");
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001075 try {
Yifan Hong89d55c12017-10-11 11:29:01 -07001076 if (oldService != null) {
1077 int r = oldService.unregisterCallback(this);
1078 if (r != Result.SUCCESS) {
1079 Slog.w(TAG, "health: cannot unregister previous callback: " +
1080 Result.toString(r));
1081 }
1082 }
1083 } catch (RemoteException ex) {
1084 Slog.w(TAG, "health: cannot unregister previous callback (transaction error): "
1085 + ex.getMessage());
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001086 } finally {
1087 traceEnd();
Adam Lesinskief2ea1f2013-12-05 16:48:06 -08001088 }
Yifan Hong89d55c12017-10-11 11:29:01 -07001089
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001090 traceBegin("HealthRegisterCallback");
Yifan Hong89d55c12017-10-11 11:29:01 -07001091 try {
1092 int r = newService.registerCallback(this);
1093 if (r != Result.SUCCESS) {
1094 Slog.w(TAG, "health: cannot register callback: " + Result.toString(r));
1095 return;
1096 }
1097 // registerCallback does NOT guarantee that update is called
1098 // immediately, so request a manual update here.
1099 newService.update();
1100 } catch (RemoteException ex) {
1101 Slog.e(TAG, "health: cannot register callback (transaction error): "
1102 + ex.getMessage());
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001103 } finally {
1104 traceEnd();
Yifan Hong89d55c12017-10-11 11:29:01 -07001105 }
1106 }
Todd Poynor26faecc2013-05-22 18:54:48 -07001107 }
Jeff Brown21392762014-06-13 19:00:36 -07001108
1109 private final class BinderService extends Binder {
Dianne Hackborn2e441072015-10-28 18:00:57 -07001110 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -06001111 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Jeff Brown21392762014-06-13 19:00:36 -07001112
Netta Pe2a3cd82017-01-26 18:03:51 -08001113 if (args.length > 0 && "--proto".equals(args[0])) {
1114 dumpProto(fd);
1115 } else {
1116 dumpInternal(fd, pw, args);
1117 }
Dianne Hackborn2e441072015-10-28 18:00:57 -07001118 }
1119
1120 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out,
Dianne Hackborn354736e2016-08-22 17:00:05 -07001121 FileDescriptor err, String[] args, ShellCallback callback,
1122 ResultReceiver resultReceiver) {
1123 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver);
Jeff Brown21392762014-06-13 19:00:36 -07001124 }
1125 }
1126
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001127 // Reduced IBatteryPropertiesRegistrar that only implements getProperty for usage
1128 // in BatteryManager.
1129 private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub {
1130 public void registerListener(IBatteryPropertiesListener listener) {
1131 Slog.e(TAG, "health: must not call registerListener on battery properties");
1132 }
1133 public void unregisterListener(IBatteryPropertiesListener listener) {
1134 Slog.e(TAG, "health: must not call unregisterListener on battery properties");
1135 }
1136 public int getProperty(int id, final BatteryProperty prop) throws RemoteException {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001137 traceBegin("HealthGetProperty");
1138 try {
1139 IHealth service = mHealthServiceWrapper.getLastService();
1140 if (service == null) throw new RemoteException("no health service");
1141 final MutableInt outResult = new MutableInt(Result.NOT_SUPPORTED);
1142 switch(id) {
1143 case BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER:
1144 service.getChargeCounter((int result, int value) -> {
1145 outResult.value = result;
1146 if (result == Result.SUCCESS) prop.setLong(value);
1147 });
1148 break;
1149 case BatteryManager.BATTERY_PROPERTY_CURRENT_NOW:
1150 service.getCurrentNow((int result, int value) -> {
1151 outResult.value = result;
1152 if (result == Result.SUCCESS) prop.setLong(value);
1153 });
1154 break;
1155 case BatteryManager.BATTERY_PROPERTY_CURRENT_AVERAGE:
1156 service.getCurrentAverage((int result, int value) -> {
1157 outResult.value = result;
1158 if (result == Result.SUCCESS) prop.setLong(value);
1159 });
1160 break;
1161 case BatteryManager.BATTERY_PROPERTY_CAPACITY:
1162 service.getCapacity((int result, int value) -> {
1163 outResult.value = result;
1164 if (result == Result.SUCCESS) prop.setLong(value);
1165 });
1166 break;
1167 case BatteryManager.BATTERY_PROPERTY_STATUS:
1168 service.getChargeStatus((int result, int value) -> {
1169 outResult.value = result;
1170 if (result == Result.SUCCESS) prop.setLong(value);
1171 });
1172 break;
1173 case BatteryManager.BATTERY_PROPERTY_ENERGY_COUNTER:
1174 service.getEnergyCounter((int result, long value) -> {
1175 outResult.value = result;
1176 if (result == Result.SUCCESS) prop.setLong(value);
1177 });
1178 break;
1179 }
1180 return outResult.value;
1181 } finally {
1182 traceEnd();
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001183 }
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001184 }
Yifan Hong7838fcb2017-10-24 16:06:27 -07001185 public void scheduleUpdate() throws RemoteException {
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001186 traceBegin("HealthScheduleUpdate");
1187 try {
1188 IHealth service = mHealthServiceWrapper.getLastService();
1189 if (service == null) throw new RemoteException("no health service");
1190 service.update();
1191 } finally {
1192 traceEnd();
1193 }
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001194 }
1195 }
1196
Jeff Brown21392762014-06-13 19:00:36 -07001197 private final class LocalService extends BatteryManagerInternal {
1198 @Override
1199 public boolean isPowered(int plugTypeSet) {
1200 synchronized (mLock) {
1201 return isPoweredLocked(plugTypeSet);
1202 }
1203 }
1204
1205 @Override
1206 public int getPlugType() {
1207 synchronized (mLock) {
1208 return mPlugType;
1209 }
1210 }
1211
1212 @Override
1213 public int getBatteryLevel() {
1214 synchronized (mLock) {
Yifan Honge41e9392017-11-06 12:56:59 -08001215 return mHealthInfo.batteryLevel;
Jeff Brown21392762014-06-13 19:00:36 -07001216 }
1217 }
1218
1219 @Override
Makoto Onuki076218b2018-01-26 10:26:36 -08001220 public int getBatteryChargeCounter() {
1221 synchronized (mLock) {
1222 return mHealthInfo.batteryChargeCounter;
1223 }
1224 }
1225
1226 @Override
1227 public int getBatteryFullCharge() {
1228 synchronized (mLock) {
1229 return mHealthInfo.batteryFullCharge;
1230 }
1231 }
1232
1233 @Override
Jeff Brown21392762014-06-13 19:00:36 -07001234 public boolean getBatteryLevelLow() {
1235 synchronized (mLock) {
1236 return mBatteryLevelLow;
1237 }
1238 }
1239
1240 @Override
1241 public int getInvalidCharger() {
1242 synchronized (mLock) {
1243 return mInvalidCharger;
1244 }
1245 }
1246 }
Yifan Hong98852792017-10-12 11:35:14 -07001247
1248 /**
1249 * HealthServiceWrapper wraps the internal IHealth service and refreshes the service when
1250 * necessary.
1251 *
1252 * On new registration of IHealth service, {@link #onRegistration onRegistration} is called and
1253 * the internal service is refreshed.
1254 * On death of an existing IHealth service, the internal service is NOT cleared to avoid
1255 * race condition between death notification and new service notification. Hence,
1256 * a caller must check for transaction errors when calling into the service.
1257 *
1258 * @hide Should only be used internally.
1259 */
1260 @VisibleForTesting
1261 static final class HealthServiceWrapper {
1262 private static final String TAG = "HealthServiceWrapper";
1263 public static final String INSTANCE_HEALTHD = "backup";
1264 public static final String INSTANCE_VENDOR = "default";
1265 // All interesting instances, sorted by priority high -> low.
1266 private static final List<String> sAllInstances =
1267 Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
1268
1269 private final IServiceNotification mNotification = new Notification();
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001270 private final HandlerThread mHandlerThread = new HandlerThread("HealthServiceRefresh");
Yifan Hong1fff9842017-10-27 13:53:10 -07001271 // These variables are fixed after init.
Yifan Hong98852792017-10-12 11:35:14 -07001272 private Callback mCallback;
1273 private IHealthSupplier mHealthSupplier;
Yifan Hong1fff9842017-10-27 13:53:10 -07001274 private String mInstanceName;
Yifan Hong98852792017-10-12 11:35:14 -07001275
Yifan Hong89d55c12017-10-11 11:29:01 -07001276 // Last IHealth service received.
Yifan Hong89d55c12017-10-11 11:29:01 -07001277 private final AtomicReference<IHealth> mLastService = new AtomicReference<>();
1278
Yifan Hong98852792017-10-12 11:35:14 -07001279 /**
1280 * init should be called after constructor. For testing purposes, init is not called by
1281 * constructor.
1282 */
1283 HealthServiceWrapper() {
1284 }
1285
Yifan Hong1fd86f4c2017-10-09 16:50:33 -07001286 IHealth getLastService() {
1287 return mLastService.get();
1288 }
1289
Yifan Hong98852792017-10-12 11:35:14 -07001290 /**
1291 * Start monitoring registration of new IHealth services. Only instances that are in
1292 * {@code sAllInstances} and in device / framework manifest are used. This function should
1293 * only be called once.
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001294 *
1295 * mCallback.onRegistration() is called synchronously (aka in init thread) before
1296 * this method returns.
1297 *
Yifan Hong98852792017-10-12 11:35:14 -07001298 * @throws RemoteException transaction error when talking to IServiceManager
1299 * @throws NoSuchElementException if one of the following cases:
1300 * - No service manager;
1301 * - none of {@code sAllInstances} are in manifests (i.e. not
1302 * available on this device), or none of these instances are available to current
1303 * process.
1304 * @throws NullPointerException when callback is null or supplier is null
1305 */
1306 void init(Callback callback,
1307 IServiceManagerSupplier managerSupplier,
1308 IHealthSupplier healthSupplier)
1309 throws RemoteException, NoSuchElementException, NullPointerException {
1310 if (callback == null || managerSupplier == null || healthSupplier == null)
1311 throw new NullPointerException();
1312
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001313 IServiceManager manager;
1314
Yifan Hong98852792017-10-12 11:35:14 -07001315 mCallback = callback;
1316 mHealthSupplier = healthSupplier;
1317
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001318 // Initialize mLastService and call callback for the first time (in init thread)
1319 IHealth newService = null;
Yifan Hong98852792017-10-12 11:35:14 -07001320 for (String name : sAllInstances) {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001321 traceBegin("HealthInitGetService_" + name);
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001322 try {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001323 newService = healthSupplier.get(name);
1324 } catch (NoSuchElementException ex) {
1325 /* ignored, handled below */
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001326 } finally {
1327 traceEnd();
Yifan Hong98852792017-10-12 11:35:14 -07001328 }
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001329 if (newService != null) {
1330 mInstanceName = name;
1331 mLastService.set(newService);
1332 break;
1333 }
Yifan Hong98852792017-10-12 11:35:14 -07001334 }
1335
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001336 if (mInstanceName == null || newService == null) {
Yifan Hong1fff9842017-10-27 13:53:10 -07001337 throw new NoSuchElementException(String.format(
1338 "No IHealth service instance among %s is available. Perhaps no permission?",
1339 sAllInstances.toString()));
1340 }
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001341 mCallback.onRegistration(null, newService, mInstanceName);
Yifan Hong1fff9842017-10-27 13:53:10 -07001342
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001343 // Register for future service registrations
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001344 traceBegin("HealthInitRegisterNotification");
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001345 mHandlerThread.start();
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001346 try {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001347 managerSupplier.get().registerForNotifications(
1348 IHealth.kInterfaceName, mInstanceName, mNotification);
Yifan Hong8cc18ef2017-10-31 12:27:47 -07001349 } finally {
1350 traceEnd();
1351 }
Yifan Hong1fff9842017-10-27 13:53:10 -07001352 Slog.i(TAG, "health: HealthServiceWrapper listening to instance " + mInstanceName);
Yifan Hong98852792017-10-12 11:35:14 -07001353 }
1354
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001355 @VisibleForTesting
1356 HandlerThread getHandlerThread() {
1357 return mHandlerThread;
1358 }
1359
Yifan Hong98852792017-10-12 11:35:14 -07001360 interface Callback {
1361 /**
1362 * This function is invoked asynchronously when a new and related IServiceNotification
1363 * is received.
1364 * @param service the recently retrieved service from IServiceManager.
1365 * Can be a dead service before service notification of a new service is delivered.
1366 * Implementation must handle cases for {@link RemoteException}s when calling
1367 * into service.
1368 * @param instance instance name.
1369 */
Yifan Hong89d55c12017-10-11 11:29:01 -07001370 void onRegistration(IHealth oldService, IHealth newService, String instance);
Yifan Hong98852792017-10-12 11:35:14 -07001371 }
1372
1373 /**
1374 * Supplier of services.
1375 * Must not return null; throw {@link NoSuchElementException} if a service is not available.
1376 */
1377 interface IServiceManagerSupplier {
Yifan Hong89d55c12017-10-11 11:29:01 -07001378 default IServiceManager get() throws NoSuchElementException, RemoteException {
1379 return IServiceManager.getService();
1380 }
Yifan Hong98852792017-10-12 11:35:14 -07001381 }
1382 /**
1383 * Supplier of services.
1384 * Must not return null; throw {@link NoSuchElementException} if a service is not available.
1385 */
1386 interface IHealthSupplier {
Yifan Hong89d55c12017-10-11 11:29:01 -07001387 default IHealth get(String name) throws NoSuchElementException, RemoteException {
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001388 return IHealth.getService(name, true /* retry */);
Yifan Hong89d55c12017-10-11 11:29:01 -07001389 }
Yifan Hong98852792017-10-12 11:35:14 -07001390 }
1391
1392 private class Notification extends IServiceNotification.Stub {
1393 @Override
1394 public final void onRegistration(String interfaceName, String instanceName,
1395 boolean preexisting) {
1396 if (!IHealth.kInterfaceName.equals(interfaceName)) return;
Yifan Hong1fff9842017-10-27 13:53:10 -07001397 if (!mInstanceName.equals(instanceName)) return;
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001398
1399 // This runnable only runs on mHandlerThread and ordering is ensured, hence
1400 // no locking is needed inside the runnable.
1401 mHandlerThread.getThreadHandler().post(new Runnable() {
1402 @Override
1403 public void run() {
1404 try {
1405 IHealth newService = mHealthSupplier.get(mInstanceName);
1406 IHealth oldService = mLastService.getAndSet(newService);
1407
1408 // preexisting may be inaccurate (race). Check for equality here.
1409 if (Objects.equals(newService, oldService)) return;
1410
1411 Slog.i(TAG, "health: new instance registered " + mInstanceName);
1412 mCallback.onRegistration(oldService, newService, mInstanceName);
1413 } catch (NoSuchElementException | RemoteException ex) {
1414 Slog.e(TAG, "health: Cannot get instance '" + mInstanceName
1415 + "': " + ex.getMessage() + ". Perhaps no permission?");
1416 }
Yifan Hong89d55c12017-10-11 11:29:01 -07001417 }
Yifan Hongcf9a8b22017-11-02 18:43:06 -07001418 });
Yifan Hong98852792017-10-12 11:35:14 -07001419 }
1420 }
1421 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001422}