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