1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
|
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.proto.ProtoOutputStream;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Interface for objects containing battery attribution data.
*
* @hide
*/
public abstract class BatteryConsumer {
/**
* Power usage component, describing the particular part of the system
* responsible for power drain.
*
* @hide
*/
@IntDef(prefix = {"POWER_COMPONENT_"}, value = {
POWER_COMPONENT_SCREEN,
POWER_COMPONENT_CPU,
POWER_COMPONENT_BLUETOOTH,
POWER_COMPONENT_CAMERA,
POWER_COMPONENT_AUDIO,
POWER_COMPONENT_VIDEO,
POWER_COMPONENT_FLASHLIGHT,
POWER_COMPONENT_MOBILE_RADIO,
POWER_COMPONENT_SYSTEM_SERVICES,
POWER_COMPONENT_SENSORS,
POWER_COMPONENT_GNSS,
POWER_COMPONENT_WIFI,
POWER_COMPONENT_WAKELOCK,
POWER_COMPONENT_MEMORY,
POWER_COMPONENT_PHONE,
POWER_COMPONENT_IDLE,
POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS,
})
@Retention(RetentionPolicy.SOURCE)
public static @interface PowerComponent {
}
public static final int POWER_COMPONENT_SCREEN = OsProtoEnums.POWER_COMPONENT_SCREEN; // 0
public static final int POWER_COMPONENT_CPU = OsProtoEnums.POWER_COMPONENT_CPU; // 1
public static final int POWER_COMPONENT_BLUETOOTH = OsProtoEnums.POWER_COMPONENT_BLUETOOTH; // 2
public static final int POWER_COMPONENT_CAMERA = OsProtoEnums.POWER_COMPONENT_CAMERA; // 3
public static final int POWER_COMPONENT_AUDIO = OsProtoEnums.POWER_COMPONENT_AUDIO; // 4
public static final int POWER_COMPONENT_VIDEO = OsProtoEnums.POWER_COMPONENT_VIDEO; // 5
public static final int POWER_COMPONENT_FLASHLIGHT =
OsProtoEnums.POWER_COMPONENT_FLASHLIGHT; // 6
public static final int POWER_COMPONENT_SYSTEM_SERVICES =
OsProtoEnums.POWER_COMPONENT_SYSTEM_SERVICES; // 7
public static final int POWER_COMPONENT_MOBILE_RADIO =
OsProtoEnums.POWER_COMPONENT_MOBILE_RADIO; // 8
public static final int POWER_COMPONENT_SENSORS = OsProtoEnums.POWER_COMPONENT_SENSORS; // 9
public static final int POWER_COMPONENT_GNSS = OsProtoEnums.POWER_COMPONENT_GNSS; // 10
public static final int POWER_COMPONENT_WIFI = OsProtoEnums.POWER_COMPONENT_WIFI; // 11
public static final int POWER_COMPONENT_WAKELOCK = OsProtoEnums.POWER_COMPONENT_WAKELOCK; // 12
public static final int POWER_COMPONENT_MEMORY = OsProtoEnums.POWER_COMPONENT_MEMORY; // 13
public static final int POWER_COMPONENT_PHONE = OsProtoEnums.POWER_COMPONENT_PHONE; // 14
public static final int POWER_COMPONENT_AMBIENT_DISPLAY =
OsProtoEnums.POWER_COMPONENT_AMBIENT_DISPLAY; // 15
public static final int POWER_COMPONENT_IDLE = OsProtoEnums.POWER_COMPONENT_IDLE; // 16
// Power that is re-attributed to other battery consumers. For example, for System Server
// this represents the power attributed to apps requesting system services.
// The value should be negative or zero.
public static final int POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS =
OsProtoEnums.POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS; // 17
public static final int POWER_COMPONENT_COUNT = 18;
public static final int FIRST_CUSTOM_POWER_COMPONENT_ID = 1000;
public static final int LAST_CUSTOM_POWER_COMPONENT_ID = 9999;
private static final String[] sPowerComponentNames = new String[POWER_COMPONENT_COUNT];
static {
// Assign individually to avoid future mismatch
sPowerComponentNames[POWER_COMPONENT_SCREEN] = "screen";
sPowerComponentNames[POWER_COMPONENT_CPU] = "cpu";
sPowerComponentNames[POWER_COMPONENT_BLUETOOTH] = "bluetooth";
sPowerComponentNames[POWER_COMPONENT_CAMERA] = "camera";
sPowerComponentNames[POWER_COMPONENT_AUDIO] = "audio";
sPowerComponentNames[POWER_COMPONENT_VIDEO] = "video";
sPowerComponentNames[POWER_COMPONENT_FLASHLIGHT] = "flashlight";
sPowerComponentNames[POWER_COMPONENT_SYSTEM_SERVICES] = "system_services";
sPowerComponentNames[POWER_COMPONENT_MOBILE_RADIO] = "mobile_radio";
sPowerComponentNames[POWER_COMPONENT_SENSORS] = "sensors";
sPowerComponentNames[POWER_COMPONENT_GNSS] = "gnss";
sPowerComponentNames[POWER_COMPONENT_WIFI] = "wifi";
sPowerComponentNames[POWER_COMPONENT_WAKELOCK] = "wakelock";
sPowerComponentNames[POWER_COMPONENT_MEMORY] = "memory";
sPowerComponentNames[POWER_COMPONENT_PHONE] = "phone";
sPowerComponentNames[POWER_COMPONENT_AMBIENT_DISPLAY] = "ambient_display";
sPowerComponentNames[POWER_COMPONENT_IDLE] = "idle";
sPowerComponentNames[POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS] = "reattributed";
}
/**
* Identifiers of models used for power estimation.
*
* @hide
*/
@IntDef(prefix = {"POWER_MODEL_"}, value = {
POWER_MODEL_UNDEFINED,
POWER_MODEL_POWER_PROFILE,
POWER_MODEL_MEASURED_ENERGY,
})
@Retention(RetentionPolicy.SOURCE)
public @interface PowerModel {
}
/**
* Unspecified power model.
*/
public static final int POWER_MODEL_UNDEFINED = 0;
/**
* Power model that is based on average consumption rates that hardware components
* consume in various states.
*/
public static final int POWER_MODEL_POWER_PROFILE = 1;
/**
* Power model that is based on energy consumption measured by on-device power monitors.
*/
public static final int POWER_MODEL_MEASURED_ENERGY = 2;
protected final PowerComponents mPowerComponents;
protected BatteryConsumer(@NonNull PowerComponents powerComponents) {
mPowerComponents = powerComponents;
}
/**
* Total power consumed by this consumer, in mAh.
*/
public double getConsumedPower() {
return mPowerComponents.getConsumedPower();
}
/**
* Returns the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
*
* @param componentId The ID of the power component, e.g.
* {@link BatteryConsumer#POWER_COMPONENT_CPU}.
* @return Amount of consumed power in mAh.
*/
public double getConsumedPower(@PowerComponent int componentId) {
return mPowerComponents.getConsumedPower(componentId);
}
/**
* Returns the ID of the model that was used for power estimation.
*
* @param componentId The ID of the power component, e.g.
* {@link BatteryConsumer#POWER_COMPONENT_CPU}.
*/
public @PowerModel int getPowerModel(@BatteryConsumer.PowerComponent int componentId) {
return mPowerComponents.getPowerModel(componentId);
}
/**
* Returns the amount of drain attributed to the specified custom drain type.
*
* @param componentId The ID of the custom power component.
* @return Amount of consumed power in mAh.
*/
public double getConsumedPowerForCustomComponent(int componentId) {
return mPowerComponents.getConsumedPowerForCustomComponent(componentId);
}
public int getCustomPowerComponentCount() {
return mPowerComponents.getCustomPowerComponentCount();
}
void setCustomPowerComponentNames(String[] customPowerComponentNames) {
mPowerComponents.setCustomPowerComponentNames(customPowerComponentNames);
}
/**
* Returns the name of the specified power component.
*
* @param componentId The ID of the custom power component.
*/
public String getCustomPowerComponentName(int componentId) {
return mPowerComponents.getCustomPowerComponentName(componentId);
}
/**
* Returns the amount of time since BatteryStats reset used by the specified component, e.g.
* CPU, WiFi etc.
*
* @param componentId The ID of the power component, e.g.
* {@link UidBatteryConsumer#POWER_COMPONENT_CPU}.
* @return Amount of time in milliseconds.
*/
public long getUsageDurationMillis(@PowerComponent int componentId) {
return mPowerComponents.getUsageDurationMillis(componentId);
}
/**
* Returns the amount of usage time attributed to the specified custom component
* since BatteryStats reset.
*
* @param componentId The ID of the custom power component.
* @return Amount of time in milliseconds.
*/
public long getUsageDurationForCustomComponentMillis(int componentId) {
return mPowerComponents.getUsageDurationForCustomComponentMillis(componentId);
}
protected void writeToParcel(Parcel dest, int flags) {
mPowerComponents.writeToParcel(dest, flags);
}
/**
* Returns the name of the specified component. Intended for logging and debugging.
*/
public static String powerComponentIdToString(@BatteryConsumer.PowerComponent int componentId) {
return sPowerComponentNames[componentId];
}
/**
* Returns the name of the specified power model. Intended for logging and debugging.
*/
public static String powerModelToString(@BatteryConsumer.PowerModel int powerModel) {
switch (powerModel) {
case BatteryConsumer.POWER_MODEL_MEASURED_ENERGY:
return "measured energy";
case BatteryConsumer.POWER_MODEL_POWER_PROFILE:
return "power profile";
default:
return "";
}
}
/**
* Prints the stats in a human-readable format.
*/
public void dump(PrintWriter pw) {
dump(pw, true);
}
/**
* Prints the stats in a human-readable format.
*
* @param skipEmptyComponents if true, omit any power components with a zero amount.
*/
public abstract void dump(PrintWriter pw, boolean skipEmptyComponents);
/** Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto. */
boolean hasStatsProtoData() {
return writeStatsProtoImpl(null, /* Irrelevant fieldId: */ 0);
}
/** Writes the atoms.proto BATTERY_CONSUMER_DATA for this BatteryConsumer to the given proto. */
void writeStatsProto(@NonNull ProtoOutputStream proto, long fieldId) {
writeStatsProtoImpl(proto, fieldId);
}
/**
* Returns whether there are any atoms.proto BATTERY_CONSUMER_DATA data to write to a proto,
* and writes it to the given proto if it is non-null.
*/
private boolean writeStatsProtoImpl(@Nullable ProtoOutputStream proto, long fieldId) {
final long totalConsumedPowerDeciCoulombs = convertMahToDeciCoulombs(getConsumedPower());
if (totalConsumedPowerDeciCoulombs == 0) {
// NOTE: Strictly speaking we should also check !mPowerComponents.hasStatsProtoData().
// However, that call is a bit expensive (a for loop). And the only way that
// totalConsumedPower can be 0 while mPowerComponents.hasStatsProtoData() is true is
// if POWER_COMPONENT_REATTRIBUTED_TO_OTHER_CONSUMERS (which is the only negative
// allowed) happens to exactly equal the sum of all other components, which
// can't really happen in practice.
// So we'll just adopt the rule "if total==0, don't write any details".
// If negative values are used for other things in the future, this can be revisited.
return false;
}
if (proto == null) {
// We're just asked whether there is data, not to actually write it. And there is.
return true;
}
final long token = proto.start(fieldId);
proto.write(
BatteryUsageStatsAtomsProto.BatteryConsumerData.TOTAL_CONSUMED_POWER_DECI_COULOMBS,
totalConsumedPowerDeciCoulombs);
mPowerComponents.writeStatsProto(proto);
proto.end(token);
return true;
}
/** Converts charge from milliamp hours (mAh) to decicoulombs (dC). */
static long convertMahToDeciCoulombs(double powerMah) {
return (long) (powerMah * (10 * 3600 / 1000) + 0.5);
}
protected abstract static class BaseBuilder<T extends BaseBuilder<?>> {
final PowerComponents.Builder mPowerComponentsBuilder;
public BaseBuilder(@NonNull String[] customPowerComponentNames,
boolean includePowerModels) {
mPowerComponentsBuilder = new PowerComponents.Builder(customPowerComponentNames,
includePowerModels);
}
/**
* Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
*
* @param componentId The ID of the power component, e.g.
* {@link BatteryConsumer#POWER_COMPONENT_CPU}.
* @param componentPower Amount of consumed power in mAh.
*/
@NonNull
public T setConsumedPower(@PowerComponent int componentId, double componentPower) {
return setConsumedPower(componentId, componentPower, POWER_MODEL_POWER_PROFILE);
}
/**
* Sets the amount of drain attributed to the specified drain type, e.g. CPU, WiFi etc.
*
* @param componentId The ID of the power component, e.g.
* {@link BatteryConsumer#POWER_COMPONENT_CPU}.
* @param componentPower Amount of consumed power in mAh.
*/
@SuppressWarnings("unchecked")
@NonNull
public T setConsumedPower(@PowerComponent int componentId, double componentPower,
@PowerModel int powerModel) {
mPowerComponentsBuilder.setConsumedPower(componentId, componentPower, powerModel);
return (T) this;
}
/**
* Sets the amount of drain attributed to the specified custom drain type.
*
* @param componentId The ID of the custom power component.
* @param componentPower Amount of consumed power in mAh.
*/
@SuppressWarnings("unchecked")
@NonNull
public T setConsumedPowerForCustomComponent(int componentId, double componentPower) {
mPowerComponentsBuilder.setConsumedPowerForCustomComponent(componentId, componentPower);
return (T) this;
}
/**
* Sets the amount of time used by the specified component, e.g. CPU, WiFi etc.
*
* @param componentId The ID of the power component, e.g.
* {@link UidBatteryConsumer#POWER_COMPONENT_CPU}.
* @param componentUsageTimeMillis Amount of time in microseconds.
*/
@SuppressWarnings("unchecked")
@NonNull
public T setUsageDurationMillis(@UidBatteryConsumer.PowerComponent int componentId,
long componentUsageTimeMillis) {
mPowerComponentsBuilder.setUsageDurationMillis(componentId, componentUsageTimeMillis);
return (T) this;
}
/**
* Sets the amount of time used by the specified custom component.
*
* @param componentId The ID of the custom power component.
* @param componentUsageTimeMillis Amount of time in microseconds.
*/
@SuppressWarnings("unchecked")
@NonNull
public T setUsageDurationForCustomComponentMillis(int componentId,
long componentUsageTimeMillis) {
mPowerComponentsBuilder.setUsageDurationForCustomComponentMillis(componentId,
componentUsageTimeMillis);
return (T) this;
}
/**
* Returns the total power accumulated by this builder so far. It may change
* by the time the {@code build()} method is called.
*/
public double getTotalPower() {
return mPowerComponentsBuilder.getTotalPower();
}
}
}
|