1 /* 2 * Copyright 2018 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 package android.os; 17 18 import android.annotation.SystemApi; 19 import android.util.Log; 20 21 import java.util.ArrayList; 22 import java.util.List; 23 24 /** 25 * Container for statsd dimension value information, corresponding to a 26 * stats_log.proto's DimensionValue. 27 * 28 * This consists of a field (an int representing a statsd atom field) 29 * and a value (which may be one of a number of types). 30 * 31 * <p> 32 * Only a single value is held, and it is necessarily one of the following types: 33 * {@link String}, int, long, boolean, float, 34 * or tuple (i.e. {@link List} of {@code StatsDimensionsValue}). 35 * 36 * The type of value held can be retrieved using {@link #getValueType()}, which returns one of the 37 * following ints, depending on the type of value: 38 * <ul> 39 * <li>{@link #STRING_VALUE_TYPE}</li> 40 * <li>{@link #INT_VALUE_TYPE}</li> 41 * <li>{@link #LONG_VALUE_TYPE}</li> 42 * <li>{@link #BOOLEAN_VALUE_TYPE}</li> 43 * <li>{@link #FLOAT_VALUE_TYPE}</li> 44 * <li>{@link #TUPLE_VALUE_TYPE}</li> 45 * </ul> 46 * Alternatively, this can be determined using {@link #isValueType(int)} with one of these constants 47 * as a parameter. 48 * The value itself can be retrieved using the correct get...Value() function for its type. 49 * 50 * <p> 51 * The field is always an int, and always exists; it can be obtained using {@link #getField()}. 52 * 53 * 54 * @hide 55 */ 56 @SystemApi 57 public final class StatsDimensionsValue implements Parcelable { 58 private static final String TAG = "StatsDimensionsValue"; 59 60 // Values of the value type correspond to stats_log.proto's DimensionValue fields. 61 // Keep constants in sync with frameworks/base/cmds/statsd/src/HashableDimensionKey.cpp. 62 /** Indicates that this holds a String. */ 63 public static final int STRING_VALUE_TYPE = 2; 64 /** Indicates that this holds an int. */ 65 public static final int INT_VALUE_TYPE = 3; 66 /** Indicates that this holds a long. */ 67 public static final int LONG_VALUE_TYPE = 4; 68 /** Indicates that this holds a boolean. */ 69 public static final int BOOLEAN_VALUE_TYPE = 5; 70 /** Indicates that this holds a float. */ 71 public static final int FLOAT_VALUE_TYPE = 6; 72 /** Indicates that this holds a List of StatsDimensionsValues. */ 73 public static final int TUPLE_VALUE_TYPE = 7; 74 75 private final StatsDimensionsValueParcel mInner; 76 77 /** 78 * Creates a {@code StatsDimensionValue} from a parcel. 79 * 80 * @hide 81 */ StatsDimensionsValue(Parcel in)82 public StatsDimensionsValue(Parcel in) { 83 mInner = StatsDimensionsValueParcel.CREATOR.createFromParcel(in); 84 } 85 86 /** 87 * Creates a {@code StatsDimensionsValue} from a StatsDimensionsValueParcel 88 * 89 * @hide 90 */ StatsDimensionsValue(StatsDimensionsValueParcel parcel)91 public StatsDimensionsValue(StatsDimensionsValueParcel parcel) { 92 mInner = parcel; 93 } 94 95 /** 96 * Return the field, i.e. the tag of a statsd atom. 97 * 98 * @return the field 99 */ getField()100 public int getField() { 101 return mInner.field; 102 } 103 104 /** 105 * Retrieve the String held, if any. 106 * 107 * @return the {@link String} held if {@link #getValueType()} == {@link #STRING_VALUE_TYPE}, 108 * null otherwise 109 */ getStringValue()110 public String getStringValue() { 111 if (mInner.valueType == STRING_VALUE_TYPE) { 112 return mInner.stringValue; 113 } else { 114 Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not string."); 115 return null; 116 } 117 } 118 119 /** 120 * Retrieve the int held, if any. 121 * 122 * @return the int held if {@link #getValueType()} == {@link #INT_VALUE_TYPE}, 0 otherwise 123 */ getIntValue()124 public int getIntValue() { 125 if (mInner.valueType == INT_VALUE_TYPE) { 126 return mInner.intValue; 127 } else { 128 Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not int."); 129 return 0; 130 } 131 } 132 133 /** 134 * Retrieve the long held, if any. 135 * 136 * @return the long held if {@link #getValueType()} == {@link #LONG_VALUE_TYPE}, 0 otherwise 137 */ getLongValue()138 public long getLongValue() { 139 if (mInner.valueType == LONG_VALUE_TYPE) { 140 return mInner.longValue; 141 } else { 142 Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not long."); 143 return 0; 144 } 145 } 146 147 /** 148 * Retrieve the boolean held, if any. 149 * 150 * @return the boolean held if {@link #getValueType()} == {@link #BOOLEAN_VALUE_TYPE}, 151 * false otherwise 152 */ getBooleanValue()153 public boolean getBooleanValue() { 154 if (mInner.valueType == BOOLEAN_VALUE_TYPE) { 155 return mInner.boolValue; 156 } else { 157 Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not boolean."); 158 return false; 159 } 160 } 161 162 /** 163 * Retrieve the float held, if any. 164 * 165 * @return the float held if {@link #getValueType()} == {@link #FLOAT_VALUE_TYPE}, 0 otherwise 166 */ getFloatValue()167 public float getFloatValue() { 168 if (mInner.valueType == FLOAT_VALUE_TYPE) { 169 return mInner.floatValue; 170 } else { 171 Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not float."); 172 return 0; 173 } 174 } 175 176 /** 177 * Retrieve the tuple, in the form of a {@link List} of {@link StatsDimensionsValue}, held, 178 * if any. 179 * 180 * @return the {@link List} of {@link StatsDimensionsValue} held 181 * if {@link #getValueType()} == {@link #TUPLE_VALUE_TYPE}, 182 * null otherwise 183 */ getTupleValueList()184 public List<StatsDimensionsValue> getTupleValueList() { 185 if (mInner.valueType == TUPLE_VALUE_TYPE) { 186 int length = (mInner.tupleValue == null) ? 0 : mInner.tupleValue.length; 187 List<StatsDimensionsValue> tupleValues = new ArrayList<>(length); 188 for (int i = 0; i < length; i++) { 189 tupleValues.add(new StatsDimensionsValue(mInner.tupleValue[i])); 190 } 191 return tupleValues; 192 } else { 193 Log.w(TAG, "Value type is " + getValueTypeAsString() + ", not tuple."); 194 return null; 195 } 196 } 197 198 /** 199 * Returns the constant representing the type of value stored, namely one of 200 * <ul> 201 * <li>{@link #STRING_VALUE_TYPE}</li> 202 * <li>{@link #INT_VALUE_TYPE}</li> 203 * <li>{@link #LONG_VALUE_TYPE}</li> 204 * <li>{@link #BOOLEAN_VALUE_TYPE}</li> 205 * <li>{@link #FLOAT_VALUE_TYPE}</li> 206 * <li>{@link #TUPLE_VALUE_TYPE}</li> 207 * </ul> 208 * 209 * @return the constant representing the type of value stored 210 */ getValueType()211 public int getValueType() { 212 return mInner.valueType; 213 } 214 215 /** 216 * Returns whether the type of value stored is equal to the given type. 217 * 218 * @param valueType int representing the type of value stored, as used in {@link #getValueType} 219 * @return true if {@link #getValueType()} is equal to {@code valueType}. 220 */ isValueType(int valueType)221 public boolean isValueType(int valueType) { 222 return mInner.valueType == valueType; 223 } 224 225 /** 226 * Returns a String representing the information in this StatsDimensionValue. 227 * No guarantees are made about the format of this String. 228 * 229 * @return String representation 230 * 231 * @hide 232 */ 233 // Follows the format of statsd's dimension.h toString. toString()234 public String toString() { 235 StringBuilder sb = new StringBuilder(); 236 sb.append(mInner.field); 237 sb.append(":"); 238 switch (mInner.valueType) { 239 case STRING_VALUE_TYPE: 240 sb.append(mInner.stringValue); 241 break; 242 case INT_VALUE_TYPE: 243 sb.append(String.valueOf(mInner.intValue)); 244 break; 245 case LONG_VALUE_TYPE: 246 sb.append(String.valueOf(mInner.longValue)); 247 break; 248 case BOOLEAN_VALUE_TYPE: 249 sb.append(String.valueOf(mInner.boolValue)); 250 break; 251 case FLOAT_VALUE_TYPE: 252 sb.append(String.valueOf(mInner.floatValue)); 253 break; 254 case TUPLE_VALUE_TYPE: 255 sb.append("{"); 256 int length = (mInner.tupleValue == null) ? 0 : mInner.tupleValue.length; 257 for (int i = 0; i < length; i++) { 258 StatsDimensionsValue child = new StatsDimensionsValue(mInner.tupleValue[i]); 259 sb.append(child.toString()); 260 sb.append("|"); 261 } 262 sb.append("}"); 263 break; 264 default: 265 Log.w(TAG, "Incorrect value type"); 266 break; 267 } 268 return sb.toString(); 269 } 270 271 /** 272 * Parcelable Creator for StatsDimensionsValue. 273 */ 274 public static final @android.annotation.NonNull 275 Parcelable.Creator<StatsDimensionsValue> CREATOR = new 276 Parcelable.Creator<StatsDimensionsValue>() { 277 public StatsDimensionsValue createFromParcel(Parcel in) { 278 return new StatsDimensionsValue(in); 279 } 280 281 public StatsDimensionsValue[] newArray(int size) { 282 return new StatsDimensionsValue[size]; 283 } 284 }; 285 286 @Override describeContents()287 public int describeContents() { 288 return 0; 289 } 290 291 @Override writeToParcel(Parcel out, int flags)292 public void writeToParcel(Parcel out, int flags) { 293 mInner.writeToParcel(out, flags); 294 } 295 296 /** 297 * Returns a string representation of the type of value stored. 298 */ getValueTypeAsString()299 private String getValueTypeAsString() { 300 switch (mInner.valueType) { 301 case STRING_VALUE_TYPE: 302 return "string"; 303 case INT_VALUE_TYPE: 304 return "int"; 305 case LONG_VALUE_TYPE: 306 return "long"; 307 case BOOLEAN_VALUE_TYPE: 308 return "boolean"; 309 case FLOAT_VALUE_TYPE: 310 return "float"; 311 case TUPLE_VALUE_TYPE: 312 return "tuple"; 313 default: 314 return "unknown"; 315 } 316 } 317 } 318