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 android.os.Flags.batteryServiceSupportCurrentAdbCommand; 20 import static android.os.Flags.stateOfHealthPublic; 21 22 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent; 23 import static com.android.server.health.Utils.copyV1Battery; 24 25 import static java.lang.Math.abs; 26 27 import android.annotation.NonNull; 28 import android.annotation.Nullable; 29 import android.annotation.SuppressLint; 30 import android.app.ActivityManager; 31 import android.app.ActivityManagerInternal; 32 import android.app.AppOpsManager; 33 import android.app.BroadcastOptions; 34 import android.content.ContentResolver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.database.ContentObserver; 38 import android.hardware.health.HealthInfo; 39 import android.hardware.health.V2_1.BatteryCapacityLevel; 40 import android.metrics.LogMaker; 41 import android.os.BatteryManager; 42 import android.os.BatteryManagerInternal; 43 import android.os.BatteryProperty; 44 import android.os.BatteryStats; 45 import android.os.Binder; 46 import android.os.Build; 47 import android.os.Bundle; 48 import android.os.ConditionVariable; 49 import android.os.DropBoxManager; 50 import android.os.FileUtils; 51 import android.os.Handler; 52 import android.os.IBatteryPropertiesRegistrar; 53 import android.os.IBinder; 54 import android.os.Looper; 55 import android.os.OsProtoEnums; 56 import android.os.PowerManager; 57 import android.os.RemoteException; 58 import android.os.ResultReceiver; 59 import android.os.ServiceManager; 60 import android.os.ShellCallback; 61 import android.os.ShellCommand; 62 import android.os.SystemClock; 63 import android.os.SystemProperties; 64 import android.os.Trace; 65 import android.os.UEventObserver; 66 import android.os.UserHandle; 67 import android.provider.Settings; 68 import android.service.battery.BatteryServiceDumpProto; 69 import android.sysprop.PowerProperties; 70 import android.util.EventLog; 71 import android.util.Slog; 72 import android.util.TimeUtils; 73 import android.util.proto.ProtoOutputStream; 74 75 import com.android.internal.annotations.VisibleForTesting; 76 import com.android.internal.app.IBatteryStats; 77 import com.android.internal.logging.MetricsLogger; 78 import com.android.internal.os.SomeArgs; 79 import com.android.internal.util.DumpUtils; 80 import com.android.server.am.BatteryStatsService; 81 import com.android.server.health.HealthServiceWrapper; 82 import com.android.server.lights.LightsManager; 83 import com.android.server.lights.LogicalLight; 84 85 import java.io.File; 86 import java.io.FileDescriptor; 87 import java.io.FileOutputStream; 88 import java.io.IOException; 89 import java.io.PrintWriter; 90 import java.util.ArrayDeque; 91 import java.util.ArrayList; 92 import java.util.NoSuchElementException; 93 import java.util.Objects; 94 import java.util.concurrent.CopyOnWriteArraySet; 95 96 /** 97 * <p>BatteryService monitors the charging status, and charge level of the device 98 * battery. When these values change this service broadcasts the new values 99 * to all {@link android.content.BroadcastReceiver IntentReceivers} that are 100 * watching the {@link android.content.Intent#ACTION_BATTERY_CHANGED 101 * BATTERY_CHANGED} action.</p> 102 * <p>The new values are stored in the Intent data and can be retrieved by 103 * calling {@link android.content.Intent#getExtra Intent.getExtra} with the 104 * following keys:</p> 105 * <p>"scale" - int, the maximum value for the charge level</p> 106 * <p>"level" - int, charge level, from 0 through "scale" inclusive</p> 107 * <p>"status" - String, the current charging status.<br /> 108 * <p>"health" - String, the current battery health.<br /> 109 * <p>"present" - boolean, true if the battery is present<br /> 110 * <p>"icon-small" - int, suggested small icon to use for this state</p> 111 * <p>"plugged" - int, 0 if the device is not plugged in; 1 if plugged 112 * into an AC power adapter; 2 if plugged in via USB.</p> 113 * <p>"voltage" - int, current battery voltage in millivolts</p> 114 * <p>"temperature" - int, current battery temperature in tenths of 115 * a degree Centigrade</p> 116 * <p>"technology" - String, the type of battery installed, e.g. "Li-ion"</p> 117 * 118 * <p> 119 * The battery service may be called by the power manager while holding its locks so 120 * we take care to post all outcalls into the activity manager to a handler. 121 * 122 * FIXME: Ideally the power manager would perform all of its calls into the battery 123 * service asynchronously itself. 124 * </p> 125 */ 126 public final class BatteryService extends SystemService { 127 private static final String TAG = BatteryService.class.getSimpleName(); 128 129 private static final boolean DEBUG = false; 130 131 private static final int BATTERY_SCALE = 100; // battery capacity is a percentage 132 133 private static final long HEALTH_HAL_WAIT_MS = 1000; 134 private static final long BATTERY_LEVEL_CHANGE_THROTTLE_MS = 60_000; 135 private static final int MAX_BATTERY_LEVELS_QUEUE_SIZE = 100; 136 137 // Used locally for determining when to make a last ditch effort to log 138 // discharge stats before the device dies. 139 private int mCriticalBatteryLevel; 140 141 // TODO: Current args don't work since "--unplugged" flag was purposefully removed. 142 private static final String[] DUMPSYS_ARGS = new String[] { "--checkin", "--unplugged" }; 143 144 private static final String DUMPSYS_DATA_PATH = "/data/system/"; 145 146 // This should probably be exposed in the API, though it's not critical 147 private static final int BATTERY_PLUGGED_NONE = OsProtoEnums.BATTERY_PLUGGED_NONE; // = 0 148 149 private final Context mContext; 150 private final IBatteryStats mBatteryStats; 151 BinderService mBinderService; 152 private final Handler mHandler; 153 154 private final Object mLock = new Object(); 155 private final ConditionVariable mConditionVariable = new ConditionVariable(); 156 private HealthInfo mHealthInfo; 157 private final HealthInfo mLastHealthInfo = new HealthInfo(); 158 private boolean mBatteryLevelCritical; 159 160 /** 161 * {@link HealthInfo#batteryStatus} value when {@link Intent#ACTION_BATTERY_CHANGED} 162 * broadcast was sent last. 163 * Note: This value may be used for internal operations and/or to determine whether to trigger 164 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 165 */ 166 private int mLastBroadcastBatteryStatus; 167 /** 168 * {@link HealthInfo#batteryHealth} value when {@link Intent#ACTION_BATTERY_CHANGED} 169 * broadcast was sent last. 170 * Note: This value may be used for internal operations and/or to determine whether to trigger 171 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 172 */ 173 private int mLastBroadcastBatteryHealth; 174 /** 175 * {@link HealthInfo#batteryPresent} value when {@link Intent#ACTION_BATTERY_CHANGED} 176 * broadcast was sent last. 177 * Note: This value may be used for internal operations and/or to determine whether to trigger 178 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 179 */ 180 private boolean mLastBroadcastBatteryPresent; 181 /** 182 * {@link HealthInfo#batteryLevel} value when {@link Intent#ACTION_BATTERY_CHANGED} 183 * broadcast was sent last. 184 * Note: This value may be used for internal operations and/or to determine whether to trigger 185 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 186 */ 187 private int mLastBroadcastBatteryLevel; 188 /** 189 * {@link HealthInfo#batteryVoltageMillivolts} value when {@link Intent#ACTION_BATTERY_CHANGED} 190 * broadcast was sent last. 191 * Note: This value may be used for internal operations and/or to determine whether to trigger 192 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 193 */ 194 private int mLastBroadcastBatteryVoltage; 195 /** 196 * {@link HealthInfo#batteryTemperatureTenthsCelsius} value when 197 * {@link Intent#ACTION_BATTERY_CHANGED} broadcast was sent last. 198 * Note: This value may be used for internal operations and/or to determine whether to trigger 199 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 200 */ 201 private int mLastBroadcastBatteryTemperature; 202 /** 203 * {@link #mBatteryLevelCritical} value when {@link Intent#ACTION_BATTERY_CHANGED} 204 * broadcast was sent last. 205 * Note: These values may be used for internal operations and/or to determine whether to trigger 206 * the broadcast or not. 207 */ 208 private boolean mLastBroadcastBatteryLevelCritical; 209 /** 210 * {@link HealthInfo#maxChargingCurrentMicroamps} value when 211 * {@link Intent#ACTION_BATTERY_CHANGED} broadcast was sent last. 212 * Note: This value may be used for internal operations and/or to determine whether to trigger 213 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 214 */ 215 private int mLastBroadcastMaxChargingCurrent; 216 /** 217 * {@link HealthInfo#maxChargingVoltageMicrovolts} value when 218 * {@link Intent#ACTION_BATTERY_CHANGED} broadcast was sent last. 219 * Note: This value may be used for internal operations and/or to determine whether to trigger 220 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 221 */ 222 private int mLastBroadcastMaxChargingVoltage; 223 /** 224 * {@link HealthInfo#batteryChargeCounterUah} value when {@link Intent#ACTION_BATTERY_CHANGED} 225 * broadcast was sent last. 226 * Note: This value may be used for internal operations and/or to determine whether to trigger 227 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 228 */ 229 private int mLastBroadcastChargeCounter; 230 /** 231 * {@link HealthInfo#batteryCycleCount} value when {@link Intent#ACTION_BATTERY_CHANGED} 232 * broadcast was sent last. 233 * Note: This value may be used for internal operations and/or to determine whether to trigger 234 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 235 */ 236 private int mLastBroadcastBatteryCycleCount; 237 /** 238 * {@link HealthInfo#chargingState} value when {@link Intent#ACTION_BATTERY_CHANGED} 239 * broadcast was sent last. 240 * Note: This value may be used for internal operations and/or to determine whether to trigger 241 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 242 */ 243 private int mLastBroadcastChargingState; 244 /** 245 * {@link HealthInfo#batteryCapacityLevel} value when {@link Intent#ACTION_BATTERY_CHANGED} 246 * broadcast was sent last. 247 * Note: This value may be used for internal operations and/or to determine whether to trigger 248 * the {@link Intent#ACTION_BATTERY_CHANGED} broadcast or not. 249 */ 250 private int mLastBroadcastBatteryCapacityLevel; 251 /** 252 * {@link #mPlugType} value when {@link Intent#ACTION_BATTERY_CHANGED} 253 * broadcast was sent last. 254 * Note: These values may be used for internal operations and/or to determine whether to trigger 255 * the broadcast or not. 256 */ 257 private int mLastBroadcastPlugType = -1; // Extra state so we can detect first run 258 /** 259 * {@link #mInvalidCharger} value when {@link Intent#ACTION_BATTERY_CHANGED} 260 * broadcast was sent last. 261 * Note: These values may be used for internal operations and/or to determine whether to trigger 262 * the broadcast or not. 263 */ 264 private int mLastBroadcastInvalidCharger; 265 /** 266 * The last seen charging policy. This requires the 267 * {@link android.Manifest.permission#BATTERY_STATS} permission and should therefore not be 268 * included in the ACTION_BATTERY_CHANGED intent extras. 269 */ 270 private int mLastChargingPolicy; 271 272 private int mSequence = 1; 273 274 private int mInvalidCharger; 275 276 private int mLowBatteryWarningLevel; 277 private int mLastLowBatteryWarningLevel; 278 private int mLowBatteryCloseWarningLevel; 279 private int mBatteryNearlyFullLevel; 280 private int mShutdownBatteryTemperature; 281 private boolean mShutdownIfNoPower; 282 283 private static String sSystemUiPackage; 284 285 private int mPlugType; 286 287 private boolean mBatteryLevelLow; 288 289 private long mDischargeStartTime; 290 private int mDischargeStartLevel; 291 292 private long mChargeStartTime; 293 private int mChargeStartLevel; 294 295 private boolean mUpdatesStopped; 296 private boolean mBatteryInputSuspended; 297 298 /** 299 * Time when the voltage was updated last by HAL and we sent the 300 * {@link Intent#ACTION_BATTERY_CHANGED} broadcast. 301 * Note: This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast 302 * so it is possible that voltage was updated but we did not send the broadcast so in that 303 * case we do not update the time. 304 */ 305 @VisibleForTesting 306 public long mLastBroadcastVoltageUpdateTime; 307 /** 308 * Time when the max charging current was updated last by HAL and we sent the 309 * {@link Intent#ACTION_BATTERY_CHANGED} broadcast. 310 * Note: This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast 311 * so it is possible that max current was updated but we did not send the broadcast so in that 312 * case we do not update the time. 313 */ 314 @VisibleForTesting 315 public long mLastBroadcastMaxChargingCurrentUpdateTime; 316 317 private boolean mIsFirstBatteryChangedUpdate = true; 318 319 private Led mLed; 320 321 private boolean mSentLowBatteryBroadcast = false; 322 323 private ActivityManagerInternal mActivityManagerInternal; 324 325 private HealthServiceWrapper mHealthServiceWrapper; 326 private BatteryPropertiesRegistrar mBatteryPropertiesRegistrar; 327 private ArrayDeque<Bundle> mBatteryLevelsEventQueue; 328 private long mLastBatteryLevelChangedSentMs; 329 330 private final CopyOnWriteArraySet<BatteryManagerInternal.ChargingPolicyChangeListener> 331 mChargingPolicyChangeListeners = new CopyOnWriteArraySet<>(); 332 333 @VisibleForTesting 334 public static final Bundle BATTERY_CHANGED_OPTIONS = BroadcastOptions.makeBasic() 335 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 336 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 337 .toBundle(); 338 /** Used for both connected/disconnected, so match using key */ 339 private static final Bundle POWER_OPTIONS = BroadcastOptions.makeBasic() 340 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 341 .setDeliveryGroupMatchingKey("android", Intent.ACTION_POWER_CONNECTED) 342 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 343 .toBundle(); 344 /** Used for both low/okay, so match using key */ 345 private static final Bundle BATTERY_OPTIONS = BroadcastOptions.makeBasic() 346 .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT) 347 .setDeliveryGroupMatchingKey("android", Intent.ACTION_BATTERY_OKAY) 348 .setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE) 349 .toBundle(); 350 351 private MetricsLogger mMetricsLogger; 352 353 private static final int MSG_BROADCAST_BATTERY_CHANGED = 1; 354 private static final int MSG_BROADCAST_POWER_CONNECTION_CHANGED = 2; 355 private static final int MSG_BROADCAST_BATTERY_LOW_OKAY = 3; 356 357 /** 358 * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We 359 * only send the broadcast and update the temperature value when the temp change is greater or 360 * equals to 1 degree celsius. 361 */ 362 private static final int ABSOLUTE_DECI_CELSIUS_DIFF_FOR_TEMP_UPDATE = 10; 363 /** 364 * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We 365 * only send the broadcast if the last voltage was updated at least 20 seconds back and has a 366 * fluctuation of at least 1%. 367 */ 368 private static final int TIME_DIFF_FOR_VOLTAGE_UPDATE_MS = 20000; 369 /** 370 * The value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We 371 * only send the broadcast if the last voltage was updated at least 20 seconds back and has a 372 * fluctuation of at least 1%. 373 */ 374 private static final float BASE_POINT_DIFF_FOR_VOLTAGE_UPDATE = 0.01f; 375 /** 376 * This value is used to rate limit the {@link Intent#ACTION_BATTERY_CHANGED} broadcast. We 377 * only send the broadcast if the last max charging current was updated at least 5 seconds back. 378 */ 379 private static final int TIME_DIFF_FOR_MAX_CHARGING_CURRENT_UPDATE_MS = 5000; 380 381 private final Handler.Callback mLocalCallback = msg -> { 382 switch (msg.what) { 383 case MSG_BROADCAST_BATTERY_CHANGED: { 384 final SomeArgs args = (SomeArgs) msg.obj; 385 final Context context; 386 final Intent intent; 387 final boolean forceUpdate; 388 try { 389 context = (Context) args.arg1; 390 intent = (Intent) args.arg2; 391 forceUpdate = (Boolean) args.arg3; 392 } finally { 393 args.recycle(); 394 } 395 broadcastBatteryChangedIntent(context, intent, BATTERY_CHANGED_OPTIONS, 396 forceUpdate); 397 return true; 398 } 399 case MSG_BROADCAST_POWER_CONNECTION_CHANGED: { 400 final SomeArgs args = (SomeArgs) msg.obj; 401 final Context context; 402 final Intent intent; 403 try { 404 context = (Context) args.arg1; 405 intent = (Intent) args.arg2; 406 } finally { 407 args.recycle(); 408 } 409 sendBroadcastToAllUsers(context, intent, POWER_OPTIONS); 410 return true; 411 } 412 case MSG_BROADCAST_BATTERY_LOW_OKAY: { 413 final SomeArgs args = (SomeArgs) msg.obj; 414 final Context context; 415 final Intent intent; 416 try { 417 context = (Context) args.arg1; 418 intent = (Intent) args.arg2; 419 } finally { 420 args.recycle(); 421 } 422 sendBroadcastToAllUsers(context, intent, BATTERY_OPTIONS); 423 return true; 424 } 425 } 426 return false; 427 }; 428 BatteryService(Context context)429 public BatteryService(Context context) { 430 this(context, Objects.requireNonNull(Looper.myLooper(), 431 "BatteryService uses handler!! Can't create handler inside thread that has not " 432 + "called Looper.prepare()")); 433 } 434 435 @VisibleForTesting BatteryService(Context context, @NonNull Looper looper)436 public BatteryService(Context context, @NonNull Looper looper) { 437 super(context); 438 439 Objects.requireNonNull(looper); 440 441 mContext = context; 442 mHandler = new Handler(looper, mLocalCallback, true /*async*/); 443 mLed = new Led(context, getLocalService(LightsManager.class)); 444 mBatteryStats = BatteryStatsService.getService(); 445 mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); 446 447 mCriticalBatteryLevel = mContext.getResources().getInteger( 448 com.android.internal.R.integer.config_criticalBatteryWarningLevel); 449 mLowBatteryWarningLevel = mContext.getResources().getInteger( 450 com.android.internal.R.integer.config_lowBatteryWarningLevel); 451 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger( 452 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 453 mShutdownBatteryTemperature = mContext.getResources().getInteger( 454 com.android.internal.R.integer.config_shutdownBatteryTemperature); 455 mShutdownIfNoPower = mContext.getResources().getBoolean( 456 com.android.internal.R.bool.config_shutdownIfNoPower); 457 sSystemUiPackage = mContext.getResources().getString( 458 com.android.internal.R.string.config_systemUi); 459 460 mBatteryLevelsEventQueue = new ArrayDeque<>(); 461 mMetricsLogger = new MetricsLogger(); 462 463 // watch for invalid charger messages if the invalid_charger switch exists 464 if (new File("/sys/devices/virtual/switch/invalid_charger/state").exists()) { 465 UEventObserver invalidChargerObserver = new UEventObserver() { 466 @Override 467 public void onUEvent(UEvent event) { 468 final int invalidCharger = "1".equals(event.get("SWITCH_STATE")) ? 1 : 0; 469 synchronized (mLock) { 470 if (mInvalidCharger != invalidCharger) { 471 mInvalidCharger = invalidCharger; 472 } 473 } 474 } 475 }; 476 invalidChargerObserver.startObserving( 477 "DEVPATH=/devices/virtual/switch/invalid_charger"); 478 } 479 480 mBatteryInputSuspended = PowerProperties.battery_input_suspended().orElse(false); 481 } 482 483 @Override onStart()484 public void onStart() { 485 registerHealthCallback(); 486 487 mBinderService = new BinderService(); 488 publishBinderService("battery", mBinderService); 489 mBatteryPropertiesRegistrar = new BatteryPropertiesRegistrar(); 490 publishBinderService("batteryproperties", mBatteryPropertiesRegistrar); 491 publishLocalService(BatteryManagerInternal.class, new LocalService()); 492 } 493 494 @Override onBootPhase(int phase)495 public void onBootPhase(int phase) { 496 if (phase == PHASE_ACTIVITY_MANAGER_READY) { 497 // check our power situation now that it is safe to display the shutdown dialog. 498 synchronized (mLock) { 499 ContentObserver obs = new ContentObserver(mHandler) { 500 @Override 501 public void onChange(boolean selfChange) { 502 synchronized (mLock) { 503 updateBatteryWarningLevelLocked(); 504 } 505 } 506 }; 507 final ContentResolver resolver = mContext.getContentResolver(); 508 resolver.registerContentObserver(Settings.Global.getUriFor( 509 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), 510 false, obs, UserHandle.USER_ALL); 511 updateBatteryWarningLevelLocked(); 512 } 513 } 514 } 515 registerHealthCallback()516 private void registerHealthCallback() { 517 traceBegin("HealthInitWrapper"); 518 // IHealth is lazily retrieved. 519 try { 520 mHealthServiceWrapper = HealthServiceWrapper.create(this::update); 521 } catch (RemoteException ex) { 522 Slog.e(TAG, "health: cannot register callback. (RemoteException)"); 523 throw ex.rethrowFromSystemServer(); 524 } catch (NoSuchElementException ex) { 525 Slog.e(TAG, "health: cannot register callback. (no supported health HAL service)"); 526 throw ex; 527 } finally { 528 traceEnd(); 529 } 530 531 traceBegin("HealthInitWaitUpdate"); 532 // init register for new service notifications, and IServiceManager should return the 533 // existing service in a near future. Wait for this.update() to instantiate 534 // the initial mHealthInfo. 535 long beforeWait = SystemClock.uptimeMillis(); 536 if (mHealthInfo == null) { 537 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) 538 + "ms for callbacks. Waiting another " + HEALTH_HAL_WAIT_MS + " ms..."); 539 mConditionVariable.block(HEALTH_HAL_WAIT_MS); 540 } 541 542 Slog.i(TAG, "health: Waited " + (SystemClock.uptimeMillis() - beforeWait) 543 + "ms and received the update."); 544 traceEnd(); 545 } 546 updateBatteryWarningLevelLocked()547 private void updateBatteryWarningLevelLocked() { 548 final ContentResolver resolver = mContext.getContentResolver(); 549 int defWarnLevel = mContext.getResources().getInteger( 550 com.android.internal.R.integer.config_lowBatteryWarningLevel); 551 mLastLowBatteryWarningLevel = mLowBatteryWarningLevel; 552 mLowBatteryWarningLevel = Settings.Global.getInt(resolver, 553 Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL, defWarnLevel); 554 if (mLowBatteryWarningLevel == 0) { 555 mLowBatteryWarningLevel = defWarnLevel; 556 } 557 if (mLowBatteryWarningLevel < mCriticalBatteryLevel) { 558 mLowBatteryWarningLevel = mCriticalBatteryLevel; 559 } 560 mLowBatteryCloseWarningLevel = mLowBatteryWarningLevel + mContext.getResources().getInteger( 561 com.android.internal.R.integer.config_lowBatteryCloseWarningBump); 562 processValuesLocked(true); 563 } 564 isPoweredLocked(int plugTypeSet)565 private boolean isPoweredLocked(int plugTypeSet) { 566 // assume we are powered if battery state is unknown so 567 // the "stay on while plugged in" option will work. 568 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_UNKNOWN) { 569 return true; 570 } 571 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_AC) != 0 572 && mHealthInfo.chargerAcOnline) { 573 return true; 574 } 575 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_USB) != 0 576 && mHealthInfo.chargerUsbOnline) { 577 return true; 578 } 579 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_WIRELESS) != 0 580 && mHealthInfo.chargerWirelessOnline) { 581 return true; 582 } 583 if ((plugTypeSet & BatteryManager.BATTERY_PLUGGED_DOCK) != 0 584 && mHealthInfo.chargerDockOnline) { 585 return true; 586 } 587 return false; 588 } 589 shouldSendBatteryLowLocked()590 private boolean shouldSendBatteryLowLocked() { 591 final boolean plugged = mPlugType != BATTERY_PLUGGED_NONE; 592 final boolean oldPlugged = mLastBroadcastPlugType != BATTERY_PLUGGED_NONE; 593 594 /* The ACTION_BATTERY_LOW broadcast is sent in these situations: 595 * - is just un-plugged (previously was plugged) and battery level is 596 * less than or equal to WARNING, or 597 * - is not plugged and battery level falls to WARNING boundary 598 * (becomes <= mLowBatteryWarningLevel). 599 */ 600 return !plugged 601 && mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 602 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel 603 && (oldPlugged || mLastBroadcastBatteryLevel > mLowBatteryWarningLevel 604 || mHealthInfo.batteryLevel > mLastLowBatteryWarningLevel); 605 } 606 shouldShutdownLocked()607 private boolean shouldShutdownLocked() { 608 if (mHealthInfo.batteryCapacityLevel != BatteryCapacityLevel.UNSUPPORTED) { 609 return (mHealthInfo.batteryCapacityLevel == BatteryCapacityLevel.CRITICAL); 610 } 611 if (!mShutdownIfNoPower) { 612 return false; 613 } 614 if (mHealthInfo.batteryLevel > 0) { 615 return false; 616 } 617 618 // Battery-less devices should not shutdown. 619 if (!mHealthInfo.batteryPresent) { 620 return false; 621 } 622 623 // If battery state is not CHARGING, shutdown. 624 // - If battery present and state == unknown, this is an unexpected error state. 625 // - If level <= 0 and state == full, this is also an unexpected state 626 // - All other states (NOT_CHARGING, DISCHARGING) means it is not charging. 627 return mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING; 628 } 629 shutdownIfNoPowerLocked()630 private void shutdownIfNoPowerLocked() { 631 // shut down gracefully if our battery is critically low and we are not powered. 632 // wait until the system has booted before attempting to display the shutdown dialog. 633 if (shouldShutdownLocked()) { 634 mHandler.post(new Runnable() { 635 @Override 636 public void run() { 637 if (mActivityManagerInternal.isSystemReady()) { 638 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 639 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); 640 intent.putExtra(Intent.EXTRA_REASON, 641 PowerManager.SHUTDOWN_LOW_BATTERY); 642 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 643 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 644 } 645 } 646 }); 647 } 648 } 649 shutdownIfOverTempLocked()650 private void shutdownIfOverTempLocked() { 651 // shut down gracefully if temperature is too high (> 68.0C by default) 652 // wait until the system has booted before attempting to display the 653 // shutdown dialog. 654 if (mHealthInfo.batteryTemperatureTenthsCelsius > mShutdownBatteryTemperature) { 655 mHandler.post(new Runnable() { 656 @Override 657 public void run() { 658 if (mActivityManagerInternal.isSystemReady()) { 659 Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN); 660 intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false); 661 intent.putExtra(Intent.EXTRA_REASON, 662 PowerManager.SHUTDOWN_BATTERY_THERMAL_STATE); 663 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 664 mContext.startActivityAsUser(intent, UserHandle.CURRENT); 665 } 666 } 667 }); 668 } 669 } 670 671 /** 672 * Updates the healthInfo and triggers the broadcast. 673 * 674 * @param info the new health info 675 */ 676 @VisibleForTesting update(android.hardware.health.HealthInfo info)677 public void update(android.hardware.health.HealthInfo info) { 678 traceBegin("HealthInfoUpdate"); 679 680 Trace.traceCounter( 681 Trace.TRACE_TAG_POWER, "BatteryChargeCounter", info.batteryChargeCounterUah); 682 Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryCurrent", info.batteryCurrentMicroamps); 683 Trace.traceCounter(Trace.TRACE_TAG_POWER, "PlugType", plugType(info)); 684 Trace.traceCounter(Trace.TRACE_TAG_POWER, "BatteryStatus", info.batteryStatus); 685 686 synchronized (mLock) { 687 if (!mUpdatesStopped) { 688 mHealthInfo = info; 689 // Process the new values. 690 processValuesLocked(false); 691 mConditionVariable.open(); 692 } else { 693 copyV1Battery(mLastHealthInfo, info); 694 } 695 } 696 traceEnd(); 697 } 698 plugType(HealthInfo healthInfo)699 private static int plugType(HealthInfo healthInfo) { 700 if (healthInfo.chargerAcOnline) { 701 return BatteryManager.BATTERY_PLUGGED_AC; 702 } else if (healthInfo.chargerUsbOnline) { 703 return BatteryManager.BATTERY_PLUGGED_USB; 704 } else if (healthInfo.chargerWirelessOnline) { 705 return BatteryManager.BATTERY_PLUGGED_WIRELESS; 706 } else if (healthInfo.chargerDockOnline) { 707 return BatteryManager.BATTERY_PLUGGED_DOCK; 708 } else { 709 return BATTERY_PLUGGED_NONE; 710 } 711 } 712 processValuesLocked(boolean force)713 private void processValuesLocked(boolean force) { 714 boolean logOutlier = false; 715 long dischargeDuration = 0; 716 717 mBatteryLevelCritical = 718 mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_UNKNOWN 719 && mHealthInfo.batteryLevel <= mCriticalBatteryLevel; 720 mPlugType = plugType(mHealthInfo); 721 722 if (DEBUG) { 723 Slog.d(TAG, "Processing new values: " 724 + "info=" + mHealthInfo 725 + ", mBatteryLevelCritical=" + mBatteryLevelCritical 726 + ", mPlugType=" + mPlugType); 727 } 728 729 // Let the battery stats keep track of the current level. 730 try { 731 mBatteryStats.setBatteryState( 732 mHealthInfo.batteryStatus, 733 mHealthInfo.batteryHealth, 734 mPlugType, 735 mHealthInfo.batteryLevel, 736 mHealthInfo.batteryTemperatureTenthsCelsius, 737 mHealthInfo.batteryVoltageMillivolts, 738 mHealthInfo.batteryChargeCounterUah, 739 mHealthInfo.batteryFullChargeUah, 740 mHealthInfo.batteryChargeTimeToFullNowSeconds); 741 } catch (RemoteException e) { 742 // Should never happen. 743 } 744 745 shutdownIfNoPowerLocked(); 746 shutdownIfOverTempLocked(); 747 748 if (force || mHealthInfo.chargingPolicy != mLastChargingPolicy) { 749 mLastChargingPolicy = mHealthInfo.chargingPolicy; 750 mHandler.post(this::notifyChargingPolicyChanged); 751 } 752 753 final boolean includeChargeCounter = 754 !com.android.server.flags.Flags.rateLimitBatteryChangedBroadcast() 755 && mHealthInfo.batteryChargeCounterUah != mLastBroadcastChargeCounter; 756 757 if (force 758 || (mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus 759 || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth 760 || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent 761 || mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel 762 || mPlugType != mLastBroadcastPlugType 763 || mHealthInfo.batteryVoltageMillivolts != mLastBroadcastBatteryVoltage 764 || mHealthInfo.batteryTemperatureTenthsCelsius != mLastBroadcastBatteryTemperature 765 || mHealthInfo.maxChargingCurrentMicroamps != mLastBroadcastMaxChargingCurrent 766 || mHealthInfo.maxChargingVoltageMicrovolts != mLastBroadcastMaxChargingVoltage 767 || includeChargeCounter 768 || mInvalidCharger != mLastBroadcastInvalidCharger 769 || mHealthInfo.batteryCycleCount != mLastBroadcastBatteryCycleCount 770 || mHealthInfo.chargingState != mLastBroadcastChargingState 771 || mHealthInfo.batteryCapacityLevel != mLastBroadcastBatteryCapacityLevel)) { 772 773 if (mPlugType != mLastBroadcastPlugType) { 774 if (mLastBroadcastPlugType == BATTERY_PLUGGED_NONE) { 775 // discharging -> charging 776 mChargeStartLevel = mHealthInfo.batteryLevel; 777 mChargeStartTime = SystemClock.elapsedRealtime(); 778 779 final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE); 780 builder.setType(MetricsEvent.TYPE_ACTION); 781 builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mPlugType); 782 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START, 783 mHealthInfo.batteryLevel); 784 mMetricsLogger.write(builder); 785 786 // There's no value in this data unless we've discharged at least once and the 787 // battery level has changed; so don't log until it does. 788 if (mDischargeStartTime != 0 789 && mDischargeStartLevel != mHealthInfo.batteryLevel) { 790 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; 791 logOutlier = true; 792 EventLog.writeEvent(EventLogTags.BATTERY_DISCHARGE, dischargeDuration, 793 mDischargeStartLevel, mHealthInfo.batteryLevel); 794 // make sure we see a discharge event before logging again 795 mDischargeStartTime = 0; 796 } 797 } else if (mPlugType == BATTERY_PLUGGED_NONE) { 798 // charging -> discharging or we just powered up 799 mDischargeStartTime = SystemClock.elapsedRealtime(); 800 mDischargeStartLevel = mHealthInfo.batteryLevel; 801 802 long chargeDuration = SystemClock.elapsedRealtime() - mChargeStartTime; 803 if (mChargeStartTime != 0 && chargeDuration != 0) { 804 final LogMaker builder = new LogMaker(MetricsEvent.ACTION_CHARGE); 805 builder.setType(MetricsEvent.TYPE_DISMISS); 806 builder.addTaggedData(MetricsEvent.FIELD_PLUG_TYPE, mLastBroadcastPlugType); 807 builder.addTaggedData(MetricsEvent.FIELD_CHARGING_DURATION_MILLIS, 808 chargeDuration); 809 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_START, 810 mChargeStartLevel); 811 builder.addTaggedData(MetricsEvent.FIELD_BATTERY_LEVEL_END, 812 mHealthInfo.batteryLevel); 813 mMetricsLogger.write(builder); 814 } 815 mChargeStartTime = 0; 816 } 817 } 818 if (mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus 819 || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth 820 || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent 821 || mPlugType != mLastBroadcastPlugType) { 822 EventLog.writeEvent(EventLogTags.BATTERY_STATUS, 823 mHealthInfo.batteryStatus, mHealthInfo.batteryHealth, 824 mHealthInfo.batteryPresent ? 1 : 0, 825 mPlugType, mHealthInfo.batteryTechnology); 826 SystemProperties.set( 827 "debug.tracing.battery_status", 828 Integer.toString(mHealthInfo.batteryStatus)); 829 SystemProperties.set("debug.tracing.plug_type", Integer.toString(mPlugType)); 830 } 831 if (mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel) { 832 // Don't do this just from voltage or temperature changes, that is 833 // too noisy. 834 EventLog.writeEvent( 835 EventLogTags.BATTERY_LEVEL, 836 mHealthInfo.batteryLevel, 837 mHealthInfo.batteryVoltageMillivolts, 838 mHealthInfo.batteryTemperatureTenthsCelsius); 839 } 840 if (mBatteryLevelCritical && !mLastBroadcastBatteryLevelCritical 841 && mPlugType == BATTERY_PLUGGED_NONE) { 842 // We want to make sure we log discharge cycle outliers 843 // if the battery is about to die. 844 dischargeDuration = SystemClock.elapsedRealtime() - mDischargeStartTime; 845 logOutlier = true; 846 } 847 848 if (!mBatteryLevelLow) { 849 // Should we now switch in to low battery mode? 850 if (mPlugType == BATTERY_PLUGGED_NONE 851 && mHealthInfo.batteryStatus != 852 BatteryManager.BATTERY_STATUS_UNKNOWN 853 && mHealthInfo.batteryLevel <= mLowBatteryWarningLevel) { 854 mBatteryLevelLow = true; 855 } 856 } else { 857 // Should we now switch out of low battery mode? 858 if (mPlugType != BATTERY_PLUGGED_NONE) { 859 mBatteryLevelLow = false; 860 } else if (mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) { 861 mBatteryLevelLow = false; 862 } else if (force && mHealthInfo.batteryLevel >= mLowBatteryWarningLevel) { 863 // If being forced, the previous state doesn't matter, we will just 864 // absolutely check to see if we are now above the warning level. 865 mBatteryLevelLow = false; 866 } 867 } 868 869 mSequence++; 870 871 // Separate broadcast is sent for power connected / not connected 872 // since the standard intent will not wake any applications and some 873 // applications may want to have smart behavior based on this. 874 if (mPlugType != 0 && mLastBroadcastPlugType == 0) { 875 final Intent statusIntent = new Intent(Intent.ACTION_POWER_CONNECTED); 876 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 877 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 878 if (com.android.server.flags.Flags.consolidateBatteryChangeEvents()) { 879 mHandler.removeMessages(MSG_BROADCAST_POWER_CONNECTION_CHANGED); 880 final SomeArgs args = SomeArgs.obtain(); 881 args.arg1 = mContext; 882 args.arg2 = statusIntent; 883 mHandler.obtainMessage(MSG_BROADCAST_POWER_CONNECTION_CHANGED, args) 884 .sendToTarget(); 885 } else { 886 mHandler.post(new Runnable() { 887 @Override 888 public void run() { 889 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 890 POWER_OPTIONS); 891 } 892 }); 893 } 894 } else if (mPlugType == 0 && mLastBroadcastPlugType != 0) { 895 final Intent statusIntent = new Intent(Intent.ACTION_POWER_DISCONNECTED); 896 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 897 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 898 if (com.android.server.flags.Flags.consolidateBatteryChangeEvents()) { 899 mHandler.removeMessages(MSG_BROADCAST_POWER_CONNECTION_CHANGED); 900 final SomeArgs args = SomeArgs.obtain(); 901 args.arg1 = mContext; 902 args.arg2 = statusIntent; 903 mHandler.obtainMessage(MSG_BROADCAST_POWER_CONNECTION_CHANGED, args) 904 .sendToTarget(); 905 } else { 906 mHandler.post(new Runnable() { 907 @Override 908 public void run() { 909 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 910 POWER_OPTIONS); 911 } 912 }); 913 } 914 } 915 916 if (shouldSendBatteryLowLocked()) { 917 mSentLowBatteryBroadcast = true; 918 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_LOW); 919 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 920 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 921 if (com.android.server.flags.Flags.consolidateBatteryChangeEvents()) { 922 mHandler.removeMessages(MSG_BROADCAST_BATTERY_LOW_OKAY); 923 final SomeArgs args = SomeArgs.obtain(); 924 args.arg1 = mContext; 925 args.arg2 = statusIntent; 926 mHandler.obtainMessage(MSG_BROADCAST_BATTERY_LOW_OKAY, args) 927 .sendToTarget(); 928 } else { 929 mHandler.post(new Runnable() { 930 @Override 931 public void run() { 932 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 933 BATTERY_OPTIONS); 934 } 935 }); 936 } 937 } else if (mSentLowBatteryBroadcast && 938 mHealthInfo.batteryLevel >= mLowBatteryCloseWarningLevel) { 939 mSentLowBatteryBroadcast = false; 940 final Intent statusIntent = new Intent(Intent.ACTION_BATTERY_OKAY); 941 statusIntent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 942 statusIntent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 943 if (com.android.server.flags.Flags.consolidateBatteryChangeEvents()) { 944 mHandler.removeMessages(MSG_BROADCAST_BATTERY_LOW_OKAY); 945 final SomeArgs args = SomeArgs.obtain(); 946 args.arg1 = mContext; 947 args.arg2 = statusIntent; 948 mHandler.obtainMessage(MSG_BROADCAST_BATTERY_LOW_OKAY, args) 949 .sendToTarget(); 950 } else { 951 mHandler.post(new Runnable() { 952 @Override 953 public void run() { 954 mContext.sendBroadcastAsUser(statusIntent, UserHandle.ALL, null, 955 BATTERY_OPTIONS); 956 } 957 }); 958 } 959 } 960 961 // We are doing this after sending the above broadcasts, so anything processing 962 // them will get the new sequence number at that point. (See for example how testing 963 // of JobScheduler's BatteryController works.) 964 965 boolean rateLimitBatteryChangedBroadcast = rateLimitBatteryChangedBroadcast(force); 966 967 if (!rateLimitBatteryChangedBroadcast) { 968 sendBatteryChangedIntentLocked(force); 969 } 970 if (mLastBroadcastBatteryLevel != mHealthInfo.batteryLevel 971 || mLastBroadcastPlugType != mPlugType) { 972 sendBatteryLevelChangedIntentLocked(); 973 } 974 975 976 // Update the battery LED 977 mLed.updateLightsLocked(); 978 979 // This needs to be done after sendIntent() so that we get the lastest battery stats. 980 if (logOutlier && dischargeDuration != 0) { 981 logOutlierLocked(dischargeDuration); 982 } 983 984 // Only update the values when we send the broadcast 985 if (!rateLimitBatteryChangedBroadcast) { 986 mLastBroadcastBatteryStatus = mHealthInfo.batteryStatus; 987 mLastBroadcastBatteryHealth = mHealthInfo.batteryHealth; 988 mLastBroadcastBatteryPresent = mHealthInfo.batteryPresent; 989 mLastBroadcastBatteryLevel = mHealthInfo.batteryLevel; 990 mLastBroadcastPlugType = mPlugType; 991 mLastBroadcastBatteryVoltage = mHealthInfo.batteryVoltageMillivolts; 992 mLastBroadcastBatteryTemperature = mHealthInfo.batteryTemperatureTenthsCelsius; 993 mLastBroadcastMaxChargingCurrent = mHealthInfo.maxChargingCurrentMicroamps; 994 mLastBroadcastMaxChargingVoltage = mHealthInfo.maxChargingVoltageMicrovolts; 995 mLastBroadcastChargeCounter = mHealthInfo.batteryChargeCounterUah; 996 mLastBroadcastBatteryLevelCritical = mBatteryLevelCritical; 997 mLastBroadcastInvalidCharger = mInvalidCharger; 998 mLastBroadcastBatteryCycleCount = mHealthInfo.batteryCycleCount; 999 mLastBroadcastChargingState = mHealthInfo.chargingState; 1000 mLastBroadcastBatteryCapacityLevel = mHealthInfo.batteryCapacityLevel; 1001 } 1002 } 1003 } 1004 sendBatteryChangedIntentLocked(boolean forceUpdate)1005 private void sendBatteryChangedIntentLocked(boolean forceUpdate) { 1006 // Pack up the values and broadcast them to everyone 1007 final Intent intent = new Intent(Intent.ACTION_BATTERY_CHANGED); 1008 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY 1009 | Intent.FLAG_RECEIVER_REPLACE_PENDING); 1010 1011 int icon = getIconLocked(mHealthInfo.batteryLevel); 1012 1013 intent.putExtra(BatteryManager.EXTRA_SEQUENCE, mSequence); 1014 intent.putExtra(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus); 1015 intent.putExtra(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth); 1016 intent.putExtra(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent); 1017 intent.putExtra(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel); 1018 intent.putExtra(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast); 1019 intent.putExtra(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); 1020 intent.putExtra(BatteryManager.EXTRA_ICON_SMALL, icon); 1021 intent.putExtra(BatteryManager.EXTRA_PLUGGED, mPlugType); 1022 intent.putExtra(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts); 1023 intent.putExtra( 1024 BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius); 1025 intent.putExtra(BatteryManager.EXTRA_TECHNOLOGY, mHealthInfo.batteryTechnology); 1026 intent.putExtra(BatteryManager.EXTRA_INVALID_CHARGER, mInvalidCharger); 1027 intent.putExtra( 1028 BatteryManager.EXTRA_MAX_CHARGING_CURRENT, mHealthInfo.maxChargingCurrentMicroamps); 1029 intent.putExtra( 1030 BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, 1031 mHealthInfo.maxChargingVoltageMicrovolts); 1032 intent.putExtra(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); 1033 intent.putExtra(BatteryManager.EXTRA_CYCLE_COUNT, mHealthInfo.batteryCycleCount); 1034 intent.putExtra(BatteryManager.EXTRA_CHARGING_STATUS, mHealthInfo.chargingState); 1035 intent.putExtra(BatteryManager.EXTRA_CAPACITY_LEVEL, mHealthInfo.batteryCapacityLevel); 1036 if (DEBUG) { 1037 Slog.d(TAG, "Sending ACTION_BATTERY_CHANGED. scale:" + BATTERY_SCALE 1038 + ", info:" + mHealthInfo.toString()); 1039 } 1040 1041 if (com.android.server.flags.Flags.consolidateBatteryChangeEvents()) { 1042 mHandler.removeMessages(MSG_BROADCAST_BATTERY_CHANGED); 1043 final SomeArgs args = SomeArgs.obtain(); 1044 args.arg1 = mContext; 1045 args.arg2 = intent; 1046 args.arg3 = forceUpdate; 1047 mHandler.obtainMessage(MSG_BROADCAST_BATTERY_CHANGED, args).sendToTarget(); 1048 } else { 1049 mHandler.post(() -> broadcastBatteryChangedIntent(mContext, 1050 intent, BATTERY_CHANGED_OPTIONS, forceUpdate)); 1051 } 1052 } 1053 broadcastBatteryChangedIntent(Context context, Intent intent, Bundle options, boolean forceUpdate)1054 private static void broadcastBatteryChangedIntent(Context context, Intent intent, 1055 Bundle options, boolean forceUpdate) { 1056 traceBatteryChangedBroadcastEvent(intent, forceUpdate); 1057 // TODO (293959093): It is important that SystemUI receives this broadcast as soon as 1058 // possible. Ideally, it should be using binder callbacks but until then, dispatch this 1059 // as a foreground broadcast to SystemUI. 1060 final Intent fgIntent = new Intent(intent); 1061 fgIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 1062 fgIntent.setPackage(sSystemUiPackage); 1063 if (com.android.server.flags.Flags.pkgTargetedBatteryChangedNotSticky()) { 1064 context.sendBroadcastAsUser(fgIntent, UserHandle.ALL, null, options); 1065 } else { 1066 ActivityManager.broadcastStickyIntent(fgIntent, AppOpsManager.OP_NONE, 1067 options, UserHandle.USER_ALL); 1068 } 1069 1070 ActivityManager.broadcastStickyIntent(intent, new String[] {sSystemUiPackage}, 1071 AppOpsManager.OP_NONE, options, UserHandle.USER_ALL); 1072 } 1073 traceBatteryChangedBroadcastEvent(Intent intent, boolean forceUpdate)1074 private static void traceBatteryChangedBroadcastEvent(Intent intent, boolean forceUpdate) { 1075 if (!com.android.server.flags.Flags.traceBatteryChangedBroadcastEvent()) { 1076 return; 1077 } 1078 if (!Trace.isTagEnabled(Trace.TRACE_TAG_SYSTEM_SERVER)) return; 1079 1080 final StringBuilder builder = new StringBuilder(); 1081 builder.append("broadcastBatteryChanged; "); 1082 builder.append("force="); builder.append(forceUpdate); 1083 builder.append(",seq="); builder.append(intent.getIntExtra( 1084 BatteryManager.EXTRA_SEQUENCE, -1)); 1085 builder.append(",s="); builder.append(intent.getIntExtra( 1086 BatteryManager.EXTRA_STATUS, -1)); 1087 builder.append(",h="); builder.append(intent.getIntExtra( 1088 BatteryManager.EXTRA_HEALTH, -1)); 1089 builder.append(",p="); builder.append(intent.getBooleanExtra( 1090 BatteryManager.EXTRA_PRESENT, false)); 1091 builder.append(",l="); builder.append(intent.getIntExtra( 1092 BatteryManager.EXTRA_LEVEL, -1)); 1093 builder.append(",bl="); builder.append(intent.getBooleanExtra( 1094 BatteryManager.EXTRA_BATTERY_LOW, false)); 1095 builder.append(",sc="); builder.append(intent.getIntExtra( 1096 BatteryManager.EXTRA_SCALE, -1)); 1097 builder.append(",pt="); builder.append(intent.getIntExtra( 1098 BatteryManager.EXTRA_PLUGGED, -1)); 1099 builder.append(",v="); builder.append(intent.getIntExtra( 1100 BatteryManager.EXTRA_VOLTAGE, -1)); 1101 builder.append(",t="); builder.append(intent.getIntExtra( 1102 BatteryManager.EXTRA_TEMPERATURE, -1)); 1103 builder.append(",tech="); builder.append(intent.getStringExtra( 1104 BatteryManager.EXTRA_TECHNOLOGY)); 1105 builder.append(",invc="); builder.append(intent.getIntExtra( 1106 BatteryManager.EXTRA_INVALID_CHARGER, -1)); 1107 builder.append(",mcc="); builder.append(intent.getIntExtra( 1108 BatteryManager.EXTRA_MAX_CHARGING_CURRENT, -1)); 1109 builder.append(",mcv="); builder.append(intent.getIntExtra( 1110 BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE, -1)); 1111 builder.append(",chc="); builder.append(intent.getIntExtra( 1112 BatteryManager.EXTRA_CHARGE_COUNTER, -1)); 1113 builder.append(",cc="); builder.append(intent.getIntExtra( 1114 BatteryManager.EXTRA_CYCLE_COUNT, -1)); 1115 builder.append(",chs="); builder.append(intent.getIntExtra( 1116 BatteryManager.EXTRA_CHARGING_STATUS, -1)); 1117 1118 Trace.instant(Trace.TRACE_TAG_SYSTEM_SERVER, builder.toString()); 1119 } 1120 sendBatteryLevelChangedIntentLocked()1121 private void sendBatteryLevelChangedIntentLocked() { 1122 Bundle event = new Bundle(); 1123 long now = SystemClock.elapsedRealtime(); 1124 event.putInt(BatteryManager.EXTRA_SEQUENCE, mSequence); 1125 event.putInt(BatteryManager.EXTRA_STATUS, mHealthInfo.batteryStatus); 1126 event.putInt(BatteryManager.EXTRA_HEALTH, mHealthInfo.batteryHealth); 1127 event.putBoolean(BatteryManager.EXTRA_PRESENT, mHealthInfo.batteryPresent); 1128 event.putInt(BatteryManager.EXTRA_LEVEL, mHealthInfo.batteryLevel); 1129 event.putBoolean(BatteryManager.EXTRA_BATTERY_LOW, mSentLowBatteryBroadcast); 1130 event.putInt(BatteryManager.EXTRA_SCALE, BATTERY_SCALE); 1131 event.putInt(BatteryManager.EXTRA_PLUGGED, mPlugType); 1132 event.putInt(BatteryManager.EXTRA_VOLTAGE, mHealthInfo.batteryVoltageMillivolts); 1133 event.putInt(BatteryManager.EXTRA_TEMPERATURE, mHealthInfo.batteryTemperatureTenthsCelsius); 1134 event.putInt(BatteryManager.EXTRA_CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); 1135 event.putLong(BatteryManager.EXTRA_EVENT_TIMESTAMP, now); 1136 event.putInt(BatteryManager.EXTRA_CYCLE_COUNT, mHealthInfo.batteryCycleCount); 1137 event.putInt(BatteryManager.EXTRA_CHARGING_STATUS, mHealthInfo.chargingState); 1138 event.putInt(BatteryManager.EXTRA_CAPACITY_LEVEL, mHealthInfo.batteryCapacityLevel); 1139 1140 boolean queueWasEmpty = mBatteryLevelsEventQueue.isEmpty(); 1141 mBatteryLevelsEventQueue.add(event); 1142 // Make sure queue is bounded and doesn't exceed intent payload limits 1143 if (mBatteryLevelsEventQueue.size() > MAX_BATTERY_LEVELS_QUEUE_SIZE) { 1144 mBatteryLevelsEventQueue.removeFirst(); 1145 } 1146 1147 if (queueWasEmpty) { 1148 // send now if last event was before throttle interval, otherwise delay 1149 long delay = now - mLastBatteryLevelChangedSentMs > BATTERY_LEVEL_CHANGE_THROTTLE_MS 1150 ? 0 : mLastBatteryLevelChangedSentMs + BATTERY_LEVEL_CHANGE_THROTTLE_MS - now; 1151 mHandler.postDelayed(this::sendEnqueuedBatteryLevelChangedEvents, delay); 1152 } 1153 } 1154 sendEnqueuedBatteryLevelChangedEvents()1155 private void sendEnqueuedBatteryLevelChangedEvents() { 1156 ArrayList<Bundle> events; 1157 synchronized (mLock) { 1158 events = new ArrayList<>(mBatteryLevelsEventQueue); 1159 mBatteryLevelsEventQueue.clear(); 1160 } 1161 final Intent intent = new Intent(Intent.ACTION_BATTERY_LEVEL_CHANGED); 1162 intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1163 intent.putParcelableArrayListExtra(BatteryManager.EXTRA_EVENTS, events); 1164 1165 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 1166 android.Manifest.permission.BATTERY_STATS); 1167 mLastBatteryLevelChangedSentMs = SystemClock.elapsedRealtime(); 1168 } 1169 notifyChargingPolicyChanged()1170 private void notifyChargingPolicyChanged() { 1171 final int newPolicy; 1172 synchronized (mLock) { 1173 newPolicy = mLastChargingPolicy; 1174 } 1175 for (BatteryManagerInternal.ChargingPolicyChangeListener listener 1176 : mChargingPolicyChangeListeners) { 1177 listener.onChargingPolicyChanged(newPolicy); 1178 } 1179 } 1180 1181 // TODO: Current code doesn't work since "--unplugged" flag in BSS was purposefully removed. logBatteryStatsLocked()1182 private void logBatteryStatsLocked() { 1183 IBinder batteryInfoService = ServiceManager.getService(BatteryStats.SERVICE_NAME); 1184 if (batteryInfoService == null) return; 1185 1186 DropBoxManager db = (DropBoxManager) mContext.getSystemService(Context.DROPBOX_SERVICE); 1187 if (db == null || !db.isTagEnabled("BATTERY_DISCHARGE_INFO")) return; 1188 1189 File dumpFile = null; 1190 FileOutputStream dumpStream = null; 1191 try { 1192 // dump the service to a file 1193 dumpFile = new File(DUMPSYS_DATA_PATH + BatteryStats.SERVICE_NAME + ".dump"); 1194 dumpStream = new FileOutputStream(dumpFile); 1195 batteryInfoService.dump(dumpStream.getFD(), DUMPSYS_ARGS); 1196 FileUtils.sync(dumpStream); 1197 1198 // add dump file to drop box 1199 db.addFile("BATTERY_DISCHARGE_INFO", dumpFile, DropBoxManager.IS_TEXT); 1200 } catch (RemoteException e) { 1201 Slog.e(TAG, "failed to dump battery service", e); 1202 } catch (IOException e) { 1203 Slog.e(TAG, "failed to write dumpsys file", e); 1204 } finally { 1205 // make sure we clean up 1206 if (dumpStream != null) { 1207 try { 1208 dumpStream.close(); 1209 } catch (IOException e) { 1210 Slog.e(TAG, "failed to close dumpsys output stream"); 1211 } 1212 } 1213 if (dumpFile != null && !dumpFile.delete()) { 1214 Slog.e(TAG, "failed to delete temporary dumpsys file: " 1215 + dumpFile.getAbsolutePath()); 1216 } 1217 } 1218 } 1219 logOutlierLocked(long duration)1220 private void logOutlierLocked(long duration) { 1221 ContentResolver cr = mContext.getContentResolver(); 1222 String dischargeThresholdString = Settings.Global.getString(cr, 1223 Settings.Global.BATTERY_DISCHARGE_THRESHOLD); 1224 String durationThresholdString = Settings.Global.getString(cr, 1225 Settings.Global.BATTERY_DISCHARGE_DURATION_THRESHOLD); 1226 1227 if (dischargeThresholdString != null && durationThresholdString != null) { 1228 try { 1229 long durationThreshold = Long.parseLong(durationThresholdString); 1230 int dischargeThreshold = Integer.parseInt(dischargeThresholdString); 1231 if (duration <= durationThreshold && 1232 mDischargeStartLevel - mHealthInfo.batteryLevel >= dischargeThreshold) { 1233 // If the discharge cycle is bad enough we want to know about it. 1234 logBatteryStatsLocked(); 1235 } 1236 if (DEBUG) Slog.v(TAG, "duration threshold: " + durationThreshold + 1237 " discharge threshold: " + dischargeThreshold); 1238 if (DEBUG) Slog.v(TAG, "duration: " + duration + " discharge: " + 1239 (mDischargeStartLevel - mHealthInfo.batteryLevel)); 1240 } catch (NumberFormatException e) { 1241 Slog.e(TAG, "Invalid DischargeThresholds GService string: " + 1242 durationThresholdString + " or " + dischargeThresholdString); 1243 } 1244 } 1245 } 1246 getIconLocked(int level)1247 private int getIconLocked(int level) { 1248 if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_CHARGING) { 1249 return com.android.internal.R.drawable.stat_sys_battery_charge; 1250 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_DISCHARGING) { 1251 return com.android.internal.R.drawable.stat_sys_battery; 1252 } else if (mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_NOT_CHARGING 1253 || mHealthInfo.batteryStatus == BatteryManager.BATTERY_STATUS_FULL) { 1254 if (isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY) 1255 && mHealthInfo.batteryLevel >= 100) { 1256 return com.android.internal.R.drawable.stat_sys_battery_charge; 1257 } else { 1258 return com.android.internal.R.drawable.stat_sys_battery; 1259 } 1260 } else { 1261 return com.android.internal.R.drawable.stat_sys_battery_unknown; 1262 } 1263 } 1264 1265 /** 1266 * Rate limit's the broadcast based on the changes in temp, voltage and chargeCounter. 1267 */ rateLimitBatteryChangedBroadcast(boolean forceUpdate)1268 private boolean rateLimitBatteryChangedBroadcast(boolean forceUpdate) { 1269 if (!com.android.server.flags.Flags.rateLimitBatteryChangedBroadcast()) { 1270 return false; 1271 } 1272 if (mIsFirstBatteryChangedUpdate) { 1273 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); 1274 mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime(); 1275 mIsFirstBatteryChangedUpdate = false; 1276 return false; 1277 } 1278 1279 final boolean voltageUpdated = 1280 mLastBroadcastBatteryVoltage != mHealthInfo.batteryVoltageMillivolts; 1281 final boolean temperatureUpdated = 1282 mLastBroadcastBatteryTemperature != mHealthInfo.batteryTemperatureTenthsCelsius; 1283 final boolean maxChargingCurrentUpdated = 1284 mLastBroadcastMaxChargingCurrent != mHealthInfo.maxChargingCurrentMicroamps; 1285 final boolean otherStatesUpdated = forceUpdate 1286 || mHealthInfo.batteryStatus != mLastBroadcastBatteryStatus 1287 || mHealthInfo.batteryHealth != mLastBroadcastBatteryHealth 1288 || mHealthInfo.batteryPresent != mLastBroadcastBatteryPresent 1289 || mHealthInfo.batteryLevel != mLastBroadcastBatteryLevel 1290 || mPlugType != mLastBroadcastPlugType 1291 || mHealthInfo.maxChargingVoltageMicrovolts != mLastBroadcastMaxChargingVoltage 1292 || mInvalidCharger != mLastBroadcastInvalidCharger 1293 || mHealthInfo.batteryCycleCount != mLastBroadcastBatteryCycleCount 1294 || mHealthInfo.chargingState != mLastBroadcastChargingState 1295 || mHealthInfo.batteryCapacityLevel != mLastBroadcastBatteryCapacityLevel; 1296 1297 // We only rate limit based on changes in the temp, voltage. 1298 if (otherStatesUpdated) { 1299 1300 if (voltageUpdated) { 1301 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); 1302 } 1303 if (maxChargingCurrentUpdated) { 1304 mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime(); 1305 } 1306 return false; 1307 } 1308 1309 final float basePointDiff = 1310 (float) (mLastBroadcastBatteryVoltage - mHealthInfo.batteryVoltageMillivolts) 1311 / mLastBroadcastBatteryVoltage; 1312 1313 // We only send the broadcast if voltage change is greater than 1% and last voltage 1314 // update was sent at least 20 seconds back. 1315 if (voltageUpdated 1316 && abs(basePointDiff) >= BASE_POINT_DIFF_FOR_VOLTAGE_UPDATE 1317 && SystemClock.elapsedRealtime() - mLastBroadcastVoltageUpdateTime 1318 >= TIME_DIFF_FOR_VOLTAGE_UPDATE_MS) { 1319 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); 1320 1321 if (maxChargingCurrentUpdated) { 1322 mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime(); 1323 } 1324 return false; 1325 } 1326 1327 // Only send the broadcast if the temperature update is greater than 1 degree celsius. 1328 if (temperatureUpdated 1329 && abs( 1330 mLastBroadcastBatteryTemperature - mHealthInfo.batteryTemperatureTenthsCelsius) 1331 >= ABSOLUTE_DECI_CELSIUS_DIFF_FOR_TEMP_UPDATE) { 1332 1333 if (voltageUpdated) { 1334 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); 1335 } 1336 if (maxChargingCurrentUpdated) { 1337 mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime(); 1338 } 1339 return false; 1340 } 1341 1342 if (maxChargingCurrentUpdated 1343 && SystemClock.elapsedRealtime() - mLastBroadcastMaxChargingCurrentUpdateTime 1344 >= TIME_DIFF_FOR_MAX_CHARGING_CURRENT_UPDATE_MS) { 1345 mLastBroadcastMaxChargingCurrentUpdateTime = SystemClock.elapsedRealtime(); 1346 1347 if (voltageUpdated) { 1348 mLastBroadcastVoltageUpdateTime = SystemClock.elapsedRealtime(); 1349 } 1350 return false; 1351 } 1352 1353 return true; 1354 } 1355 1356 class Shell extends ShellCommand { 1357 @Override onCommand(String cmd)1358 public int onCommand(String cmd) { 1359 return onShellCommand(this, cmd); 1360 } 1361 1362 @Override onHelp()1363 public void onHelp() { 1364 PrintWriter pw = getOutPrintWriter(); 1365 dumpHelp(pw); 1366 } 1367 } 1368 dumpHelp(PrintWriter pw)1369 static void dumpHelp(PrintWriter pw) { 1370 pw.println("Battery service (battery) commands:"); 1371 pw.println(" help"); 1372 pw.println(" Print this help text."); 1373 String getSetOptions = "ac|usb|wireless|dock|status|level|temp|present|counter|invalid"; 1374 if (batteryServiceSupportCurrentAdbCommand()) { 1375 getSetOptions += "|current_now|current_average"; 1376 } 1377 pw.println(" get [-f] [" + getSetOptions + "]"); 1378 pw.println(" Gets the value of a battery state."); 1379 pw.println(" -f: force to get the latest property value."); 1380 pw.println(" set [-f] [" + getSetOptions + "] <value>"); 1381 pw.println(" Force a battery property value, freezing battery state."); 1382 pw.println(" -f: force a battery change broadcast be sent, prints new sequence."); 1383 pw.println(" unplug [-f]"); 1384 pw.println(" Force battery unplugged, freezing battery state."); 1385 pw.println(" -f: force a battery change broadcast be sent, prints new sequence."); 1386 pw.println(" reset [-f]"); 1387 pw.println(" Unfreeze battery state, returning to current hardware values."); 1388 pw.println(" -f: force a battery change broadcast be sent, prints new sequence."); 1389 if (Build.IS_DEBUGGABLE) { 1390 pw.println(" suspend_input"); 1391 pw.println(" Suspend charging even if plugged in. "); 1392 } 1393 } 1394 1395 static final int OPTION_FORCE_UPDATE = 1<<0; 1396 parseOptions(Shell shell)1397 int parseOptions(Shell shell) { 1398 String opt; 1399 int opts = 0; 1400 while ((opt = shell.getNextOption()) != null) { 1401 if ("-f".equals(opt)) { 1402 opts |= OPTION_FORCE_UPDATE; 1403 } 1404 } 1405 return opts; 1406 } 1407 onShellCommand(Shell shell, String cmd)1408 int onShellCommand(Shell shell, String cmd) { 1409 if (cmd == null) { 1410 return shell.handleDefaultCommands(cmd); 1411 } 1412 PrintWriter pw = shell.getOutPrintWriter(); 1413 switch (cmd) { 1414 case "unplug": { 1415 int opts = parseOptions(shell); 1416 getContext().enforceCallingOrSelfPermission( 1417 android.Manifest.permission.DEVICE_POWER, null); 1418 unplugBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); 1419 } break; 1420 case "get": { 1421 final int opts = parseOptions(shell); 1422 final String key = shell.getNextArg(); 1423 if (key == null) { 1424 pw.println("No property specified"); 1425 return -1; 1426 } 1427 1428 // Update the health info. 1429 if ((opts & OPTION_FORCE_UPDATE) != 0) { 1430 mConditionVariable.close(); 1431 updateHealthInfo(); 1432 mConditionVariable.block(HEALTH_HAL_WAIT_MS); 1433 } 1434 1435 switch (key) { 1436 case "present": 1437 pw.println(mHealthInfo.batteryPresent); 1438 break; 1439 case "ac": 1440 pw.println(mHealthInfo.chargerAcOnline); 1441 break; 1442 case "usb": 1443 pw.println(mHealthInfo.chargerUsbOnline); 1444 break; 1445 case "wireless": 1446 pw.println(mHealthInfo.chargerWirelessOnline); 1447 break; 1448 case "dock": 1449 pw.println(mHealthInfo.chargerDockOnline); 1450 break; 1451 case "status": 1452 pw.println(mHealthInfo.batteryStatus); 1453 break; 1454 case "level": 1455 pw.println(mHealthInfo.batteryLevel); 1456 break; 1457 case "counter": 1458 pw.println(mHealthInfo.batteryChargeCounterUah); 1459 break; 1460 case "current_now": 1461 if (batteryServiceSupportCurrentAdbCommand()) { 1462 pw.println(mHealthInfo.batteryCurrentMicroamps); 1463 } 1464 break; 1465 case "current_average": 1466 if (batteryServiceSupportCurrentAdbCommand()) { 1467 pw.println(mHealthInfo.batteryCurrentAverageMicroamps); 1468 } 1469 break; 1470 case "temp": 1471 pw.println(mHealthInfo.batteryTemperatureTenthsCelsius); 1472 break; 1473 case "invalid": 1474 pw.println(mInvalidCharger); 1475 break; 1476 default: 1477 pw.println("Unknown get option: " + key); 1478 break; 1479 } 1480 } break; 1481 case "set": { 1482 int opts = parseOptions(shell); 1483 getContext().enforceCallingOrSelfPermission( 1484 android.Manifest.permission.DEVICE_POWER, null); 1485 final String key = shell.getNextArg(); 1486 if (key == null) { 1487 pw.println("No property specified"); 1488 return -1; 1489 1490 } 1491 final String value = shell.getNextArg(); 1492 if (value == null) { 1493 pw.println("No value specified"); 1494 return -1; 1495 1496 } 1497 try { 1498 if (!mUpdatesStopped) { 1499 copyV1Battery(mLastHealthInfo, mHealthInfo); 1500 } 1501 boolean update = true; 1502 switch (key) { 1503 case "present": 1504 mHealthInfo.batteryPresent = Integer.parseInt(value) != 0; 1505 break; 1506 case "ac": 1507 mHealthInfo.chargerAcOnline = Integer.parseInt(value) != 0; 1508 break; 1509 case "usb": 1510 mHealthInfo.chargerUsbOnline = Integer.parseInt(value) != 0; 1511 break; 1512 case "wireless": 1513 mHealthInfo.chargerWirelessOnline = Integer.parseInt(value) != 0; 1514 break; 1515 case "dock": 1516 mHealthInfo.chargerDockOnline = Integer.parseInt(value) != 0; 1517 break; 1518 case "status": 1519 mHealthInfo.batteryStatus = Integer.parseInt(value); 1520 break; 1521 case "level": 1522 mHealthInfo.batteryLevel = Integer.parseInt(value); 1523 break; 1524 case "counter": 1525 mHealthInfo.batteryChargeCounterUah = Integer.parseInt(value); 1526 break; 1527 case "current_now": 1528 if (batteryServiceSupportCurrentAdbCommand()) { 1529 mHealthInfo.batteryCurrentMicroamps = Integer.parseInt(value); 1530 } 1531 break; 1532 case "current_average": 1533 if (batteryServiceSupportCurrentAdbCommand()) { 1534 mHealthInfo.batteryCurrentAverageMicroamps = 1535 Integer.parseInt(value); 1536 } 1537 case "temp": 1538 mHealthInfo.batteryTemperatureTenthsCelsius = Integer.parseInt(value); 1539 break; 1540 case "invalid": 1541 mInvalidCharger = Integer.parseInt(value); 1542 break; 1543 default: 1544 pw.println("Unknown set option: " + key); 1545 update = false; 1546 break; 1547 } 1548 if (update) { 1549 final long ident = Binder.clearCallingIdentity(); 1550 try { 1551 mUpdatesStopped = true; 1552 processValuesLocked( 1553 /* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); 1554 } finally { 1555 Binder.restoreCallingIdentity(ident); 1556 } 1557 } 1558 } catch (NumberFormatException ex) { 1559 pw.println("Bad value: " + value); 1560 return -1; 1561 } 1562 } break; 1563 case "reset": { 1564 int opts = parseOptions(shell); 1565 getContext().enforceCallingOrSelfPermission( 1566 android.Manifest.permission.DEVICE_POWER, null); 1567 resetBattery(/* forceUpdate= */ (opts & OPTION_FORCE_UPDATE) != 0, pw); 1568 } break; 1569 case "suspend_input": { 1570 getContext().enforceCallingOrSelfPermission( 1571 android.Manifest.permission.DEVICE_POWER, null); 1572 suspendBatteryInput(); 1573 } break; 1574 default: 1575 return shell.handleDefaultCommands(cmd); 1576 } 1577 return 0; 1578 } 1579 updateHealthInfo()1580 private void updateHealthInfo() { 1581 try { 1582 mHealthServiceWrapper.scheduleUpdate(); 1583 } catch (RemoteException e) { 1584 Slog.e(TAG, "Unable to update health service data.", e); 1585 } 1586 } 1587 setChargerAcOnline(boolean online, boolean forceUpdate)1588 private void setChargerAcOnline(boolean online, boolean forceUpdate) { 1589 if (!mUpdatesStopped) { 1590 copyV1Battery(mLastHealthInfo, mHealthInfo); 1591 } 1592 mHealthInfo.chargerAcOnline = online; 1593 mUpdatesStopped = true; 1594 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate)); 1595 } 1596 setBatteryLevel(int level, boolean forceUpdate)1597 private void setBatteryLevel(int level, boolean forceUpdate) { 1598 if (!mUpdatesStopped) { 1599 copyV1Battery(mLastHealthInfo, mHealthInfo); 1600 } 1601 mHealthInfo.batteryLevel = level; 1602 mUpdatesStopped = true; 1603 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate)); 1604 } 1605 unplugBattery(boolean forceUpdate, PrintWriter pw)1606 private void unplugBattery(boolean forceUpdate, PrintWriter pw) { 1607 if (!mUpdatesStopped) { 1608 copyV1Battery(mLastHealthInfo, mHealthInfo); 1609 } 1610 mHealthInfo.chargerAcOnline = false; 1611 mHealthInfo.chargerUsbOnline = false; 1612 mHealthInfo.chargerWirelessOnline = false; 1613 mHealthInfo.chargerDockOnline = false; 1614 mUpdatesStopped = true; 1615 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); 1616 } 1617 resetBattery(boolean forceUpdate, @Nullable PrintWriter pw)1618 private void resetBattery(boolean forceUpdate, @Nullable PrintWriter pw) { 1619 if (mUpdatesStopped) { 1620 mUpdatesStopped = false; 1621 copyV1Battery(mHealthInfo, mLastHealthInfo); 1622 Binder.withCleanCallingIdentity(() -> processValuesLocked(forceUpdate, pw)); 1623 } 1624 if (mBatteryInputSuspended) { 1625 PowerProperties.battery_input_suspended(false); 1626 mBatteryInputSuspended = false; 1627 } 1628 } 1629 suspendBatteryInput()1630 private void suspendBatteryInput() { 1631 if (!Build.IS_DEBUGGABLE) { 1632 throw new SecurityException( 1633 "battery suspend_input is only supported on debuggable builds"); 1634 } 1635 PowerProperties.battery_input_suspended(true); 1636 mBatteryInputSuspended = true; 1637 } 1638 processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw)1639 private void processValuesLocked(boolean forceUpdate, @Nullable PrintWriter pw) { 1640 processValuesLocked(forceUpdate); 1641 if (pw != null && forceUpdate) { 1642 pw.println(mSequence); 1643 } 1644 } 1645 dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args)1646 private void dumpInternal(FileDescriptor fd, PrintWriter pw, String[] args) { 1647 synchronized (mLock) { 1648 if (args == null || args.length == 0 || "-a".equals(args[0])) { 1649 pw.println("Current Battery Service state:"); 1650 if (mUpdatesStopped) { 1651 pw.println(" (UPDATES STOPPED -- use 'reset' to restart)"); 1652 } 1653 pw.println(" AC powered: " + mHealthInfo.chargerAcOnline); 1654 pw.println(" USB powered: " + mHealthInfo.chargerUsbOnline); 1655 pw.println(" Wireless powered: " + mHealthInfo.chargerWirelessOnline); 1656 pw.println(" Dock powered: " + mHealthInfo.chargerDockOnline); 1657 pw.println(" Max charging current: " + mHealthInfo.maxChargingCurrentMicroamps); 1658 pw.println(" Time when the latest updated value of the Max charging current was" 1659 + " sent via battery changed broadcast: " 1660 + TimeUtils.formatDuration(mLastBroadcastMaxChargingCurrentUpdateTime)); 1661 pw.println(" Max charging voltage: " + mHealthInfo.maxChargingVoltageMicrovolts); 1662 pw.println(" Charge counter: " + mHealthInfo.batteryChargeCounterUah); 1663 pw.println(" status: " + mHealthInfo.batteryStatus); 1664 pw.println(" health: " + mHealthInfo.batteryHealth); 1665 pw.println(" present: " + mHealthInfo.batteryPresent); 1666 pw.println(" level: " + mHealthInfo.batteryLevel); 1667 pw.println(" scale: " + BATTERY_SCALE); 1668 pw.println(" voltage: " + mHealthInfo.batteryVoltageMillivolts); 1669 pw.println(" Time when the latest updated value of the voltage was sent via " 1670 + "battery changed broadcast: " 1671 + TimeUtils.formatDuration(mLastBroadcastVoltageUpdateTime)); 1672 pw.println(" The last voltage value sent via the battery changed broadcast: " 1673 + mLastBroadcastBatteryVoltage); 1674 pw.println(" temperature: " + mHealthInfo.batteryTemperatureTenthsCelsius); 1675 pw.println(" technology: " + mHealthInfo.batteryTechnology); 1676 pw.println(" Charging state: " + mHealthInfo.chargingState); 1677 pw.println(" Charging policy: " + mHealthInfo.chargingPolicy); 1678 pw.println(" Capacity level: " + mHealthInfo.batteryCapacityLevel); 1679 } else { 1680 Shell shell = new Shell(); 1681 shell.exec(mBinderService, null, fd, null, args, null, new ResultReceiver(null)); 1682 } 1683 } 1684 } 1685 dumpProto(FileDescriptor fd)1686 private void dumpProto(FileDescriptor fd) { 1687 final ProtoOutputStream proto = new ProtoOutputStream(fd); 1688 1689 synchronized (mLock) { 1690 proto.write(BatteryServiceDumpProto.ARE_UPDATES_STOPPED, mUpdatesStopped); 1691 int batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_NONE; 1692 if (mHealthInfo.chargerAcOnline) { 1693 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_AC; 1694 } else if (mHealthInfo.chargerUsbOnline) { 1695 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_USB; 1696 } else if (mHealthInfo.chargerWirelessOnline) { 1697 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_WIRELESS; 1698 } else if (mHealthInfo.chargerDockOnline) { 1699 batteryPluggedValue = OsProtoEnums.BATTERY_PLUGGED_DOCK; 1700 } 1701 proto.write(BatteryServiceDumpProto.PLUGGED, batteryPluggedValue); 1702 proto.write( 1703 BatteryServiceDumpProto.MAX_CHARGING_CURRENT, 1704 mHealthInfo.maxChargingCurrentMicroamps); 1705 proto.write( 1706 BatteryServiceDumpProto.MAX_CHARGING_VOLTAGE, 1707 mHealthInfo.maxChargingVoltageMicrovolts); 1708 proto.write( 1709 BatteryServiceDumpProto.CHARGE_COUNTER, mHealthInfo.batteryChargeCounterUah); 1710 proto.write(BatteryServiceDumpProto.STATUS, mHealthInfo.batteryStatus); 1711 proto.write(BatteryServiceDumpProto.HEALTH, mHealthInfo.batteryHealth); 1712 proto.write(BatteryServiceDumpProto.IS_PRESENT, mHealthInfo.batteryPresent); 1713 proto.write(BatteryServiceDumpProto.LEVEL, mHealthInfo.batteryLevel); 1714 proto.write(BatteryServiceDumpProto.SCALE, BATTERY_SCALE); 1715 proto.write(BatteryServiceDumpProto.VOLTAGE, mHealthInfo.batteryVoltageMillivolts); 1716 proto.write( 1717 BatteryServiceDumpProto.TEMPERATURE, 1718 mHealthInfo.batteryTemperatureTenthsCelsius); 1719 proto.write(BatteryServiceDumpProto.TECHNOLOGY, mHealthInfo.batteryTechnology); 1720 } 1721 proto.flush(); 1722 } 1723 traceBegin(String name)1724 private static void traceBegin(String name) { 1725 Trace.traceBegin(Trace.TRACE_TAG_SYSTEM_SERVER, name); 1726 } 1727 traceEnd()1728 private static void traceEnd() { 1729 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); 1730 } 1731 1732 @VisibleForTesting getHandlerForTest()1733 public Handler getHandlerForTest() { 1734 return mHandler; 1735 } 1736 1737 @SuppressLint("AndroidFrameworkRequiresPermission") sendBroadcastToAllUsers(Context context, Intent intent, Bundle options)1738 private static void sendBroadcastToAllUsers(Context context, Intent intent, 1739 Bundle options) { 1740 context.sendBroadcastAsUser(intent, UserHandle.ALL, null, options); 1741 } 1742 1743 private final class Led { 1744 // must match: config_notificationsBatteryLowBehavior in config.xml 1745 static final int LOW_BATTERY_BEHAVIOR_DEFAULT = 0; 1746 static final int LOW_BATTERY_BEHAVIOR_SOLID = 1; 1747 static final int LOW_BATTERY_BEHAVIOR_FLASHING = 2; 1748 1749 private final LogicalLight mBatteryLight; 1750 1751 private final int mBatteryLowARGB; 1752 private final int mBatteryMediumARGB; 1753 private final int mBatteryFullARGB; 1754 private final int mBatteryLedOn; 1755 private final int mBatteryLedOff; 1756 private final int mBatteryLowBehavior; 1757 Led(Context context, LightsManager lights)1758 public Led(Context context, LightsManager lights) { 1759 mBatteryLight = lights.getLight(LightsManager.LIGHT_ID_BATTERY); 1760 1761 mBatteryLowARGB = context.getResources().getInteger( 1762 com.android.internal.R.integer.config_notificationsBatteryLowARGB); 1763 mBatteryMediumARGB = context.getResources().getInteger( 1764 com.android.internal.R.integer.config_notificationsBatteryMediumARGB); 1765 mBatteryFullARGB = context.getResources().getInteger( 1766 com.android.internal.R.integer.config_notificationsBatteryFullARGB); 1767 mBatteryLedOn = context.getResources().getInteger( 1768 com.android.internal.R.integer.config_notificationsBatteryLedOn); 1769 mBatteryLedOff = context.getResources().getInteger( 1770 com.android.internal.R.integer.config_notificationsBatteryLedOff); 1771 mBatteryNearlyFullLevel = context.getResources().getInteger( 1772 com.android.internal.R.integer.config_notificationsBatteryNearlyFullLevel); 1773 mBatteryLowBehavior = context.getResources().getInteger( 1774 com.android.internal.R.integer.config_notificationsBatteryLowBehavior); 1775 } 1776 1777 /** 1778 * Synchronize on BatteryService. 1779 */ updateLightsLocked()1780 public void updateLightsLocked() { 1781 if (mBatteryLight == null) { 1782 return; 1783 } 1784 final int level = mHealthInfo.batteryLevel; 1785 final int status = mHealthInfo.batteryStatus; 1786 if (level < mLowBatteryWarningLevel) { 1787 switch (mBatteryLowBehavior) { 1788 case LOW_BATTERY_BEHAVIOR_SOLID: 1789 // Solid red when low battery 1790 mBatteryLight.setColor(mBatteryLowARGB); 1791 break; 1792 case LOW_BATTERY_BEHAVIOR_FLASHING: 1793 // Flash red when battery is low and not charging 1794 mBatteryLight.setFlashing(mBatteryLowARGB, LogicalLight.LIGHT_FLASH_TIMED, 1795 mBatteryLedOn, mBatteryLedOff); 1796 break; 1797 default: 1798 if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 1799 // Solid red when battery is charging 1800 mBatteryLight.setColor(mBatteryLowARGB); 1801 } else { 1802 // Flash red when battery is low and not charging 1803 mBatteryLight.setFlashing(mBatteryLowARGB, 1804 LogicalLight.LIGHT_FLASH_TIMED, mBatteryLedOn, mBatteryLedOff); 1805 } 1806 break; 1807 } 1808 } else if (status == BatteryManager.BATTERY_STATUS_CHARGING 1809 || status == BatteryManager.BATTERY_STATUS_FULL) { 1810 if (status == BatteryManager.BATTERY_STATUS_FULL 1811 || level >= mBatteryNearlyFullLevel) { 1812 // Solid green when full or charging and nearly full 1813 mBatteryLight.setColor(mBatteryFullARGB); 1814 } else { 1815 // Solid orange when charging and halfway full 1816 mBatteryLight.setColor(mBatteryMediumARGB); 1817 } 1818 } else { 1819 // No lights if not charging and not low 1820 mBatteryLight.turnOff(); 1821 } 1822 } 1823 } 1824 1825 private final class BinderService extends Binder { dump(FileDescriptor fd, PrintWriter pw, String[] args)1826 @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1827 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; 1828 1829 if (args.length > 0 && "--proto".equals(args[0])) { 1830 dumpProto(fd); 1831 } else { 1832 dumpInternal(fd, pw, args); 1833 } 1834 } 1835 onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)1836 @Override public void onShellCommand(FileDescriptor in, FileDescriptor out, 1837 FileDescriptor err, String[] args, ShellCallback callback, 1838 ResultReceiver resultReceiver) { 1839 (new Shell()).exec(this, in, out, err, args, callback, resultReceiver); 1840 } 1841 } 1842 1843 // Reduced IBatteryPropertiesRegistrar that implements getProperty for usage 1844 // in BatteryManager and enforce permissions. 1845 private final class BatteryPropertiesRegistrar extends IBatteryPropertiesRegistrar.Stub { 1846 @Override getProperty(int id, final BatteryProperty prop)1847 public int getProperty(int id, final BatteryProperty prop) throws RemoteException { 1848 switch (id) { 1849 case BatteryManager.BATTERY_PROPERTY_STATE_OF_HEALTH: 1850 if (stateOfHealthPublic()) { 1851 break; 1852 } 1853 1854 case BatteryManager.BATTERY_PROPERTY_MANUFACTURING_DATE: 1855 case BatteryManager.BATTERY_PROPERTY_FIRST_USAGE_DATE: 1856 case BatteryManager.BATTERY_PROPERTY_CHARGING_POLICY: 1857 case BatteryManager.BATTERY_PROPERTY_SERIAL_NUMBER: 1858 case BatteryManager.BATTERY_PROPERTY_PART_STATUS: 1859 mContext.enforceCallingPermission( 1860 android.Manifest.permission.BATTERY_STATS, null); 1861 break; 1862 } 1863 return mHealthServiceWrapper.getProperty(id, prop); 1864 } 1865 @Override scheduleUpdate()1866 public void scheduleUpdate() throws RemoteException { 1867 mHealthServiceWrapper.scheduleUpdate(); 1868 } 1869 } 1870 1871 private final class LocalService extends BatteryManagerInternal { 1872 @Override isPowered(int plugTypeSet)1873 public boolean isPowered(int plugTypeSet) { 1874 synchronized (mLock) { 1875 return isPoweredLocked(plugTypeSet); 1876 } 1877 } 1878 1879 @Override getPlugType()1880 public int getPlugType() { 1881 synchronized (mLock) { 1882 return mPlugType; 1883 } 1884 } 1885 1886 @Override getBatteryLevel()1887 public int getBatteryLevel() { 1888 synchronized (mLock) { 1889 return mHealthInfo.batteryLevel; 1890 } 1891 } 1892 1893 @Override getBatteryChargeCounter()1894 public int getBatteryChargeCounter() { 1895 synchronized (mLock) { 1896 return mHealthInfo.batteryChargeCounterUah; 1897 } 1898 } 1899 1900 @Override getBatteryFullCharge()1901 public int getBatteryFullCharge() { 1902 synchronized (mLock) { 1903 return mHealthInfo.batteryFullChargeUah; 1904 } 1905 } 1906 1907 @Override getBatteryHealth()1908 public int getBatteryHealth() { 1909 synchronized (mLock) { 1910 return mHealthInfo.batteryHealth; 1911 } 1912 } 1913 1914 @Override getBatteryLevelLow()1915 public boolean getBatteryLevelLow() { 1916 synchronized (mLock) { 1917 return mBatteryLevelLow; 1918 } 1919 } 1920 1921 @Override registerChargingPolicyChangeListener( BatteryManagerInternal.ChargingPolicyChangeListener listener)1922 public void registerChargingPolicyChangeListener( 1923 BatteryManagerInternal.ChargingPolicyChangeListener listener) { 1924 mChargingPolicyChangeListeners.add(listener); 1925 } 1926 1927 @Override getChargingPolicy()1928 public int getChargingPolicy() { 1929 synchronized (mLock) { 1930 return mLastChargingPolicy; 1931 } 1932 } 1933 1934 @Override getInvalidCharger()1935 public int getInvalidCharger() { 1936 synchronized (mLock) { 1937 return mInvalidCharger; 1938 } 1939 } 1940 1941 @Override setChargerAcOnline(boolean online, boolean forceUpdate)1942 public void setChargerAcOnline(boolean online, boolean forceUpdate) { 1943 BatteryService.this.setChargerAcOnline(online, forceUpdate); 1944 } 1945 1946 @Override setBatteryLevel(int level, boolean forceUpdate)1947 public void setBatteryLevel(int level, boolean forceUpdate) { 1948 BatteryService.this.setBatteryLevel(level, forceUpdate); 1949 } 1950 1951 @Override unplugBattery(boolean forceUpdate)1952 public void unplugBattery(boolean forceUpdate) { 1953 BatteryService.this.unplugBattery(forceUpdate, /* printWriter= */ null); 1954 } 1955 1956 @Override resetBattery(boolean forceUpdate)1957 public void resetBattery(boolean forceUpdate) { 1958 BatteryService.this.resetBattery(forceUpdate, /* printWriter= */ null); 1959 } 1960 1961 @Override suspendBatteryInput()1962 public void suspendBatteryInput() { 1963 BatteryService.this.suspendBatteryInput(); 1964 } 1965 } 1966 } 1967