1 /* 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 17 package com.android.server; 18 19 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent; 20 import static com.android.server.health.Utils.copyV1Battery; 21 22 import android.annotation.Nullable; 23 import android.app.ActivityManager; 24 import android.app.ActivityManagerInternal; 25 import android.app.AppOpsManager; 26 import android.app.BroadcastOptions; 27 import android.content.ContentResolver; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.IntentFilter; 31 import android.database.ContentObserver; 32 import android.hardware.health.HealthInfo; 33 import android.hardware.health.V2_1.BatteryCapacityLevel; 34 import android.metrics.LogMaker; 35 import android.os.BatteryManager; 36 import android.os.BatteryManagerInternal; 37 import android.os.BatteryProperty; 38 import android.os.BatteryStats; 39 import android.os.Binder; 40 import android.os.Build; 41 import android.os.Bundle; 42 import android.os.DropBoxManager; 43 import android.os.FileUtils; 44 import android.os.Handler; 45 import android.os.IBatteryPropertiesRegistrar; 46 import android.os.IBinder; 47 import android.os.OsProtoEnums; 48 import android.os.PowerManager; 49 import android.os.RemoteException; 50 import android.os.ResultReceiver; 51 import android.os.ServiceManager; 52 import android.os.ShellCallback; 53 import android.os.ShellCommand; 54 import android.os.SystemClock; 55 import android.os.SystemProperties; 56 import android.os.Trace; 57 import android.os.UEventObserver; 58 import android.os.UserHandle; 59 import android.provider.Settings; 60 import android.service.battery.BatteryServiceDumpProto; 61 import android.sysprop.PowerProperties; 62 import android.util.EventLog; 63 import android.util.Slog; 64 import android.util.proto.ProtoOutputStream; 65 66 import com.android.internal.app.IBatteryStats; 67 import com.android.internal.logging.MetricsLogger; 68 import com.android.internal.util.DumpUtils; 69 import com.android.server.am.BatteryStatsService; 70 import com.android.server.health.HealthServiceWrapper; 71 import com.android.server.lights.LightsManager; 72 import com.android.server.lights.LogicalLight; 73 74 import java.io.File; 75 import java.io.FileDescriptor; 76 import java.io.FileOutputStream; 77 import java.io.IOException; 78 import java.io.PrintWriter; 79 import java.util.ArrayDeque; 80 import java.util.ArrayList; 81 import java.util.NoSuchElementException; 82 83 /** 84 * <p>BatteryService monitors the charging status, and charge level of the device 85 * battery. When these values change this service broadcasts the new values 86 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are 87 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED 88 * BATTERY_CHANGED} action.</p> 89 * <p>The new values are stored in the Intent data and can be retrieved by 90 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the 91 * following keys:</p> 92 * <p>"scale" - int, the maximum value for the charge level</p> 93 * <p>"level" - int, charge level, from 0 through "scale" inclusive</p> 94 * <p>"status" - String, the current charging status.<br /> 95 * <p>"health" - String, the current battery health.<br /> 96 * <p>"present" - boolean, true if the battery is present<br /> 97 * <p>"icon-small" - int, suggested small icon to use for this state</p> 98 * <p>"plugged" - int, 0 if the device is not plugged in; 1 if plugged 99 * into an AC power adapter; 2 if plugged in via USB.</p> 100 * <p>"voltage" - int, current battery voltage in millivolts</p> 101 * <p>"temperature" - int, current battery temperature in tenths of 102 * a degree Centigrade</p> 103 * <p>"technology" - String, the type of battery installed, e.g. "Li-ion"</p> 104 * 105 * <p> 106 * The battery service may be called by the power manager while holding its locks so 107 * we take care to post all outcalls into the activity manager to a handler. 108 * 109 * FIXME: Ideally the power manager would perform all of its calls into the battery 110 * service asynchronously itself. 111 * </p> 112 */ 113 public final class BatteryService extends SystemService { 114 private static final String TAG = BatteryService.class.getSimpleName(); 115 116 private static final boolean DEBUG = false; 117 118 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage 119 120 private static final long HEALTH_HAL_WAIT_MS = 1000; 121 private static final long BATTERY_LEVEL_CHANGE_THROTTLE_MS = 60_000; 122 private static final int MAX_BATTERY_LEVELS_QUEUE_SIZE = 100; 123 124 // Used locally for determining when to make a last ditch effort to log 125 // discharge stats before the device dies. 126 private int mCriticalBatteryLevel; 127 128 // TODO: Current args don't work since "--unplugged" flag was purposefully removed. 129 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" }; 130 131 private static final String DUMPSYS_DATA_PATH = "/data/system/"; 132 133 // This should probably be exposed in the API, though it's not critical 134 private static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0 135 136 private final Context mContext; 137 private final IBatteryStats mBatteryStats; 138 BinderService mBinderService; 139 private final Handler mHandler; 140 141 private final Object mLock = new Object(); 142 143 private HealthInfo mHealthInfo; 144 private final HealthInfo mLastHealthInfo = new HealthInfo(); 145 private boolean mBatteryLevelCritical; 146 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; 153 private int mLastMaxChargingCurrent; 154 private int mLastMaxChargingVoltage; 155 private int mLastChargeCounter; 156 private int mLastBatteryCycleCount; 157 private int mLastCharingState; 158 159 private int mSequence = 1; 160 161 private int mInvalidCharger; 162 private int mLastInvalidCharger; 163 164 private int mLowBatteryWarningLevel; 165 private int mLastLowBatteryWarningLevel; 166 private int mLowBatteryCloseWarningLevel; 167 private int mBatteryNearlyFullLevel; 168 private int mShutdownBatteryTemperature; 169 170 private static String sSystemUiPackage; 171 172 private int mPlugType; 173 private int mLastPlugType = -1; // Extra state so we can detect first run 174 175 private boolean mBatteryLevelLow; 176 177 private long mDischargeStartTime; 178 private int mDischargeStartLevel; 179 180 private long mChargeStartTime; 181 private int mChargeStartLevel; 182 183 private boolean mUpdatesStopped; 184 private boolean mBatteryInputSuspended; 185 186 private Led mLed; 187 188 private boolean mSentLowBatteryBroadcast = false; 189 190 private ActivityManagerInternal mActivityManagerInternal; 191 192 private HealthServiceWrapper mHealthServiceWrapper; 193 private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar; 194 private ArrayDeque<Bundle> mBatteryLevelsEventQueue; 195 private long mLastBatteryLevelChangedSentMs; 196 197 private Bundle mBatteryChangedOptions = BroadcastOptions.makeBasic() 198 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 199 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 200 .toBundle(); 201 /** Used for both connected/disconnected, so match using key */ 202 private Bundle mPowerOptions = BroadcastOptions.makeBasic() 203 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 204 .setDeliveryGroupMatchingKey("android", Intent.ACTION_POWER_CONNECTED) 205 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 206 .toBundle(); 207 /** Used for both low/okay, so match using key */ 208 private Bundle mBatteryOptions = BroadcastOptions.makeBasic() 209 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 210 .setDeliveryGroupMatchingKey("android", Intent.ACTION_BATTERY_OKAY) 211 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 212 .toBundle(); 213 214 private MetricsLogger mMetricsLogger; 215 BatteryService(Context context)216 public BatteryService(Context context) { 217 super(context); 218 219 mContext = context; 220 mHandler = new Handler(true /*async*/); 221 mLed = new Led(context, getLocalService(LightsManager.class)); 222 mBatteryStats = BatteryStatsService.getService(); 223 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 224 225 mCriticalBatteryLevel = mContext.getResources().getInteger( 226 com.android.internal.R.integer.config_criticalBatteryWarningLevel); 227 mLowBatteryWarningLevel = mContext.getResources().getInteger( 228 com.android.internal.R.integer.config_lowBatteryWarningLevel); 229 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger( 230 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 231 mShutdownBatteryTemperature = mContext.getResources().getInteger( 232 com.android.internal.R.integer.config_shutdownBatteryTemperature); 233 sSystemUiPackage = mContext.getResources().getString( 234 com.android.internal.R.string.config_systemUi); 235 236 mBatteryLevelsEventQueue = new ArrayDeque<>(); 237 mMetricsLogger = new MetricsLogger(); 238 239 // watch for invalid charger messages if the invalid_charger switch exists 240 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) { 241 UEventObserver invalidChargerObserver = new UEventObserver() { 242 @Override 243 public void onUEvent(UEvent event) { 244 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0; 245 synchronized (mLock) { 246 if (mInvalidCharger != invalidCharger) { 247 mInvalidCharger = invalidCharger; 248 } 249 } 250 } 251 }; 252 invalidChargerObserver.startObserving( 253 "DEVPATH=/devices/virtual/switch/invalid_charger"); 254 } 255 256 mBatteryInputSuspended = PowerProperties.battery_input_suspended().orElse(false); 257 } 258 259 @Override onStart()260 public void onStart() { 261 registerHealthCallback(); 262 263 mBinderService = new BinderService(); 264 publishBinderService("battery", mBinderService); 265 mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(); 266 publishBinderService("batteryproperties", mBatteryPropertiesRegistrar); 267 publishLocalService(BatteryManagerInternal.class, new LocalService()); 268 } 269 270 @Override onBootPhase(int phase)271 public void onBootPhase(int phase) { 272 if (phase == PHASE_ACTIVITY_MANAGER_READY) { 273 // check our power situation now that it is safe to display the shutdown dialog. 274 synchronized (mLock) { 275 ContentObserver obs = new ContentObserver(mHandler) { 276 @Override 277 public void onChange(boolean selfChange) { 278 synchronized (mLock) { 279 updateBatteryWarningLevelLocked(); 280 } 281 } 282 }; 283 final ContentResolver resolver = mContext.getContentResolver(); 284 resolver.registerContentObserver(Settings.Global.getUriFor( 285 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), 286 false, obs, UserHandle.USER_ALL); 287 updateBatteryWarningLevelLocked(); 288 } 289 } 290 } 291 registerHealthCallback()292 private void registerHealthCallback() { 293 traceBegin("HealthInitWrapper"); 294 // IHealth is lazily retrieved. 295 try { 296 mHealthServiceWrapper = HealthServiceWrapper.create(this::update); 297 } catch (RemoteException ex) { 298 Slog.e(TAG, "health: cannot register callback. (RemoteException)"); 299 throw ex.rethrowFromSystemServer(); 300 } catch (NoSuchElementException ex) { 301 Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)"); 302 throw ex; 303 } finally { 304 traceEnd(); 305 } 306 307 traceBegin("HealthInitWaitUpdate"); 308 // init register for new service notifications, and IServiceManager should return the 309 // existing service in a near future. Wait for this.update() to instantiate 310 // the initial mHealthInfo. 311 long beforeWait = SystemClock.uptimeMillis(); 312 synchronized (mLock) { 313 while (mHealthInfo == null) { 314 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) + 315 "ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms..."); 316 try { 317 mLock.wait(HEALTH_HAL_WAIT_MS); 318 } catch (InterruptedException ex) { 319 Slog.i(TAG, "health: InterruptedException when waiting for update. " 320 + " Continuing..."); 321 } 322 } 323 } 324 325 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) 326 + "ms and received the update."); 327 traceEnd(); 328 } 329 updateBatteryWarningLevelLocked()330 private void updateBatteryWarningLevelLocked() { 331 final ContentResolver resolver = mContext.getContentResolver(); 332 int defWarnLevel = mContext.getResources().getInteger( 333 com.android.internal.R.integer.config_lowBatteryWarningLevel); 334 mLastLowBatteryWarningLevel = mLowBatteryWarningLevel; 335 mLowBatteryWarningLevel = Settings.Global.getInt(resolver, 336 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); 337 if (mLowBatteryWarningLevel == 0) { 338 mLowBatteryWarningLevel = defWarnLevel; 339 } 340 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) { 341 mLowBatteryWarningLevel = mCriticalBatteryLevel; 342 } 343 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger( 344 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 345 processValuesLocked(true); 346 } 347 isPoweredLocked(int plugTypeSet)348 private boolean isPoweredLocked(int plugTypeSet) { 349 // assume we are powered if battery state is unknown so 350 // the "stay on while plugged in" option will work. 351 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { 352 return true; 353 } 354 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 355 && mHealthInfo.chargerAcOnline) { 356 return true; 357 } 358 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 359 && mHealthInfo.chargerUsbOnline) { 360 return true; 361 } 362 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 363 && mHealthInfo.chargerWirelessOnline) { 364 return true; 365 } 366 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_DOCK) != 0 367 && mHealthInfo.chargerDockOnline) { 368 return true; 369 } 370 return false; 371 } 372 shouldSendBatteryLowLocked()373 private boolean shouldSendBatteryLowLocked() { 374 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE; 375 final boolean oldPlugged = mLastPlugType != BATTERY_PLUGGED_NONE; 376 377 /* The ACTION_BATTERY_LOW broadcast is sent in these situations: 378 * - is just un-plugged (previously was plugged) and battery level is 379 * less than or equal to WARNING, or 380 * - is not plugged and battery level falls to WARNING boundary 381 * (becomes <= mLowBatteryWarningLevel). 382 */ 383 return !plugged 384 && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 385 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel 386 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel 387 || mHealthInfo.batteryLevel > mLastLowBatteryWarningLevel); 388 } 389 shouldShutdownLocked()390 private boolean shouldShutdownLocked() { 391 if (mHealthInfo.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) { 392 return (mHealthInfo.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL); 393 } 394 if (mHealthInfo.batteryLevel > 0) { 395 return false; 396 } 397 398 // Battery-less devices should not shutdown. 399 if (!mHealthInfo.batteryPresent) { 400 return false; 401 } 402 403 // If battery state is not CHARGING, shutdown. 404 // - If battery present and state == unknown, this is an unexpected error state. 405 // - If level <= 0 and state == full, this is also an unexpected state 406 // - All other states (NOT_CHARGING, DISCHARGING) means it is not charging. 407 return mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING; 408 } 409 shutdownIfNoPowerLocked()410 private void shutdownIfNoPowerLocked() { 411 // shut down gracefully if our battery is critically low and we are not powered. 412 // wait until the system has booted before attempting to display the shutdown dialog. 413 if (shouldShutdownLocked()) { 414 mHandler.post(new Runnable() { 415 @Override 416 public void run() { 417 if (mActivityManagerInternal.isSystemReady()) { 418 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 419 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); 420 intent.putExtra(Intent.EXTRA_REASON, 421 PowerManager.SHUTDOWN_LOW_BATTERY); 422 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 423 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 424 } 425 } 426 }); 427 } 428 } 429 shutdownIfOverTempLocked()430 private void shutdownIfOverTempLocked() { 431 // shut down gracefully if temperature is too high (> 68.0C by default) 432 // wait until the system has booted before attempting to display the 433 // shutdown dialog. 434 if (mHealthInfo.batteryTemperatureTenthsCelsius > mShutdownBatteryTemperature) { 435 mHandler.post(new Runnable() { 436 @Override 437 public void run() { 438 if (mActivityManagerInternal.isSystemReady()) { 439 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 440 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); 441 intent.putExtra(Intent.EXTRA_REASON, 442 PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE); 443 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 444 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 445 } 446 } 447 }); 448 } 449 } 450 update(android.hardware.health.HealthInfo info)451 private void update(android.hardware.health.HealthInfo info) { 452 traceBegin("HealthInfoUpdate"); 453 454 Trace.traceCounter( 455 Trace.TRACE_TAG_POWER, "BatteryChargeCounter", info.batteryChargeCounterUah); 456 Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", info.batteryCurrentMicroamps); 457 Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", plugType(info)); 458 Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", info.batteryStatus); 459 460 synchronized (mLock) { 461 if (!mUpdatesStopped) { 462 mHealthInfo = info; 463 // Process the new values. 464 processValuesLocked(false); 465 mLock.notifyAll(); // for any waiters on new info 466 } else { 467 copyV1Battery(mLastHealthInfo, info); 468 } 469 } 470 traceEnd(); 471 } 472 plugType(HealthInfo healthInfo)473 private static int plugType(HealthInfo healthInfo) { 474 if (healthInfo.chargerAcOnline) { 475 return BatteryManager.BATTERY_PLUGGED_AC; 476 } else if (healthInfo.chargerUsbOnline) { 477 return BatteryManager.BATTERY_PLUGGED_USB; 478 } else if (healthInfo.chargerWirelessOnline) { 479 return BatteryManager.BATTERY_PLUGGED_WIRELESS; 480 } else if (healthInfo.chargerDockOnline) { 481 return BatteryManager.BATTERY_PLUGGED_DOCK; 482 } else { 483 return BATTERY_PLUGGED_NONE; 484 } 485 } 486 processValuesLocked(boolean force)487 private void processValuesLocked(boolean force) { 488 boolean logOutlier = false; 489 long dischargeDuration = 0; 490 491 mBatteryLevelCritical = 492 mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 493 && mHealthInfo.batteryLevel <= mCriticalBatteryLevel; 494 mPlugType = plugType(mHealthInfo); 495 496 if (DEBUG) { 497 Slog.d(TAG, "Processing new values: " 498 + "info=" + mHealthInfo 499 + ", mBatteryLevelCritical=" + mBatteryLevelCritical 500 + ", mPlugType=" + mPlugType); 501 } 502 503 // Let the battery stats keep track of the current level. 504 try { 505 mBatteryStats.setBatteryState( 506 mHealthInfo.batteryStatus, 507 mHealthInfo.batteryHealth, 508 mPlugType, 509 mHealthInfo.batteryLevel, 510 mHealthInfo.batteryTemperatureTenthsCelsius, 511 mHealthInfo.batteryVoltageMillivolts, 512 mHealthInfo.batteryChargeCounterUah, 513 mHealthInfo.batteryFullChargeUah, 514 mHealthInfo.batteryChargeTimeToFullNowSeconds); 515 } catch (RemoteException e) { 516 // Should never happen. 517 } 518 519 shutdownIfNoPowerLocked(); 520 shutdownIfOverTempLocked(); 521 522 if (force 523 || (mHealthInfo.batteryStatus != mLastBatteryStatus 524 || mHealthInfo.batteryHealth != mLastBatteryHealth 525 || mHealthInfo.batteryPresent != mLastBatteryPresent 526 || mHealthInfo.batteryLevel != mLastBatteryLevel 527 || mPlugType != mLastPlugType 528 || mHealthInfo.batteryVoltageMillivolts != mLastBatteryVoltage 529 || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBatteryTemperature 530 || mHealthInfo.maxChargingCurrentMicroamps != mLastMaxChargingCurrent 531 || mHealthInfo.maxChargingVoltageMicrovolts != mLastMaxChargingVoltage 532 || mHealthInfo.batteryChargeCounterUah != mLastChargeCounter 533 || mInvalidCharger != mLastInvalidCharger 534 || mHealthInfo.batteryCycleCount != mLastBatteryCycleCount 535 || mHealthInfo.chargingState != mLastCharingState)) { 536 537 if (mPlugType != mLastPlugType) { 538 if (mLastPlugType == BATTERY_PLUGGED_NONE) { 539 // discharging -> charging 540 mChargeStartLevel = mHealthInfo.batteryLevel; 541 mChargeStartTime = SystemClock.elapsedRealtime(); 542 543 final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE); 544 builder.setType(MetricsEvent.TYPE_ACTION); 545 builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mPlugType); 546 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START, 547 mHealthInfo.batteryLevel); 548 mMetricsLogger.write(builder); 549 550 // There's no value in this data unless we've discharged at least once and the 551 // battery level has changed; so don't log until it does. 552 if (mDischargeStartTime != 0 && mDischargeStartLevel != mHealthInfo.batteryLevel) { 553 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; 554 logOutlier = true; 555 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration, 556 mDischargeStartLevel, mHealthInfo.batteryLevel); 557 // make sure we see a discharge event before logging again 558 mDischargeStartTime = 0; 559 } 560 } else if (mPlugType == BATTERY_PLUGGED_NONE) { 561 // charging -> discharging or we just powered up 562 mDischargeStartTime = SystemClock.elapsedRealtime(); 563 mDischargeStartLevel = mHealthInfo.batteryLevel; 564 565 long chargeDuration = SystemClock.elapsedRealtime() - mChargeStartTime; 566 if (mChargeStartTime != 0 && chargeDuration != 0) { 567 final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE); 568 builder.setType(MetricsEvent.TYPE_DISMISS); 569 builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastPlugType); 570 builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS, 571 chargeDuration); 572 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START, 573 mChargeStartLevel); 574 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_END, 575 mHealthInfo.batteryLevel); 576 mMetricsLogger.write(builder); 577 } 578 mChargeStartTime = 0; 579 } 580 } 581 if (mHealthInfo.batteryStatus != mLastBatteryStatus || 582 mHealthInfo.batteryHealth != mLastBatteryHealth || 583 mHealthInfo.batteryPresent != mLastBatteryPresent || 584 mPlugType != mLastPlugType) { 585 EventLog.writeEvent(EventLogTags.BATTERY_STATUS, 586 mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, mHealthInfo.batteryPresent ? 1 : 0, 587 mPlugType, mHealthInfo.batteryTechnology); 588 SystemProperties.set( 589 "debug.tracing.battery_status", 590 Integer.toString(mHealthInfo.batteryStatus)); 591 SystemProperties.set("debug.tracing.plug_type", Integer.toString(mPlugType)); 592 } 593 if (mHealthInfo.batteryLevel != mLastBatteryLevel) { 594 // Don't do this just from voltage or temperature changes, that is 595 // too noisy. 596 EventLog.writeEvent( 597 EventLogTags.BATTERY_LEVEL, 598 mHealthInfo.batteryLevel, 599 mHealthInfo.batteryVoltageMillivolts, 600 mHealthInfo.batteryTemperatureTenthsCelsius); 601 } 602 if (mBatteryLevelCritical && !mLastBatteryLevelCritical && 603 mPlugType == BATTERY_PLUGGED_NONE) { 604 // We want to make sure we log discharge cycle outliers 605 // if the battery is about to die. 606 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; 607 logOutlier = true; 608 } 609 610 if (!mBatteryLevelLow) { 611 // Should we now switch in to low battery mode? 612 if (mPlugType == BATTERY_PLUGGED_NONE 613 && mHealthInfo.batteryStatus != 614 BatteryManager.BATTERY_STATUS_UNKNOWN 615 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) { 616 mBatteryLevelLow = true; 617 } 618 } else { 619 // Should we now switch out of low battery mode? 620 if (mPlugType != BATTERY_PLUGGED_NONE) { 621 mBatteryLevelLow = false; 622 } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) { 623 mBatteryLevelLow = false; 624 } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) { 625 // If being forced, the previous state doesn't matter, we will just 626 // absolutely check to see if we are now above the warning level. 627 mBatteryLevelLow = false; 628 } 629 } 630 631 mSequence++; 632 633 // Separate broadcast is sent for power connected / not connected 634 // since the standard intent will not wake any applications and some 635 // applications may want to have smart behavior based on this. 636 if (mPlugType != 0 && mLastPlugType == 0) { 637 final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED); 638 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 639 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 640 mHandler.post(new Runnable() { 641 @Override 642 public void run() { 643 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 644 mPowerOptions); 645 } 646 }); 647 } 648 else if (mPlugType == 0 && mLastPlugType != 0) { 649 final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED); 650 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 651 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 652 mHandler.post(new Runnable() { 653 @Override 654 public void run() { 655 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 656 mPowerOptions); 657 } 658 }); 659 } 660 661 if (shouldSendBatteryLowLocked()) { 662 mSentLowBatteryBroadcast = true; 663 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW); 664 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 665 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 666 mHandler.post(new Runnable() { 667 @Override 668 public void run() { 669 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 670 mBatteryOptions); 671 } 672 }); 673 } else if (mSentLowBatteryBroadcast && 674 mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) { 675 mSentLowBatteryBroadcast = false; 676 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY); 677 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 678 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 679 mHandler.post(new Runnable() { 680 @Override 681 public void run() { 682 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 683 mBatteryOptions); 684 } 685 }); 686 } 687 688 // We are doing this after sending the above broadcasts, so anything processing 689 // them will get the new sequence number at that point. (See for example how testing 690 // of JobScheduler's BatteryController works.) 691 sendBatteryChangedIntentLocked(); 692 if (mLastBatteryLevel != mHealthInfo.batteryLevel || mLastPlugType != mPlugType) { 693 sendBatteryLevelChangedIntentLocked(); 694 } 695 696 697 // Update the battery LED 698 mLed.updateLightsLocked(); 699 700 // This needs to be done after sendIntent() so that we get the lastest battery stats. 701 if (logOutlier && dischargeDuration != 0) { 702 logOutlierLocked(dischargeDuration); 703 } 704 705 mLastBatteryStatus = mHealthInfo.batteryStatus; 706 mLastBatteryHealth = mHealthInfo.batteryHealth; 707 mLastBatteryPresent = mHealthInfo.batteryPresent; 708 mLastBatteryLevel = mHealthInfo.batteryLevel; 709 mLastPlugType = mPlugType; 710 mLastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts; 711 mLastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius; 712 mLastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps; 713 mLastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts; 714 mLastChargeCounter = mHealthInfo.batteryChargeCounterUah; 715 mLastBatteryLevelCritical = mBatteryLevelCritical; 716 mLastInvalidCharger = mInvalidCharger; 717 mLastBatteryCycleCount = mHealthInfo.batteryCycleCount; 718 mLastCharingState = mHealthInfo.chargingState; 719 } 720 } 721 sendBatteryChangedIntentLocked()722 private void sendBatteryChangedIntentLocked() { 723 // Pack up the values and broadcast them to everyone 724 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); 725 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY 726 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 727 728 int icon = getIconLocked(mHealthInfo.batteryLevel); 729 730 intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 731 intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus); 732 intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth); 733 intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent); 734 intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel); 735 intent.putExtra(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast); 736 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); 737 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon); 738 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType); 739 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts); 740 intent.putExtra( 741 BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius); 742 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology); 743 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger); 744 intent.putExtra( 745 BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrentMicroamps); 746 intent.putExtra( 747 BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, 748 mHealthInfo.maxChargingVoltageMicrovolts); 749 intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); 750 intent.putExtra(BatteryManager.EXTRA_CYCLE_COUNT, mHealthInfo.batteryCycleCount); 751 intent.putExtra(BatteryManager.EXTRA_CHARGING_STATUS, mHealthInfo.chargingState); 752 if (DEBUG) { 753 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE 754 + ", info:" + mHealthInfo.toString()); 755 } 756 757 mHandler.post(() -> broadcastBatteryChangedIntent(intent, mBatteryChangedOptions)); 758 } 759 broadcastBatteryChangedIntent(Intent intent, Bundle options)760 private static void broadcastBatteryChangedIntent(Intent intent, Bundle options) { 761 // TODO (293959093): It is important that SystemUI receives this broadcast as soon as 762 // possible. Ideally, it should be using binder callbacks but until then, dispatch this 763 // as a foreground broadcast to SystemUI. 764 final Intent fgIntent = new Intent(intent); 765 fgIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 766 fgIntent.setPackage(sSystemUiPackage); 767 ActivityManager.broadcastStickyIntent(fgIntent, AppOpsManager.OP_NONE, 768 options, UserHandle.USER_ALL); 769 770 ActivityManager.broadcastStickyIntent(intent, new String[] {sSystemUiPackage}, 771 AppOpsManager.OP_NONE, options, UserHandle.USER_ALL); 772 } 773 sendBatteryLevelChangedIntentLocked()774 private void sendBatteryLevelChangedIntentLocked() { 775 Bundle event = new Bundle(); 776 long now = SystemClock.elapsedRealtime(); 777 event.putInt(BatteryManager.EXTRA_SEQUENCE, mSequence); 778 event.putInt(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus); 779 event.putInt(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth); 780 event.putBoolean(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent); 781 event.putInt(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel); 782 event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast); 783 event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); 784 event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType); 785 event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts); 786 event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius); 787 event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); 788 event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now); 789 event.putInt(BatteryManager.EXTRA_CYCLE_COUNT, mHealthInfo.batteryCycleCount); 790 event.putInt(BatteryManager.EXTRA_CHARGING_STATUS, mHealthInfo.chargingState); 791 792 boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty(); 793 mBatteryLevelsEventQueue.add(event); 794 // Make sure queue is bounded and doesn't exceed intent payload limits 795 if (mBatteryLevelsEventQueue.size() > MAX_BATTERY_LEVELS_QUEUE_SIZE) { 796 mBatteryLevelsEventQueue.removeFirst(); 797 } 798 799 if (queueWasEmpty) { 800 // send now if last event was before throttle interval, otherwise delay 801 long delay = now - mLastBatteryLevelChangedSentMs > BATTERY_LEVEL_CHANGE_THROTTLE_MS 802 ? 0 : mLastBatteryLevelChangedSentMs + BATTERY_LEVEL_CHANGE_THROTTLE_MS - now; 803 mHandler.postDelayed(this::sendEnqueuedBatteryLevelChangedEvents, delay); 804 } 805 } 806 sendEnqueuedBatteryLevelChangedEvents()807 private void sendEnqueuedBatteryLevelChangedEvents() { 808 ArrayList<Bundle> events; 809 synchronized (mLock) { 810 events = new ArrayList<>(mBatteryLevelsEventQueue); 811 mBatteryLevelsEventQueue.clear(); 812 } 813 final Intent intent = new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED); 814 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 815 intent.putParcelableArrayListExtra(BatteryManager.EXTRA_EVENTS, events); 816 817 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 818 android.Manifest.permission.BATTERY_STATS); 819 mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime(); 820 } 821 822 // TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed. logBatteryStatsLocked()823 private void logBatteryStatsLocked() { 824 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME); 825 if (batteryInfoService == null) return; 826 827 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); 828 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return; 829 830 File dumpFile = null; 831 FileOutputStream dumpStream = null; 832 try { 833 // dump the service to a file 834 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump"); 835 dumpStream = new FileOutputStream(dumpFile); 836 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS); 837 FileUtils.sync(dumpStream); 838 839 // add dump file to drop box 840 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT); 841 } catch (RemoteException e) { 842 Slog.e(TAG, "failed to dump battery service", e); 843 } catch (IOException e) { 844 Slog.e(TAG, "failed to write dumpsys file", e); 845 } finally { 846 // make sure we clean up 847 if (dumpStream != null) { 848 try { 849 dumpStream.close(); 850 } catch (IOException e) { 851 Slog.e(TAG, "failed to close dumpsys output stream"); 852 } 853 } 854 if (dumpFile != null && !dumpFile.delete()) { 855 Slog.e(TAG, "failed to delete temporary dumpsys file: " 856 + dumpFile.getAbsolutePath()); 857 } 858 } 859 } 860 logOutlierLocked(long duration)861 private void logOutlierLocked(long duration) { 862 ContentResolver cr = mContext.getContentResolver(); 863 String dischargeThresholdString = Settings.Global.getString(cr, 864 Settings.Global.BATTERY_DISCHARGE_THRESHOLD); 865 String durationThresholdString = Settings.Global.getString(cr, 866 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD); 867 868 if (dischargeThresholdString != null && durationThresholdString != null) { 869 try { 870 long durationThreshold = Long.parseLong(durationThresholdString); 871 int dischargeThreshold = Integer.parseInt(dischargeThresholdString); 872 if (duration <= durationThreshold && 873 mDischargeStartLevel - mHealthInfo.batteryLevel >= dischargeThreshold) { 874 // If the discharge cycle is bad enough we want to know about it. 875 logBatteryStatsLocked(); 876 } 877 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold + 878 " discharge threshold: " + dischargeThreshold); 879 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " + 880 (mDischargeStartLevel - mHealthInfo.batteryLevel)); 881 } catch (NumberFormatException e) { 882 Slog.e(TAG, "Invalid DischargeThresholds GService string: " + 883 durationThresholdString + " or " + dischargeThresholdString); 884 } 885 } 886 } 887 getIconLocked(int level)888 private int getIconLocked(int level) { 889 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) { 890 return com.android.internal.R.drawable.stat_sys_battery_charge; 891 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) { 892 return com.android.internal.R.drawable.stat_sys_battery; 893 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING 894 || mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) { 895 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY) 896 && mHealthInfo.batteryLevel >= 100) { 897 return com.android.internal.R.drawable.stat_sys_battery_charge; 898 } else { 899 return com.android.internal.R.drawable.stat_sys_battery; 900 } 901 } else { 902 return com.android.internal.R.drawable.stat_sys_battery_unknown; 903 } 904 } 905 906 class Shell extends ShellCommand { 907 @Override onCommand(String cmd)908 public int onCommand(String cmd) { 909 return onShellCommand(this, cmd); 910 } 911 912 @Override onHelp()913 public void onHelp() { 914 PrintWriter pw = getOutPrintWriter(); 915 dumpHelp(pw); 916 } 917 } 918 dumpHelp(PrintWriter pw)919 static void dumpHelp(PrintWriter pw) { 920 pw.println("Battery service (battery) commands:"); 921 pw.println(" help"); 922 pw.println(" Print this help text."); 923 pw.println(" get [-f] [ac|usb|wireless|dock|status|level|temp|present|counter|invalid]"); 924 pw.println(" set [-f] " 925 + "[ac|usb|wireless|dock|status|level|temp|present|counter|invalid] <value>"); 926 pw.println(" Force a battery property value, freezing battery state."); 927 pw.println(" -f: force a battery change broadcast be sent, prints new sequence."); 928 pw.println(" unplug [-f]"); 929 pw.println(" Force battery unplugged, freezing battery state."); 930 pw.println(" -f: force a battery change broadcast be sent, prints new sequence."); 931 pw.println(" reset [-f]"); 932 pw.println(" Unfreeze battery state, returning to current hardware values."); 933 pw.println(" -f: force a battery change broadcast be sent, prints new sequence."); 934 if (Build.IS_DEBUGGABLE) { 935 pw.println(" suspend_input"); 936 pw.println(" Suspend charging even if plugged in. "); 937 } 938 } 939 940 static final int OPTION_FORCE_UPDATE = 1<<0; 941 parseOptions(Shell shell)942 int parseOptions(Shell shell) { 943 String opt; 944 int opts = 0; 945 while ((opt = shell.getNextOption()) != null) { 946 if ("-f".equals(opt)) { 947 opts |= OPTION_FORCE_UPDATE; 948 } 949 } 950 return opts; 951 } 952 onShellCommand(Shell shell, String cmd)953 int onShellCommand(Shell shell, String cmd) { 954 if (cmd == null) { 955 return shell.handleDefaultCommands(cmd); 956 } 957 PrintWriter pw = shell.getOutPrintWriter(); 958 switch (cmd) { 959 case "unplug": { 960 int opts = parseOptions(shell); 961 getContext().enforceCallingOrSelfPermission( 962 android.Manifest.permission.DEVICE_POWER, null); 963 unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); 964 } break; 965 case "get": { 966 final String key = shell.getNextArg(); 967 if (key == null) { 968 pw.println("No property specified"); 969 return -1; 970 971 } 972 switch (key) { 973 case "present": 974 pw.println(mHealthInfo.batteryPresent); 975 break; 976 case "ac": 977 pw.println(mHealthInfo.chargerAcOnline); 978 break; 979 case "usb": 980 pw.println(mHealthInfo.chargerUsbOnline); 981 break; 982 case "wireless": 983 pw.println(mHealthInfo.chargerWirelessOnline); 984 break; 985 case "dock": 986 pw.println(mHealthInfo.chargerDockOnline); 987 break; 988 case "status": 989 pw.println(mHealthInfo.batteryStatus); 990 break; 991 case "level": 992 pw.println(mHealthInfo.batteryLevel); 993 break; 994 case "counter": 995 pw.println(mHealthInfo.batteryChargeCounterUah); 996 break; 997 case "temp": 998 pw.println(mHealthInfo.batteryTemperatureTenthsCelsius); 999 break; 1000 case "invalid": 1001 pw.println(mInvalidCharger); 1002 break; 1003 default: 1004 pw.println("Unknown get option: " + key); 1005 break; 1006 } 1007 } break; 1008 case "set": { 1009 int opts = parseOptions(shell); 1010 getContext().enforceCallingOrSelfPermission( 1011 android.Manifest.permission.DEVICE_POWER, null); 1012 final String key = shell.getNextArg(); 1013 if (key == null) { 1014 pw.println("No property specified"); 1015 return -1; 1016 1017 } 1018 final String value = shell.getNextArg(); 1019 if (value == null) { 1020 pw.println("No value specified"); 1021 return -1; 1022 1023 } 1024 try { 1025 if (!mUpdatesStopped) { 1026 copyV1Battery(mLastHealthInfo, mHealthInfo); 1027 } 1028 boolean update = true; 1029 switch (key) { 1030 case "present": 1031 mHealthInfo.batteryPresent = Integer.parseInt(value) != 0; 1032 break; 1033 case "ac": 1034 mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0; 1035 break; 1036 case "usb": 1037 mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0; 1038 break; 1039 case "wireless": 1040 mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0; 1041 break; 1042 case "dock": 1043 mHealthInfo.chargerDockOnline = Integer.parseInt(value) != 0; 1044 break; 1045 case "status": 1046 mHealthInfo.batteryStatus = Integer.parseInt(value); 1047 break; 1048 case "level": 1049 mHealthInfo.batteryLevel = Integer.parseInt(value); 1050 break; 1051 case "counter": 1052 mHealthInfo.batteryChargeCounterUah = Integer.parseInt(value); 1053 break; 1054 case "temp": 1055 mHealthInfo.batteryTemperatureTenthsCelsius = Integer.parseInt(value); 1056 break; 1057 case "invalid": 1058 mInvalidCharger = Integer.parseInt(value); 1059 break; 1060 default: 1061 pw.println("Unknown set option: " + key); 1062 update = false; 1063 break; 1064 } 1065 if (update) { 1066 final long ident = Binder.clearCallingIdentity(); 1067 try { 1068 mUpdatesStopped = true; 1069 processValuesLocked( 1070 /* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); 1071 } finally { 1072 Binder.restoreCallingIdentity(ident); 1073 } 1074 } 1075 } catch (NumberFormatException ex) { 1076 pw.println("Bad value: " + value); 1077 return -1; 1078 } 1079 } break; 1080 case "reset": { 1081 int opts = parseOptions(shell); 1082 getContext().enforceCallingOrSelfPermission( 1083 android.Manifest.permission.DEVICE_POWER, null); 1084 resetBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); 1085 } break; 1086 case "suspend_input": { 1087 getContext().enforceCallingOrSelfPermission( 1088 android.Manifest.permission.DEVICE_POWER, null); 1089 suspendBatteryInput(); 1090 } break; 1091 default: 1092 return shell.handleDefaultCommands(cmd); 1093 } 1094 return 0; 1095 } 1096 setChargerAcOnline(boolean online, boolean forceUpdate)1097 private void setChargerAcOnline(boolean online, boolean forceUpdate) { 1098 if (!mUpdatesStopped) { 1099 copyV1Battery(mLastHealthInfo, mHealthInfo); 1100 } 1101 mHealthInfo.chargerAcOnline = online; 1102 mUpdatesStopped = true; 1103 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate)); 1104 } 1105 setBatteryLevel(int level, boolean forceUpdate)1106 private void setBatteryLevel(int level, boolean forceUpdate) { 1107 if (!mUpdatesStopped) { 1108 copyV1Battery(mLastHealthInfo, mHealthInfo); 1109 } 1110 mHealthInfo.batteryLevel = level; 1111 mUpdatesStopped = true; 1112 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate)); 1113 } 1114 unplugBattery(boolean forceUpdate, PrintWriter pw)1115 private void unplugBattery(boolean forceUpdate, PrintWriter pw) { 1116 if (!mUpdatesStopped) { 1117 copyV1Battery(mLastHealthInfo, mHealthInfo); 1118 } 1119 mHealthInfo.chargerAcOnline = false; 1120 mHealthInfo.chargerUsbOnline = false; 1121 mHealthInfo.chargerWirelessOnline = false; 1122 mHealthInfo.chargerDockOnline = false; 1123 mUpdatesStopped = true; 1124 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); 1125 } 1126 resetBattery(boolean forceUpdate, @Nullable PrintWriter pw)1127 private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) { 1128 if (mUpdatesStopped) { 1129 mUpdatesStopped = false; 1130 copyV1Battery(mHealthInfo, mLastHealthInfo); 1131 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); 1132 } 1133 if (mBatteryInputSuspended) { 1134 PowerProperties.battery_input_suspended(false); 1135 mBatteryInputSuspended = false; 1136 } 1137 } 1138 suspendBatteryInput()1139 private void suspendBatteryInput() { 1140 if (!Build.IS_DEBUGGABLE) { 1141 throw new SecurityException( 1142 "battery suspend_input is only supported on debuggable builds"); 1143 } 1144 PowerProperties.battery_input_suspended(true); 1145 mBatteryInputSuspended = true; 1146 } 1147 processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw)1148 private void processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw) { 1149 processValuesLocked(forceUpdate); 1150 if (pw != null && forceUpdate) { 1151 pw.println(mSequence); 1152 } 1153 } 1154 dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args)1155 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) { 1156 synchronized (mLock) { 1157 if (args == null || args.length == 0 || "-a".equals(args[0])) { 1158 pw.println("Current Battery Service state:"); 1159 if (mUpdatesStopped) { 1160 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)"); 1161 } 1162 pw.println(" AC powered: " + mHealthInfo.chargerAcOnline); 1163 pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline); 1164 pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline); 1165 pw.println(" Dock powered: " + mHealthInfo.chargerDockOnline); 1166 pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps); 1167 pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts); 1168 pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounterUah); 1169 pw.println(" status: " + mHealthInfo.batteryStatus); 1170 pw.println(" health: " + mHealthInfo.batteryHealth); 1171 pw.println(" present: " + mHealthInfo.batteryPresent); 1172 pw.println(" level: " + mHealthInfo.batteryLevel); 1173 pw.println(" scale: " + BATTERY_SCALE); 1174 pw.println(" voltage: " + mHealthInfo.batteryVoltageMillivolts); 1175 pw.println(" temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius); 1176 pw.println(" technology: " + mHealthInfo.batteryTechnology); 1177 } else { 1178 Shell shell = new Shell(); 1179 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null)); 1180 } 1181 } 1182 } 1183 dumpProto(FileDescriptor fd)1184 private void dumpProto(FileDescriptor fd) { 1185 final ProtoOutputStream proto = new ProtoOutputStream(fd); 1186 1187 synchronized (mLock) { 1188 proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped); 1189 int batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_NONE; 1190 if (mHealthInfo.chargerAcOnline) { 1191 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_AC; 1192 } else if (mHealthInfo.chargerUsbOnline) { 1193 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_USB; 1194 } else if (mHealthInfo.chargerWirelessOnline) { 1195 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS; 1196 } else if (mHealthInfo.chargerDockOnline) { 1197 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_DOCK; 1198 } 1199 proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue); 1200 proto.write( 1201 BatteryServiceDumpProto.MAX_CHARGING_CURRENT, 1202 mHealthInfo.maxChargingCurrentMicroamps); 1203 proto.write( 1204 BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, 1205 mHealthInfo.maxChargingVoltageMicrovolts); 1206 proto.write( 1207 BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); 1208 proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus); 1209 proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth); 1210 proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent); 1211 proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel); 1212 proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE); 1213 proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltageMillivolts); 1214 proto.write( 1215 BatteryServiceDumpProto.TEMPERATURE, 1216 mHealthInfo.batteryTemperatureTenthsCelsius); 1217 proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology); 1218 } 1219 proto.flush(); 1220 } 1221 traceBegin(String name)1222 private static void traceBegin(String name) { 1223 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); 1224 } 1225 traceEnd()1226 private static void traceEnd() { 1227 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 1228 } 1229 1230 private final class Led { 1231 // must match: config_notificationsBatteryLowBehavior in config.xml 1232 static final int LOW_BATTERY_BEHAVIOR_DEFAULT = 0; 1233 static final int LOW_BATTERY_BEHAVIOR_SOLID = 1; 1234 static final int LOW_BATTERY_BEHAVIOR_FLASHING = 2; 1235 1236 private final LogicalLight mBatteryLight; 1237 1238 private final int mBatteryLowARGB; 1239 private final int mBatteryMediumARGB; 1240 private final int mBatteryFullARGB; 1241 private final int mBatteryLedOn; 1242 private final int mBatteryLedOff; 1243 private final int mBatteryLowBehavior; 1244 Led(Context context, LightsManager lights)1245 public Led(Context context, LightsManager lights) { 1246 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY); 1247 1248 mBatteryLowARGB = context.getResources().getInteger( 1249 com.android.internal.R.integer.config_notificationsBatteryLowARGB); 1250 mBatteryMediumARGB = context.getResources().getInteger( 1251 com.android.internal.R.integer.config_notificationsBatteryMediumARGB); 1252 mBatteryFullARGB = context.getResources().getInteger( 1253 com.android.internal.R.integer.config_notificationsBatteryFullARGB); 1254 mBatteryLedOn = context.getResources().getInteger( 1255 com.android.internal.R.integer.config_notificationsBatteryLedOn); 1256 mBatteryLedOff = context.getResources().getInteger( 1257 com.android.internal.R.integer.config_notificationsBatteryLedOff); 1258 mBatteryNearlyFullLevel = context.getResources().getInteger( 1259 com.android.internal.R.integer.config_notificationsBatteryNearlyFullLevel); 1260 mBatteryLowBehavior = context.getResources().getInteger( 1261 com.android.internal.R.integer.config_notificationsBatteryLowBehavior); 1262 } 1263 1264 /** 1265 * Synchronize on BatteryService. 1266 */ updateLightsLocked()1267 public void updateLightsLocked() { 1268 if (mBatteryLight == null) { 1269 return; 1270 } 1271 final int level = mHealthInfo.batteryLevel; 1272 final int status = mHealthInfo.batteryStatus; 1273 if (level < mLowBatteryWarningLevel) { 1274 switch (mBatteryLowBehavior) { 1275 case LOW_BATTERY_BEHAVIOR_SOLID: 1276 // Solid red when low battery 1277 mBatteryLight.setColor(mBatteryLowARGB); 1278 break; 1279 case LOW_BATTERY_BEHAVIOR_FLASHING: 1280 // Flash red when battery is low and not charging 1281 mBatteryLight.setFlashing(mBatteryLowARGB, LogicalLight.LIGHT_FLASH_TIMED, 1282 mBatteryLedOn, mBatteryLedOff); 1283 break; 1284 default: 1285 if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 1286 // Solid red when battery is charging 1287 mBatteryLight.setColor(mBatteryLowARGB); 1288 } else { 1289 // Flash red when battery is low and not charging 1290 mBatteryLight.setFlashing(mBatteryLowARGB, 1291 LogicalLight.LIGHT_FLASH_TIMED, mBatteryLedOn, mBatteryLedOff); 1292 } 1293 break; 1294 } 1295 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING 1296 || status == BatteryManager.BATTERY_STATUS_FULL) { 1297 if (status == BatteryManager.BATTERY_STATUS_FULL 1298 || level >= mBatteryNearlyFullLevel) { 1299 // Solid green when full or charging and nearly full 1300 mBatteryLight.setColor(mBatteryFullARGB); 1301 } else { 1302 // Solid orange when charging and halfway full 1303 mBatteryLight.setColor(mBatteryMediumARGB); 1304 } 1305 } else { 1306 // No lights if not charging and not low 1307 mBatteryLight.turnOff(); 1308 } 1309 } 1310 } 1311 1312 private final class BinderService extends Binder { dump(FileDescriptor fd, PrintWriter pw, String[] args)1313 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1314 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 1315 1316 if (args.length > 0 && "--proto".equals(args[0])) { 1317 dumpProto(fd); 1318 } else { 1319 dumpInternal(fd, pw, args); 1320 } 1321 } 1322 onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1323 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, 1324 FileDescriptor err, String[] args, ShellCallback callback, 1325 ResultReceiver resultReceiver) { 1326 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); 1327 } 1328 } 1329 1330 // Reduced IBatteryPropertiesRegistrar that implements getProperty for usage 1331 // in BatteryManager and enforce permissions. 1332 private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub { 1333 @Override getProperty(int id, final BatteryProperty prop)1334 public int getProperty(int id, final BatteryProperty prop) throws RemoteException { 1335 switch (id) { 1336 case BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE: 1337 case BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE: 1338 case BatteryManager.BATTERY_PROPERTY_CHARGING_POLICY: 1339 case BatteryManager.BATTERY_PROPERTY_STATE_OF_HEALTH: 1340 mContext.enforceCallingPermission( 1341 android.Manifest.permission.BATTERY_STATS, null); 1342 break; 1343 } 1344 return mHealthServiceWrapper.getProperty(id, prop); 1345 } 1346 @Override scheduleUpdate()1347 public void scheduleUpdate() throws RemoteException { 1348 mHealthServiceWrapper.scheduleUpdate(); 1349 } 1350 } 1351 1352 private final class LocalService extends BatteryManagerInternal { 1353 @Override isPowered(int plugTypeSet)1354 public boolean isPowered(int plugTypeSet) { 1355 synchronized (mLock) { 1356 return isPoweredLocked(plugTypeSet); 1357 } 1358 } 1359 1360 @Override getPlugType()1361 public int getPlugType() { 1362 synchronized (mLock) { 1363 return mPlugType; 1364 } 1365 } 1366 1367 @Override getBatteryLevel()1368 public int getBatteryLevel() { 1369 synchronized (mLock) { 1370 return mHealthInfo.batteryLevel; 1371 } 1372 } 1373 1374 @Override getBatteryChargeCounter()1375 public int getBatteryChargeCounter() { 1376 synchronized (mLock) { 1377 return mHealthInfo.batteryChargeCounterUah; 1378 } 1379 } 1380 1381 @Override getBatteryFullCharge()1382 public int getBatteryFullCharge() { 1383 synchronized (mLock) { 1384 return mHealthInfo.batteryFullChargeUah; 1385 } 1386 } 1387 1388 @Override getBatteryHealth()1389 public int getBatteryHealth() { 1390 synchronized (mLock) { 1391 return mHealthInfo.batteryHealth; 1392 } 1393 } 1394 1395 @Override getBatteryLevelLow()1396 public boolean getBatteryLevelLow() { 1397 synchronized (mLock) { 1398 return mBatteryLevelLow; 1399 } 1400 } 1401 1402 @Override getInvalidCharger()1403 public int getInvalidCharger() { 1404 synchronized (mLock) { 1405 return mInvalidCharger; 1406 } 1407 } 1408 1409 @Override setChargerAcOnline(boolean online, boolean forceUpdate)1410 public void setChargerAcOnline(boolean online, boolean forceUpdate) { 1411 BatteryService.this.setChargerAcOnline(online, forceUpdate); 1412 } 1413 1414 @Override setBatteryLevel(int level, boolean forceUpdate)1415 public void setBatteryLevel(int level, boolean forceUpdate) { 1416 BatteryService.this.setBatteryLevel(level, forceUpdate); 1417 } 1418 1419 @Override unplugBattery(boolean forceUpdate)1420 public void unplugBattery(boolean forceUpdate) { 1421 BatteryService.this.unplugBattery(forceUpdate, /* printWriter= */ null); 1422 } 1423 1424 @Override resetBattery(boolean forceUpdate)1425 public void resetBattery(boolean forceUpdate) { 1426 BatteryService.this.resetBattery(forceUpdate, /* printWriter= */ null); 1427 } 1428 1429 @Override suspendBatteryInput()1430 public void suspendBatteryInput() { 1431 BatteryService.this.suspendBatteryInput(); 1432 } 1433 } 1434 } 1435