1 /*
2  * Copyright (C) 2020 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.frameworks.core.batterystatsviewer;
18 
19 import android.content.pm.ApplicationInfo;
20 import android.content.pm.PackageManager;
21 import android.os.BatteryUsageStats;
22 import android.os.Process;
23 import android.os.UidBatteryConsumer;
24 
25 import androidx.annotation.NonNull;
26 
27 import java.util.List;
28 
29 class BatteryConsumerInfoHelper {
30 
31     private static final String SYSTEM_SERVER_PACKAGE_NAME = "android";
32 
33     public static class BatteryConsumerInfo {
34         public String id;
35         public CharSequence label;
36         public double powerMah;
37         public ApplicationInfo iconInfo;
38         public CharSequence packages;
39         public CharSequence details;
40         public BatteryConsumerData.ConsumerType consumerType;
41     }
42 
43     @NonNull
makeBatteryConsumerInfo( @onNull BatteryUsageStats batteryUsageStats, String batteryConsumerId, PackageManager packageManager)44     public static BatteryConsumerInfo makeBatteryConsumerInfo(
45             @NonNull BatteryUsageStats batteryUsageStats, String batteryConsumerId,
46             PackageManager packageManager) {
47         BatteryConsumerData.ConsumerType consumerType = BatteryConsumerData.getConsumerType(
48                 batteryConsumerId);
49         switch (consumerType) {
50             case UID_BATTERY_CONSUMER:
51                 final List<UidBatteryConsumer> consumers =
52                         batteryUsageStats.getUidBatteryConsumers();
53                 for (UidBatteryConsumer consumer : consumers) {
54                     if (BatteryConsumerData.batteryConsumerId(consumer).equals(batteryConsumerId)) {
55                         return makeBatteryConsumerInfo(consumer, packageManager);
56                     }
57                 }
58                 break;
59             case DEVICE_POWER_COMPONENT:
60                 return makeAggregateBatteryConsumerInfo(batteryUsageStats);
61         }
62 
63         BatteryConsumerInfo info = new BatteryConsumerInfo();
64         info.id = batteryConsumerId;
65         return info;
66     }
67 
makeBatteryConsumerInfo( UidBatteryConsumer uidBatteryConsumer, PackageManager packageManager)68     private static BatteryConsumerInfo makeBatteryConsumerInfo(
69             UidBatteryConsumer uidBatteryConsumer, PackageManager packageManager) {
70         BatteryConsumerInfo info = new BatteryConsumerInfo();
71         info.consumerType = BatteryConsumerData.ConsumerType.UID_BATTERY_CONSUMER;
72         info.id = BatteryConsumerData.batteryConsumerId(uidBatteryConsumer);
73         info.powerMah = uidBatteryConsumer.getConsumedPower();
74         int uid = uidBatteryConsumer.getUid();
75         info.details = String.format("UID: %d", uid);
76         String packageWithHighestDrain = uidBatteryConsumer.getPackageWithHighestDrain();
77         if (uid == Process.ROOT_UID) {
78             info.label = "<root>";
79         } else {
80             String[] packages = packageManager.getPackagesForUid(uid);
81             String primaryPackageName = null;
82             if (uid == Process.SYSTEM_UID) {
83                 primaryPackageName = SYSTEM_SERVER_PACKAGE_NAME;
84             } else if (packages != null) {
85                 for (String name : packages) {
86                     primaryPackageName = name;
87                     if (name.equals(packageWithHighestDrain)) {
88                         break;
89                     }
90                 }
91             }
92 
93             if (primaryPackageName != null) {
94                 try {
95                     ApplicationInfo applicationInfo =
96                             packageManager.getApplicationInfo(primaryPackageName, 0);
97                     info.label = applicationInfo.loadLabel(packageManager);
98                     info.iconInfo = applicationInfo;
99                 } catch (PackageManager.NameNotFoundException e) {
100                     info.label = primaryPackageName;
101                 }
102             } else if (packageWithHighestDrain != null) {
103                 info.label = packageWithHighestDrain;
104             }
105 
106             if (packages != null && packages.length > 0) {
107                 StringBuilder sb = new StringBuilder();
108                 if (primaryPackageName != null) {
109                     sb.append(primaryPackageName);
110                 }
111                 for (String packageName : packages) {
112                     if (packageName.equals(primaryPackageName)) {
113                         continue;
114                     }
115 
116                     if (sb.length() != 0) {
117                         sb.append(", ");
118                     }
119                     sb.append(packageName);
120                 }
121 
122                 info.packages = sb;
123             }
124         }
125         // Default the app icon to System Server. This includes root, dex2oat and other UIDs.
126         if (info.iconInfo == null) {
127             try {
128                 info.iconInfo =
129                         packageManager.getApplicationInfo(SYSTEM_SERVER_PACKAGE_NAME, 0);
130             } catch (PackageManager.NameNotFoundException nameNotFoundException) {
131                 // Won't happen
132             }
133         }
134         return info;
135     }
136 
makeAggregateBatteryConsumerInfo( BatteryUsageStats batteryUsageStats)137     private static BatteryConsumerInfo makeAggregateBatteryConsumerInfo(
138             BatteryUsageStats batteryUsageStats) {
139         BatteryConsumerInfo info = new BatteryConsumerInfo();
140         info.consumerType = BatteryConsumerData.ConsumerType.DEVICE_POWER_COMPONENT;
141         info.id = BatteryConsumerData.AGGREGATE_BATTERY_CONSUMER_ID;
142         info.powerMah = batteryUsageStats.getConsumedPower();
143         info.label = "Device";
144         return info;
145     }
146 }
147