1 /* 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 17 package android.os.health; 18 19 import android.annotation.TestApi; 20 21 import java.lang.annotation.ElementType; 22 import java.lang.annotation.Retention; 23 import java.lang.annotation.RetentionPolicy; 24 import java.lang.annotation.Target; 25 import java.lang.reflect.Field; 26 import java.util.Arrays; 27 28 /** 29 * Constants and stuff for the android.os.health package. 30 * 31 * @hide 32 */ 33 @TestApi 34 public class HealthKeys { 35 36 /** 37 * No valid key will ever be 0. 38 */ 39 public static final int UNKNOWN_KEY = 0; 40 41 /* 42 * Base key for each of the different classes. There is 43 * nothing intrinsic to the operation of the value of the 44 * keys. It's just segmented for better debugging. The 45 * classes don't mix them anway. 46 */ 47 public static final int BASE_UID = 10000; 48 public static final int BASE_PID = 20000; 49 public static final int BASE_PROCESS = 30000; 50 public static final int BASE_PACKAGE = 40000; 51 public static final int BASE_SERVICE = 50000; 52 53 /* 54 * The types of values supported by HealthStats. 55 */ 56 public static final int TYPE_TIMER = 0; 57 public static final int TYPE_MEASUREMENT = 1; 58 public static final int TYPE_STATS = 2; 59 public static final int TYPE_TIMERS = 3; 60 public static final int TYPE_MEASUREMENTS = 4; 61 62 public static final int TYPE_COUNT = 5; 63 64 /** 65 * Annotation to mark public static final int fields that are to be used 66 * as field keys in HealthStats. 67 */ 68 @Retention(RetentionPolicy.RUNTIME) 69 @Target({ElementType.FIELD}) 70 public @interface Constant { 71 /** 72 * One of the TYPE_* constants above. 73 */ type()74 int type(); 75 } 76 77 /** 78 * Class to gather the constants defined in a class full of constants and 79 * build the key indices used by HealthStatsWriter and HealthStats. 80 * 81 * @hide 82 */ 83 @TestApi 84 public static class Constants { 85 private final String mDataType; 86 private final int[][] mKeys = new int[TYPE_COUNT][]; 87 88 /** 89 * Pass in a class to gather the public static final int fields that are 90 * tagged with the @Constant annotation. 91 */ Constants(Class clazz)92 public Constants(Class clazz) { 93 // Save the class name for debugging 94 mDataType = clazz.getSimpleName(); 95 96 // Iterate through the list of fields on this class, and build the 97 // constant arrays for these fields. 98 final Field[] fields = clazz.getDeclaredFields(); 99 final Class<Constant> annotationClass = Constant.class; 100 101 final int N = fields.length; 102 103 final SortedIntArray[] keys = new SortedIntArray[mKeys.length]; 104 for (int i=0; i<keys.length; i++) { 105 keys[i] = new SortedIntArray(N); 106 } 107 108 for (int i=0; i<N; i++) { 109 final Field field = fields[i]; 110 final Constant constant = field.getAnnotation(annotationClass); 111 if (constant != null) { 112 final int type = constant.type(); 113 if (type >= keys.length) { 114 throw new RuntimeException("Unknown Constant type " + type 115 + " on " + field); 116 } 117 try { 118 keys[type].addValue(field.getInt(null)); 119 } catch (IllegalAccessException ex) { 120 throw new RuntimeException("Can't read constant value type=" + type 121 + " field=" + field, ex); 122 } 123 } 124 } 125 126 for (int i=0; i<keys.length; i++) { 127 mKeys[i] = keys[i].getArray(); 128 } 129 } 130 131 /** 132 * Get a string representation of this class. Useful for debugging. It will be the 133 * simple name of the class passed in the constructor. 134 */ getDataType()135 public String getDataType() { 136 return mDataType; 137 } 138 139 /** 140 * Return how many keys there are for the given field type. 141 * 142 * @see TYPE_TIMER 143 * @see TYPE_MEASUREMENT 144 * @see TYPE_TIMERS 145 * @see TYPE_MEASUREMENTS 146 * @see TYPE_STATS 147 */ getSize(int type)148 public int getSize(int type) { 149 return mKeys[type].length; 150 } 151 152 /** 153 * Return the index for the given type and key combination in the array of field 154 * keys or values. 155 * 156 * @see TYPE_TIMER 157 * @see TYPE_MEASUREMENT 158 * @see TYPE_TIMERS 159 * @see TYPE_MEASUREMENTS 160 * @see TYPE_STATS 161 */ getIndex(int type, int key)162 public int getIndex(int type, int key) { 163 final int index = Arrays.binarySearch(mKeys[type], key); 164 if (index >= 0) { 165 return index; 166 } else { 167 throw new RuntimeException("Unknown Constant " + key + " (of type " 168 + type + " )"); 169 } 170 } 171 172 /** 173 * Get the array of keys for the given field type. 174 */ getKeys(int type)175 public int[] getKeys(int type) { 176 return mKeys[type]; 177 } 178 } 179 180 /** 181 * An array of fixed size that will be sorted. 182 */ 183 private static class SortedIntArray { 184 int mCount; 185 int[] mArray; 186 187 /** 188 * Construct with the maximum number of values. 189 */ SortedIntArray(int maxCount)190 SortedIntArray(int maxCount) { 191 mArray = new int[maxCount]; 192 } 193 194 /** 195 * Add a value. 196 */ addValue(int value)197 void addValue(int value) { 198 mArray[mCount++] = value; 199 } 200 201 /** 202 * Get the array of values that have been added, with the values in 203 * numerically increasing order. 204 */ getArray()205 int[] getArray() { 206 if (mCount == mArray.length) { 207 Arrays.sort(mArray); 208 return mArray; 209 } else { 210 final int[] result = new int[mCount]; 211 System.arraycopy(mArray, 0, result, 0, mCount); 212 Arrays.sort(result); 213 return result; 214 } 215 } 216 } 217 } 218 219 220