1 /* 2 * Copyright (C) 2022 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.settings.fuelgauge.batteryusage; 18 19 import android.app.AppGlobals; 20 import android.content.Context; 21 import android.content.pm.ApplicationInfo; 22 import android.content.pm.IPackageManager; 23 import android.content.pm.PackageInfo; 24 import android.content.pm.PackageManager; 25 import android.content.pm.PackageManager.NameNotFoundException; 26 import android.content.pm.UserInfo; 27 import android.graphics.drawable.Drawable; 28 import android.os.BatteryConsumer; 29 import android.os.BatteryConsumer.Dimensions; 30 import android.os.Process; 31 import android.os.RemoteException; 32 import android.os.UidBatteryConsumer; 33 import android.os.UserBatteryConsumer; 34 import android.os.UserHandle; 35 import android.os.UserManager; 36 import android.util.DebugUtils; 37 import android.util.Log; 38 39 import com.android.settings.R; 40 import com.android.settings.fuelgauge.BatteryUtils; 41 import com.android.settingslib.Utils; 42 43 import java.util.Comparator; 44 import java.util.HashMap; 45 import java.util.Locale; 46 47 /** 48 * Wraps the power usage data of a BatterySipper with information about package name 49 * and icon image. 50 */ 51 public class BatteryEntry { 52 53 /** The app name and icon in app list. */ 54 public static final class NameAndIcon { 55 public final String mName; 56 public final String mPackageName; 57 public final Drawable mIcon; 58 public final int mIconId; 59 NameAndIcon(String name, Drawable icon, int iconId)60 public NameAndIcon(String name, Drawable icon, int iconId) { 61 this(name, /*packageName=*/ null, icon, iconId); 62 } 63 NameAndIcon( String name, String packageName, Drawable icon, int iconId)64 public NameAndIcon( 65 String name, String packageName, Drawable icon, int iconId) { 66 this.mName = name; 67 this.mIcon = icon; 68 this.mIconId = iconId; 69 this.mPackageName = packageName; 70 } 71 } 72 73 private static final String TAG = "BatteryEntry"; 74 private static final String PACKAGE_SYSTEM = "android"; 75 76 static final int BATTERY_USAGE_INDEX_FOREGROUND = 0; 77 static final int BATTERY_USAGE_INDEX_FOREGROUND_SERVICE = 1; 78 static final int BATTERY_USAGE_INDEX_BACKGROUND = 2; 79 static final int BATTERY_USAGE_INDEX_CACHED = 3; 80 81 static final Dimensions[] BATTERY_DIMENSIONS = new Dimensions[] { 82 new Dimensions( 83 BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_FOREGROUND), 84 new Dimensions( 85 BatteryConsumer.POWER_COMPONENT_ANY, 86 BatteryConsumer.PROCESS_STATE_FOREGROUND_SERVICE), 87 new Dimensions( 88 BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_BACKGROUND), 89 new Dimensions( 90 BatteryConsumer.POWER_COMPONENT_ANY, BatteryConsumer.PROCESS_STATE_CACHED), 91 }; 92 93 static final HashMap<String, UidToDetail> sUidCache = new HashMap<>(); 94 95 static Locale sCurrentLocale = null; 96 97 /** Clears the UID cache. */ clearUidCache()98 public static void clearUidCache() { 99 sUidCache.clear(); 100 } 101 102 public static final Comparator<BatteryEntry> COMPARATOR = 103 (a, b) -> Double.compare(b.getConsumedPower(), a.getConsumedPower()); 104 105 private final Context mContext; 106 private final BatteryConsumer mBatteryConsumer; 107 private final int mUid; 108 private final boolean mIsHidden; 109 @ConvertUtils.ConsumerType 110 private final int mConsumerType; 111 @BatteryConsumer.PowerComponent 112 private final int mPowerComponentId; 113 private long mUsageDurationMs; 114 private long mTimeInForegroundMs; 115 private long mTimeInBackgroundMs; 116 117 public String mName; 118 public Drawable mIcon; 119 public int mIconId; 120 public double mPercent; 121 private String mDefaultPackageName; 122 private double mConsumedPower; 123 private double mConsumedPowerInForeground; 124 private double mConsumedPowerInForegroundService; 125 private double mConsumedPowerInBackground; 126 private double mConsumedPowerInCached; 127 128 static class UidToDetail { 129 String mName; 130 String mPackageName; 131 Drawable mIcon; 132 } 133 BatteryEntry(Context context, UserManager um, BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages, String packageName)134 public BatteryEntry(Context context, UserManager um, BatteryConsumer batteryConsumer, 135 boolean isHidden, int uid, String[] packages, String packageName) { 136 this(context, um, batteryConsumer, isHidden, uid, packages, packageName, true); 137 } 138 BatteryEntry(Context context, UserManager um, BatteryConsumer batteryConsumer, boolean isHidden, int uid, String[] packages, String packageName, boolean loadDataInBackground)139 public BatteryEntry(Context context, UserManager um, BatteryConsumer batteryConsumer, 140 boolean isHidden, int uid, String[] packages, String packageName, 141 boolean loadDataInBackground) { 142 mContext = context; 143 mBatteryConsumer = batteryConsumer; 144 mIsHidden = isHidden; 145 mDefaultPackageName = packageName; 146 mPowerComponentId = -1; 147 148 if (batteryConsumer instanceof UidBatteryConsumer) { 149 mUid = uid; 150 mConsumerType = ConvertUtils.CONSUMER_TYPE_UID_BATTERY; 151 mConsumedPower = batteryConsumer.getConsumedPower(); 152 153 UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer; 154 if (mDefaultPackageName == null) { 155 // Apps should only have one package 156 if (packages != null && packages.length == 1) { 157 mDefaultPackageName = packages[0]; 158 } else { 159 mDefaultPackageName = isSystemUid(uid) 160 ? PACKAGE_SYSTEM : uidBatteryConsumer.getPackageWithHighestDrain(); 161 } 162 } 163 if (mDefaultPackageName != null) { 164 PackageManager pm = context.getPackageManager(); 165 try { 166 ApplicationInfo appInfo = 167 pm.getApplicationInfo(mDefaultPackageName, 0 /* no flags */); 168 mName = pm.getApplicationLabel(appInfo).toString(); 169 } catch (NameNotFoundException e) { 170 Log.d(TAG, "PackageManager failed to retrieve ApplicationInfo for: " 171 + mDefaultPackageName); 172 mName = mDefaultPackageName; 173 } 174 } 175 mTimeInForegroundMs = 176 uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND); 177 mTimeInBackgroundMs = 178 uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND); 179 mConsumedPowerInForeground = safeGetConsumedPower( 180 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]); 181 mConsumedPowerInForegroundService = safeGetConsumedPower( 182 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]); 183 mConsumedPowerInBackground = safeGetConsumedPower( 184 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]); 185 mConsumedPowerInCached = safeGetConsumedPower( 186 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]); 187 } else if (batteryConsumer instanceof UserBatteryConsumer) { 188 mUid = Process.INVALID_UID; 189 mConsumerType = ConvertUtils.CONSUMER_TYPE_USER_BATTERY; 190 mConsumedPower = batteryConsumer.getConsumedPower(); 191 final NameAndIcon nameAndIcon = getNameAndIconFromUserId( 192 context, ((UserBatteryConsumer) batteryConsumer).getUserId()); 193 mIcon = nameAndIcon.mIcon; 194 mName = nameAndIcon.mName; 195 } else { 196 throw new IllegalArgumentException("Unsupported: " + batteryConsumer); 197 } 198 } 199 200 /** Battery entry for a power component of AggregateBatteryConsumer */ BatteryEntry(Context context, int powerComponentId, double devicePowerMah, long usageDurationMs, boolean isHidden)201 public BatteryEntry(Context context, int powerComponentId, double devicePowerMah, 202 long usageDurationMs, boolean isHidden) { 203 mContext = context; 204 mBatteryConsumer = null; 205 mUid = Process.INVALID_UID; 206 mIsHidden = isHidden; 207 mPowerComponentId = powerComponentId; 208 mConsumedPower = devicePowerMah; 209 mUsageDurationMs = usageDurationMs; 210 mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; 211 212 final NameAndIcon nameAndIcon = 213 getNameAndIconFromPowerComponent(context, powerComponentId); 214 mIconId = nameAndIcon.mIconId; 215 mName = nameAndIcon.mName; 216 if (mIconId != 0) { 217 mIcon = context.getDrawable(mIconId); 218 } 219 } 220 221 /** Battery entry for a custom power component of AggregateBatteryConsumer */ BatteryEntry(Context context, int powerComponentId, String powerComponentName, double devicePowerMah)222 public BatteryEntry(Context context, int powerComponentId, String powerComponentName, 223 double devicePowerMah) { 224 mContext = context; 225 mBatteryConsumer = null; 226 mUid = Process.INVALID_UID; 227 mIsHidden = false; 228 mPowerComponentId = powerComponentId; 229 230 mIconId = R.drawable.ic_power_system; 231 mIcon = context.getDrawable(mIconId); 232 mName = powerComponentName; 233 mConsumedPower = devicePowerMah; 234 mConsumerType = ConvertUtils.CONSUMER_TYPE_SYSTEM_BATTERY; 235 } 236 getIcon()237 public Drawable getIcon() { 238 return mIcon; 239 } 240 getLabel()241 public String getLabel() { 242 return mName; 243 } 244 245 @ConvertUtils.ConsumerType getConsumerType()246 public int getConsumerType() { 247 return mConsumerType; 248 } 249 250 @BatteryConsumer.PowerComponent getPowerComponentId()251 public int getPowerComponentId() { 252 return mPowerComponentId; 253 } 254 255 /** Loads the app label and icon image and stores into the cache. */ loadNameAndIcon( Context context, int uid, BatteryEntry batteryEntry, String defaultPackageName, String name, Drawable icon)256 public static NameAndIcon loadNameAndIcon( 257 Context context, 258 int uid, 259 BatteryEntry batteryEntry, 260 String defaultPackageName, 261 String name, 262 Drawable icon) { 263 // Bail out if the current sipper is not an App sipper. 264 if (uid == 0 || uid == Process.INVALID_UID) { 265 return null; 266 } 267 268 final PackageManager pm = context.getPackageManager(); 269 final String[] packages = isSystemUid(uid) 270 ? new String[]{PACKAGE_SYSTEM} : pm.getPackagesForUid(uid); 271 if (packages != null) { 272 final String[] packageLabels = new String[packages.length]; 273 System.arraycopy(packages, 0, packageLabels, 0, packages.length); 274 275 // Convert package names to user-facing labels where possible 276 final IPackageManager ipm = AppGlobals.getPackageManager(); 277 final int userId = UserHandle.getUserId(uid); 278 for (int i = 0; i < packageLabels.length; i++) { 279 try { 280 final ApplicationInfo ai = ipm.getApplicationInfo(packageLabels[i], 281 0 /* no flags */, userId); 282 if (ai == null) { 283 Log.d(TAG, "Retrieving null app info for package " 284 + packageLabels[i] + ", user " + userId); 285 continue; 286 } 287 final CharSequence label = ai.loadLabel(pm); 288 if (label != null) { 289 packageLabels[i] = label.toString(); 290 } 291 if (ai.icon != 0) { 292 defaultPackageName = packages[i]; 293 icon = ai.loadIcon(pm); 294 break; 295 } 296 } catch (RemoteException e) { 297 Log.d(TAG, "Error while retrieving app info for package " 298 + packageLabels[i] + ", user " + userId, e); 299 } 300 } 301 302 if (packageLabels.length == 1) { 303 name = packageLabels[0]; 304 } else { 305 // Look for an official name for this UID. 306 for (String pkgName : packages) { 307 try { 308 final PackageInfo pi = ipm.getPackageInfo(pkgName, 0, userId); 309 if (pi == null) { 310 Log.d(TAG, "Retrieving null package info for package " 311 + pkgName + ", user " + userId); 312 continue; 313 } 314 if (pi.sharedUserLabel != 0) { 315 final CharSequence nm = pm.getText(pkgName, 316 pi.sharedUserLabel, pi.applicationInfo); 317 if (nm != null) { 318 name = nm.toString(); 319 if (pi.applicationInfo.icon != 0) { 320 defaultPackageName = pkgName; 321 icon = pi.applicationInfo.loadIcon(pm); 322 } 323 break; 324 } 325 } 326 } catch (RemoteException e) { 327 Log.d(TAG, "Error while retrieving package info for package " 328 + pkgName + ", user " + userId, e); 329 } 330 } 331 } 332 } 333 334 final String uidString = Integer.toString(uid); 335 if (icon == null) { 336 icon = pm.getDefaultActivityIcon(); 337 } 338 339 UidToDetail utd = new UidToDetail(); 340 utd.mName = name; 341 utd.mIcon = icon; 342 utd.mPackageName = defaultPackageName; 343 344 sUidCache.put(uidString, utd); 345 return new NameAndIcon(name, defaultPackageName, icon, /*iconId=*/ 0); 346 } 347 348 /** Returns a string that uniquely identifies this battery consumer. */ getKey()349 public String getKey() { 350 if (mBatteryConsumer instanceof UidBatteryConsumer) { 351 return Integer.toString(mUid); 352 } else if (mBatteryConsumer instanceof UserBatteryConsumer) { 353 return "U|" + ((UserBatteryConsumer) mBatteryConsumer).getUserId(); 354 } else { 355 return "S|" + mPowerComponentId; 356 } 357 } 358 359 /** Returns true if the entry is hidden from the battery usage summary list. */ isHidden()360 public boolean isHidden() { 361 return mIsHidden; 362 } 363 364 /** Returns true if this entry describes an app (UID). */ isAppEntry()365 public boolean isAppEntry() { 366 return mBatteryConsumer instanceof UidBatteryConsumer; 367 } 368 369 /** Returns true if this entry describes a User. */ isUserEntry()370 public boolean isUserEntry() { 371 if (mBatteryConsumer instanceof UserBatteryConsumer) { 372 return true; 373 } 374 return false; 375 } 376 377 /** 378 * Returns the package name that should be used to represent the UID described 379 * by this entry. 380 */ getDefaultPackageName()381 public String getDefaultPackageName() { 382 return mDefaultPackageName; 383 } 384 385 /** 386 * Returns the UID of the app described by this entry. 387 */ getUid()388 public int getUid() { 389 return mUid; 390 } 391 392 /** Returns foreground time/ms that is attributed to this entry. */ getTimeInForegroundMs()393 public long getTimeInForegroundMs() { 394 if (mBatteryConsumer instanceof UidBatteryConsumer) { 395 return mTimeInForegroundMs; 396 } else { 397 return mUsageDurationMs; 398 } 399 } 400 401 /** Returns background activity time/ms that is attributed to this entry. */ getTimeInBackgroundMs()402 public long getTimeInBackgroundMs() { 403 if (mBatteryConsumer instanceof UidBatteryConsumer) { 404 return mTimeInBackgroundMs; 405 } else { 406 return 0; 407 } 408 } 409 410 /** 411 * Returns total amount of power (in milli-amp-hours) that is attributed to this entry. 412 */ getConsumedPower()413 public double getConsumedPower() { 414 return mConsumedPower; 415 } 416 417 /** 418 * Returns amount of power (in milli-amp-hours) used in foreground that is attributed to this 419 * entry. 420 */ getConsumedPowerInForeground()421 public double getConsumedPowerInForeground() { 422 if (mBatteryConsumer instanceof UidBatteryConsumer) { 423 return mConsumedPowerInForeground; 424 } else { 425 return 0; 426 } 427 } 428 429 /** 430 * Returns amount of power (in milli-amp-hours) used in foreground service that is attributed to 431 * this entry. 432 */ getConsumedPowerInForegroundService()433 public double getConsumedPowerInForegroundService() { 434 if (mBatteryConsumer instanceof UidBatteryConsumer) { 435 return mConsumedPowerInForegroundService; 436 } else { 437 return 0; 438 } 439 } 440 441 /** 442 * Returns amount of power (in milli-amp-hours) used in background that is attributed to this 443 * entry. 444 */ getConsumedPowerInBackground()445 public double getConsumedPowerInBackground() { 446 if (mBatteryConsumer instanceof UidBatteryConsumer) { 447 return mConsumedPowerInBackground; 448 } else { 449 return 0; 450 } 451 } 452 453 /** 454 * Returns amount of power (in milli-amp-hours) used in cached that is attributed to this entry. 455 */ getConsumedPowerInCached()456 public double getConsumedPowerInCached() { 457 if (mBatteryConsumer instanceof UidBatteryConsumer) { 458 return mConsumedPowerInCached; 459 } else { 460 return 0; 461 } 462 } 463 464 /** 465 * Adds the consumed power of the supplied BatteryConsumer to this entry. Also 466 * uses its package with highest drain, if necessary. 467 */ add(BatteryConsumer batteryConsumer)468 public void add(BatteryConsumer batteryConsumer) { 469 mConsumedPower += batteryConsumer.getConsumedPower(); 470 if (batteryConsumer instanceof UidBatteryConsumer) { 471 UidBatteryConsumer uidBatteryConsumer = (UidBatteryConsumer) batteryConsumer; 472 mTimeInForegroundMs += uidBatteryConsumer.getTimeInStateMs( 473 UidBatteryConsumer.STATE_FOREGROUND); 474 mTimeInBackgroundMs += uidBatteryConsumer.getTimeInStateMs( 475 UidBatteryConsumer.STATE_BACKGROUND); 476 mConsumedPowerInForeground += safeGetConsumedPower( 477 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND]); 478 mConsumedPowerInForegroundService += safeGetConsumedPower( 479 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_FOREGROUND_SERVICE]); 480 mConsumedPowerInBackground += safeGetConsumedPower( 481 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_BACKGROUND]); 482 mConsumedPowerInCached += safeGetConsumedPower( 483 uidBatteryConsumer, BATTERY_DIMENSIONS[BATTERY_USAGE_INDEX_CACHED]); 484 if (mDefaultPackageName == null) { 485 mDefaultPackageName = uidBatteryConsumer.getPackageWithHighestDrain(); 486 } 487 } 488 } 489 490 /** Gets name and icon resource from UserBatteryConsumer userId. */ getNameAndIconFromUserId( Context context, final int userId)491 public static NameAndIcon getNameAndIconFromUserId( 492 Context context, final int userId) { 493 UserManager um = context.getSystemService(UserManager.class); 494 UserInfo info = um.getUserInfo(userId); 495 496 Drawable icon = null; 497 String name = null; 498 if (info != null) { 499 icon = Utils.getUserIcon(context, um, info); 500 name = Utils.getUserLabel(context, info); 501 } else { 502 name = context.getResources().getString( 503 R.string.running_process_item_removed_user_label); 504 } 505 return new NameAndIcon(name, icon, 0 /* iconId */); 506 } 507 508 /** Gets name and icon resource from UidBatteryConsumer uid. */ getNameAndIconFromUid( Context context, String name, final int uid)509 public static NameAndIcon getNameAndIconFromUid( 510 Context context, String name, final int uid) { 511 Drawable icon = context.getDrawable(R.drawable.ic_power_system); 512 if (uid == 0) { 513 name = context.getResources().getString(R.string.process_kernel_label); 514 } else if (uid == BatteryUtils.UID_REMOVED_APPS) { 515 name = context.getResources().getString(R.string.process_removed_apps); 516 } else if (uid == BatteryUtils.UID_TETHERING) { 517 name = context.getResources().getString(R.string.process_network_tethering); 518 } else if ("mediaserver".equals(name)) { 519 name = context.getResources().getString(R.string.process_mediaserver_label); 520 } else if ("dex2oat".equals(name) || "dex2oat32".equals(name) 521 || "dex2oat64".equals(name)) { 522 name = context.getResources().getString(R.string.process_dex2oat_label); 523 } 524 return new NameAndIcon(name, icon, 0 /* iconId */); 525 } 526 527 /** Gets name and icon resource from BatteryConsumer power component ID. */ getNameAndIconFromPowerComponent( Context context, @BatteryConsumer.PowerComponent int powerComponentId)528 public static NameAndIcon getNameAndIconFromPowerComponent( 529 Context context, @BatteryConsumer.PowerComponent int powerComponentId) { 530 String name; 531 int iconId; 532 switch (powerComponentId) { 533 // Please see go/battery-usage-system-component-map 534 case BatteryConsumer.POWER_COMPONENT_SCREEN: // id: 0 535 name = context.getResources().getString(R.string.power_screen); 536 iconId = R.drawable.ic_settings_display; 537 break; 538 case BatteryConsumer.POWER_COMPONENT_CPU: // id: 1 539 name = context.getResources().getString(R.string.power_cpu); 540 iconId = R.drawable.ic_settings_cpu; 541 break; 542 case BatteryConsumer.POWER_COMPONENT_BLUETOOTH: // id: 2 543 name = context.getResources().getString(R.string.power_bluetooth); 544 iconId = R.drawable.ic_settings_bluetooth; 545 break; 546 case BatteryConsumer.POWER_COMPONENT_CAMERA: // id: 3 547 name = context.getResources().getString(R.string.power_camera); 548 iconId = R.drawable.ic_settings_camera; 549 break; 550 case BatteryConsumer.POWER_COMPONENT_FLASHLIGHT: // id: 6 551 name = context.getResources().getString(R.string.power_flashlight); 552 iconId = R.drawable.ic_settings_flashlight; 553 break; 554 case BatteryConsumer.POWER_COMPONENT_MOBILE_RADIO: // id: 8 555 name = context.getResources().getString(R.string.power_cell); 556 iconId = R.drawable.ic_settings_cellular; 557 break; 558 case BatteryConsumer.POWER_COMPONENT_GNSS: // id: 10 559 name = context.getResources().getString(R.string.power_gps); 560 iconId = R.drawable.ic_settings_gps; 561 break; 562 case BatteryConsumer.POWER_COMPONENT_WIFI: // id: 11 563 name = context.getResources().getString(R.string.power_wifi); 564 iconId = R.drawable.ic_settings_wireless_no_theme; 565 break; 566 case BatteryConsumer.POWER_COMPONENT_PHONE: // id: 14 567 name = context.getResources().getString(R.string.power_phone); 568 iconId = R.drawable.ic_settings_voice_calls; 569 break; 570 case BatteryConsumer.POWER_COMPONENT_AMBIENT_DISPLAY: // id :15 571 name = context.getResources().getString(R.string.ambient_display_screen_title); 572 iconId = R.drawable.ic_settings_aod; 573 break; 574 default: 575 Log.w(TAG, "unknown attribute:" + DebugUtils.constantToString( 576 BatteryConsumer.class, "POWER_COMPONENT_", powerComponentId)); 577 name = null; 578 iconId = R.drawable.ic_power_system; 579 break; 580 } 581 return new NameAndIcon(name, null /* icon */, iconId); 582 } 583 584 /** Whether the uid is system uid. */ isSystemUid(int uid)585 public static boolean isSystemUid(int uid) { 586 return uid == Process.SYSTEM_UID; 587 } 588 safeGetConsumedPower( final UidBatteryConsumer uidBatteryConsumer, final Dimensions dimension)589 private static double safeGetConsumedPower( 590 final UidBatteryConsumer uidBatteryConsumer, final Dimensions dimension) { 591 try { 592 return uidBatteryConsumer.getConsumedPower(dimension); 593 } catch (IllegalArgumentException e) { 594 Log.e(TAG, "safeGetConsumedPower failed:" + e); 595 return 0.0d; 596 } 597 } 598 } 599