blob: 74ce5157a548adc6052d345e005c86a4c5b12beb [file] [log] [blame]
Joe Onorato713fec82016-03-04 10:34:02 -08001/*
2 * Copyright (C) 2016 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
17package android.os.health;
18
Jeff Sharkeyc6091162018-06-29 17:15:40 -060019import android.annotation.TestApi;
Joe Onorato713fec82016-03-04 10:34:02 -080020import android.os.Parcel;
21import android.os.Parcelable;
22import android.util.ArrayMap;
23
24import java.util.Arrays;
25import java.util.Map;
26
27/**
28 * A HealthStats object contains system health data about an application.
29 *
30 * <p>
31 * <b>Data Types</b><br>
32 * Each of the keys references data in one of five data types:
33 *
34 * <p>
35 * A <b>measurement</b> metric contains a sinlge {@code long} value. That value may
36 * be a count, a time, or some other type of value. The unit for a measurement
37 * (COUNT, MS, etc) will always be in the name of the constant for the key to
38 * retrieve it. For example, the
39 * {@link android.os.health.UidHealthStats#MEASUREMENT_WIFI_TX_MS UidHealthStats.MEASUREMENT_WIFI_TX_MS}
40 * value is the number of milliseconds (ms) that were spent transmitting on wifi by an
41 * application. The
42 * {@link android.os.health.UidHealthStats#MEASUREMENT_MOBILE_RX_PACKETS UidHealthStats.MEASUREMENT_MOBILE_RX_PACKETS}
43 * measurement is the number of packets received on behalf of an application.
44 * The {@link android.os.health.UidHealthStats#MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT
45 * UidHealthStats.MEASUREMENT_TOUCH_USER_ACTIVITY_COUNT}
46 * measurement is the number of times the user touched the screen, causing the
47 * screen to stay awake.
48 *
49 *
50 * <p>
51 * A <b>timer</b> metric contains an {@code int} count and a {@code long} time,
52 * measured in milliseconds. Timers track how many times a resource was used, and
53 * the total duration for that usage. For example, the
54 * {@link android.os.health.UidHealthStats#TIMER_FLASHLIGHT}
55 * timer tracks how many times the application turned on the flashlight, and for
56 * how many milliseconds total it kept it on.
57 *
58 * <p>
59 * A <b>measurement map</b> metric is a mapping of {@link java.lang.String} names to
60 * {@link java.lang.Long} values. The names typically are application provided names. For
61 * example, the
62 * {@link android.os.health.PackageHealthStats#MEASUREMENTS_WAKEUP_ALARMS_COUNT
63 * PackageHealthStats.MEASUREMENTS_WAKEUP_ALARMS_COUNT}
64 * measurement map is a mapping of the tag provided to the
65 * {@link android.app.AlarmManager} when the alarm is scheduled.
66 *
67 * <p>
68 * A <b>timer map</b> metric is a mapping of {@link java.lang.String} names to
69 * {@link android.os.health.TimerStat} objects. The names are typically application
70 * provided names. For example, the
71 * {@link android.os.health.UidHealthStats#TIMERS_WAKELOCKS_PARTIAL UidHealthStats.TIMERS_WAKELOCKS_PARTIAL}
72 * is a mapping of tag provided to the {@link android.os.PowerManager} when the
73 * wakelock is created to the number of times and for how long each wakelock was
74 * active.
75 *
76 * <p>
77 * Lastly, a <b>health stats</b> metric is a mapping of {@link java.lang.String}
78 * names to a recursive {@link android.os.health.HealthStats} object containing
79 * more detailed information. For example, the
80 * {@link android.os.health.UidHealthStats#STATS_PACKAGES UidHealthStats.STATS_PACKAGES}
81 * metric is a mapping of the package names for each of the APKs sharing a uid to
82 * the information recorded for that apk. The returned HealthStats objects will
83 * each be associated with a different set of constants. For the HealthStats
84 * returned for UidHealthStats.STATS_PACKAGES, the keys come from the
85 * {@link android.os.health.PackageHealthStats} class.
86 *
Joe Onorato181cada2016-05-09 10:31:41 -070087 * <p>
88 * The keys that are available are subject to change, depending on what a particular
89 * device or software version is capable of recording. Applications must handle the absence of
90 * data without crashing.
Joe Onorato713fec82016-03-04 10:34:02 -080091 */
92public class HealthStats {
93 // Header fields
94 private String mDataType;
95
96 // TimerStat fields
97 private int[] mTimerKeys;
98 private int[] mTimerCounts;
99 private long[] mTimerTimes;
100
101 // Measurement fields
102 private int[] mMeasurementKeys;
103 private long[] mMeasurementValues;
104
105 // Stats fields
106 private int[] mStatsKeys;
107 private ArrayMap<String,HealthStats>[] mStatsValues;
108
109 // Timers fields
110 private int[] mTimersKeys;
111 private ArrayMap<String,TimerStat>[] mTimersValues;
112
113 // Measurements fields
114 private int[] mMeasurementsKeys;
115 private ArrayMap<String,Long>[] mMeasurementsValues;
116
117 /**
118 * HealthStats empty constructor not implemented because this
119 * class is read-only.
120 */
121 private HealthStats() {
122 throw new RuntimeException("unsupported");
123 }
124
125 /**
126 * Construct a health stats object from a parcel.
127 *
128 * @hide
129 */
Jeff Sharkeyc6091162018-06-29 17:15:40 -0600130 @TestApi
Joe Onorato713fec82016-03-04 10:34:02 -0800131 public HealthStats(Parcel in) {
132 int count;
133
134 // Header fields
135 mDataType = in.readString();
136
137 // TimerStat fields
138 count = in.readInt();
139 mTimerKeys = new int[count];
140 mTimerCounts = new int[count];
141 mTimerTimes = new long[count];
142 for (int i=0; i<count; i++) {
143 mTimerKeys[i] = in.readInt();
144 mTimerCounts[i] = in.readInt();
145 mTimerTimes[i] = in.readLong();
146 }
147
148 // Measurement fields
149 count = in.readInt();
150 mMeasurementKeys = new int[count];
151 mMeasurementValues = new long[count];
152 for (int i=0; i<count; i++) {
153 mMeasurementKeys[i] = in.readInt();
154 mMeasurementValues[i] = in.readLong();
155 }
156
157 // Stats fields
158 count = in.readInt();
159 mStatsKeys = new int[count];
160 mStatsValues = new ArrayMap[count];
161 for (int i=0; i<count; i++) {
162 mStatsKeys[i] = in.readInt();
163 mStatsValues[i] = createHealthStatsMap(in);
164 }
165
166 // Timers fields
167 count = in.readInt();
168 mTimersKeys = new int[count];
169 mTimersValues = new ArrayMap[count];
170 for (int i=0; i<count; i++) {
171 mTimersKeys[i] = in.readInt();
172 mTimersValues[i] = createParcelableMap(in, TimerStat.CREATOR);
173 }
174
175 // Measurements fields
176 count = in.readInt();
177 mMeasurementsKeys = new int[count];
178 mMeasurementsValues = new ArrayMap[count];
179 for (int i=0; i<count; i++) {
180 mMeasurementsKeys[i] = in.readInt();
181 mMeasurementsValues[i] = createLongsMap(in);
182 }
183 }
184
185 /**
186 * Get a name representing the contents of this object.
187 *
188 * @see UidHealthStats
189 * @see PackageHealthStats
190 * @see PidHealthStats
191 * @see ProcessHealthStats
192 * @see ServiceHealthStats
193 */
194 public String getDataType() {
195 return mDataType;
196 }
197
198 /**
199 * Return whether this object contains a TimerStat for the supplied key.
200 */
201 public boolean hasTimer(int key) {
202 return getIndex(mTimerKeys, key) >= 0;
203 }
204
205 /**
206 * Return a TimerStat object for the given key.
207 *
208 * This will allocate a new {@link TimerStat} object, which may be wasteful. Instead, use
209 * {@link #getTimerCount} and {@link #getTimerTime}.
210 *
211 * @throws IndexOutOfBoundsException When the key is not present in this object.
212 * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
213 */
214 public TimerStat getTimer(int key) {
215 final int index = getIndex(mTimerKeys, key);
216 if (index < 0) {
217 throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
218 + " key=" + key);
219 }
220 return new TimerStat(mTimerCounts[index], mTimerTimes[index]);
221 }
222
223 /**
224 * Get the count for the timer for the given key.
225 *
226 * @throws IndexOutOfBoundsException When the key is not present in this object.
227 * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
228 */
229 public int getTimerCount(int key) {
230 final int index = getIndex(mTimerKeys, key);
231 if (index < 0) {
232 throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
233 + " key=" + key);
234 }
235 return mTimerCounts[index];
236 }
237
238 /**
239 * Get the time for the timer for the given key, in milliseconds.
240 *
241 * @throws IndexOutOfBoundsException When the key is not present in this object.
242 * @see #hasTimer hasTimer(int) To check if a value for the given key is present.
243 */
244 public long getTimerTime(int key) {
245 final int index = getIndex(mTimerKeys, key);
246 if (index < 0) {
247 throw new IndexOutOfBoundsException("Bad timer key dataType=" + mDataType
248 + " key=" + key);
249 }
250 return mTimerTimes[index];
251 }
252
253 /**
254 * Get the number of timer values in this object. Can be used to iterate through
255 * the available timers.
256 *
257 * @see #getTimerKeyAt
258 */
259 public int getTimerKeyCount() {
260 return mTimerKeys.length;
261 }
262
263 /**
264 * Get the key for the timer at the given index. Index must be between 0 and the result
265 * of {@link #getTimerKeyCount getTimerKeyCount()}.
266 *
267 * @see #getTimerKeyCount
268 */
269 public int getTimerKeyAt(int index) {
270 return mTimerKeys[index];
271 }
272
273 /**
274 * Return whether this object contains a measurement for the supplied key.
275 */
276 public boolean hasMeasurement(int key) {
277 return getIndex(mMeasurementKeys, key) >= 0;
278 }
279
280 /**
281 * Get the measurement for the given key.
282 *
283 * @throws IndexOutOfBoundsException When the key is not present in this object.
284 * @see #hasMeasurement hasMeasurement(int) To check if a value for the given key is present.
285 */
286 public long getMeasurement(int key) {
287 final int index = getIndex(mMeasurementKeys, key);
288 if (index < 0) {
289 throw new IndexOutOfBoundsException("Bad measurement key dataType=" + mDataType
290 + " key=" + key);
291 }
292 return mMeasurementValues[index];
293 }
294
295 /**
296 * Get the number of measurement values in this object. Can be used to iterate through
297 * the available measurements.
298 *
299 * @see #getMeasurementKeyAt
300 */
301 public int getMeasurementKeyCount() {
302 return mMeasurementKeys.length;
303 }
304
305 /**
306 * Get the key for the measurement at the given index. Index must be between 0 and the result
307 * of {@link #getMeasurementKeyCount getMeasurementKeyCount()}.
308 *
309 * @see #getMeasurementKeyCount
310 */
311 public int getMeasurementKeyAt(int index) {
312 return mMeasurementKeys[index];
313 }
314
315 /**
316 * Return whether this object contains a HealthStats map for the supplied key.
317 */
318 public boolean hasStats(int key) {
319 return getIndex(mStatsKeys, key) >= 0;
320 }
321
322 /**
323 * Get the HealthStats map for the given key.
324 *
325 * @throws IndexOutOfBoundsException When the key is not present in this object.
326 * @see #hasStats hasStats(int) To check if a value for the given key is present.
327 */
328 public Map<String,HealthStats> getStats(int key) {
329 final int index = getIndex(mStatsKeys, key);
330 if (index < 0) {
331 throw new IndexOutOfBoundsException("Bad stats key dataType=" + mDataType
332 + " key=" + key);
333 }
334 return mStatsValues[index];
335 }
336
337 /**
338 * Get the number of HealthStat map values in this object. Can be used to iterate through
339 * the available measurements.
340 *
341 * @see #getMeasurementKeyAt
342 */
343 public int getStatsKeyCount() {
344 return mStatsKeys.length;
345 }
346
347 /**
348 * Get the key for the timer at the given index. Index must be between 0 and the result
349 * of {@link #getStatsKeyCount getStatsKeyCount()}.
350 *
351 * @see #getStatsKeyCount
352 */
353 public int getStatsKeyAt(int index) {
354 return mStatsKeys[index];
355 }
356
357 /**
358 * Return whether this object contains a timers map for the supplied key.
359 */
360 public boolean hasTimers(int key) {
361 return getIndex(mTimersKeys, key) >= 0;
362 }
363
364 /**
365 * Get the TimerStat map for the given key.
366 *
367 * @throws IndexOutOfBoundsException When the key is not present in this object.
368 * @see #hasTimers hasTimers(int) To check if a value for the given key is present.
369 */
370 public Map<String,TimerStat> getTimers(int key) {
371 final int index = getIndex(mTimersKeys, key);
372 if (index < 0) {
373 throw new IndexOutOfBoundsException("Bad timers key dataType=" + mDataType
374 + " key=" + key);
375 }
376 return mTimersValues[index];
377 }
378
379 /**
380 * Get the number of timer map values in this object. Can be used to iterate through
381 * the available timer maps.
382 *
383 * @see #getTimersKeyAt
384 */
385 public int getTimersKeyCount() {
386 return mTimersKeys.length;
387 }
388
389 /**
390 * Get the key for the timer map at the given index. Index must be between 0 and the result
391 * of {@link #getTimersKeyCount getTimersKeyCount()}.
392 *
393 * @see #getTimersKeyCount
394 */
395 public int getTimersKeyAt(int index) {
396 return mTimersKeys[index];
397 }
398
399 /**
400 * Return whether this object contains a measurements map for the supplied key.
401 */
402 public boolean hasMeasurements(int key) {
403 return getIndex(mMeasurementsKeys, key) >= 0;
404 }
405
406 /**
407 * Get the measurements map for the given key.
408 *
409 * @throws IndexOutOfBoundsException When the key is not present in this object.
410 * @see #hasMeasurements To check if a value for the given key is present.
411 */
412 public Map<String,Long> getMeasurements(int key) {
413 final int index = getIndex(mMeasurementsKeys, key);
414 if (index < 0) {
415 throw new IndexOutOfBoundsException("Bad measurements key dataType=" + mDataType
416 + " key=" + key);
417 }
418 return mMeasurementsValues[index];
419 }
420
421 /**
422 * Get the number of measurement map values in this object. Can be used to iterate through
423 * the available measurement maps.
424 *
425 * @see #getMeasurementsKeyAt
426 */
427 public int getMeasurementsKeyCount() {
428 return mMeasurementsKeys.length;
429 }
430
431 /**
432 * Get the key for the measurement map at the given index.
433 * Index must be between 0 and the result
434 * of {@link #getMeasurementsKeyCount getMeasurementsKeyCount()}.
435 *
436 * @see #getMeasurementsKeyCount
437 */
438 public int getMeasurementsKeyAt(int index) {
439 return mMeasurementsKeys[index];
440 }
441
442 /**
443 * Get the index in keys of key.
444 */
445 private static int getIndex(int[] keys, int key) {
446 return Arrays.binarySearch(keys, key);
447 }
448
449 /**
450 * Create an ArrayMap<String,HealthStats> from the given Parcel.
451 */
452 private static ArrayMap<String,HealthStats> createHealthStatsMap(Parcel in) {
453 final int count = in.readInt();
454 final ArrayMap<String,HealthStats> result = new ArrayMap<String,HealthStats>(count);
455 for (int i=0; i<count; i++) {
456 result.put(in.readString(), new HealthStats(in));
457 }
458 return result;
459 }
460
461 /**
462 * Create an ArrayMap<String,T extends Parcelable> from the given Parcel using
463 * the given Parcelable.Creator.
464 */
465 private static <T extends Parcelable> ArrayMap<String,T> createParcelableMap(Parcel in,
466 Parcelable.Creator<T> creator) {
467 final int count = in.readInt();
468 final ArrayMap<String,T> result = new ArrayMap<String,T>(count);
469 for (int i=0; i<count; i++) {
470 result.put(in.readString(), creator.createFromParcel(in));
471 }
472 return result;
473 }
474
475 /**
476 * Create an ArrayMap<String,Long> from the given Parcel.
477 */
478 private static ArrayMap<String,Long> createLongsMap(Parcel in) {
479 final int count = in.readInt();
480 final ArrayMap<String,Long> result = new ArrayMap<String,Long>(count);
481 for (int i=0; i<count; i++) {
482 result.put(in.readString(), in.readLong());
483 }
484 return result;
485 }
486}
487