blob: da13ea13d5faacb0a502f124c79a76472806a620 [file] [log] [blame]
Bookatzc6977972018-01-16 16:55:05 -08001/*
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 */
16package android.os;
17
18import android.annotation.SystemApi;
19import android.util.Slog;
20
21import java.util.ArrayList;
22import 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
57public 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 services/include/android/os/StatsDimensionsValue.h.
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 /** Value of a stats_log.proto DimensionsValue.field. */
76 private final int mField;
77
78 /** Type of stats_log.proto DimensionsValue.value, according to the VALUE_TYPEs above. */
79 private final int mValueType;
80
81 /**
82 * Value of a stats_log.proto DimensionsValue.value.
83 * String, Integer, Long, Boolean, Float, or StatsDimensionsValue[].
84 */
85 private final Object mValue; // immutable or array of immutables
86
87 /**
88 * Creates a {@code StatsDimensionValue} from a parcel.
89 *
90 * @hide
91 */
92 public StatsDimensionsValue(Parcel in) {
93 mField = in.readInt();
94 mValueType = in.readInt();
95 mValue = readValueFromParcel(mValueType, in);
96 }
97
98 /**
99 * Return the field, i.e. the tag of a statsd atom.
100 *
101 * @return the field
102 */
103 public int getField() {
104 return mField;
105 }
106
107 /**
108 * Retrieve the String held, if any.
109 *
110 * @return the {@link String} held if {@link #getValueType()} == {@link #STRING_VALUE_TYPE},
111 * null otherwise
112 */
113 public String getStringValue() {
114 try {
115 if (mValueType == STRING_VALUE_TYPE) return (String) mValue;
116 } catch (ClassCastException e) {
117 Slog.w(TAG, "Failed to successfully get value", e);
118 }
119 return null;
120 }
121
122 /**
123 * Retrieve the int held, if any.
124 *
125 * @return the int held if {@link #getValueType()} == {@link #INT_VALUE_TYPE}, 0 otherwise
126 */
127 public int getIntValue() {
128 try {
129 if (mValueType == INT_VALUE_TYPE) return (Integer) mValue;
130 } catch (ClassCastException e) {
131 Slog.w(TAG, "Failed to successfully get value", e);
132 }
133 return 0;
134 }
135
136 /**
137 * Retrieve the long held, if any.
138 *
139 * @return the long held if {@link #getValueType()} == {@link #LONG_VALUE_TYPE}, 0 otherwise
140 */
141 public long getLongValue() {
142 try {
143 if (mValueType == LONG_VALUE_TYPE) return (Long) mValue;
144 } catch (ClassCastException e) {
145 Slog.w(TAG, "Failed to successfully get value", e);
146 }
147 return 0;
148 }
149
150 /**
151 * Retrieve the boolean held, if any.
152 *
153 * @return the boolean held if {@link #getValueType()} == {@link #BOOLEAN_VALUE_TYPE},
154 * false otherwise
155 */
156 public boolean getBooleanValue() {
157 try {
158 if (mValueType == BOOLEAN_VALUE_TYPE) return (Boolean) mValue;
159 } catch (ClassCastException e) {
160 Slog.w(TAG, "Failed to successfully get value", e);
161 }
162 return false;
163 }
164
165 /**
166 * Retrieve the float held, if any.
167 *
168 * @return the float held if {@link #getValueType()} == {@link #FLOAT_VALUE_TYPE}, 0 otherwise
169 */
170 public float getFloatValue() {
171 try {
172 if (mValueType == FLOAT_VALUE_TYPE) return (Float) mValue;
173 } catch (ClassCastException e) {
174 Slog.w(TAG, "Failed to successfully get value", e);
175 }
176 return 0;
177 }
178
179 /**
180 * Retrieve the tuple, in the form of a {@link List} of {@link StatsDimensionsValue}, held,
181 * if any.
182 *
183 * @return the {@link List} of {@link StatsDimensionsValue} held
184 * if {@link #getValueType()} == {@link #TUPLE_VALUE_TYPE},
185 * null otherwise
186 */
187 public List<StatsDimensionsValue> getTupleValueList() {
188 if (mValueType != TUPLE_VALUE_TYPE) {
189 return null;
190 }
191 try {
192 StatsDimensionsValue[] orig = (StatsDimensionsValue[]) mValue;
193 List<StatsDimensionsValue> copy = new ArrayList<>(orig.length);
194 // Shallow copy since StatsDimensionsValue is immutable anyway
195 for (int i = 0; i < orig.length; i++) {
196 copy.add(orig[i]);
197 }
198 return copy;
199 } catch (ClassCastException e) {
200 Slog.w(TAG, "Failed to successfully get value", e);
201 return null;
202 }
203 }
204
205 /**
206 * Returns the constant representing the type of value stored, namely one of
207 * <ul>
208 * <li>{@link #STRING_VALUE_TYPE}</li>
209 * <li>{@link #INT_VALUE_TYPE}</li>
210 * <li>{@link #LONG_VALUE_TYPE}</li>
211 * <li>{@link #BOOLEAN_VALUE_TYPE}</li>
212 * <li>{@link #FLOAT_VALUE_TYPE}</li>
213 * <li>{@link #TUPLE_VALUE_TYPE}</li>
214 * </ul>
215 *
216 * @return the constant representing the type of value stored
217 */
218 public int getValueType() {
219 return mValueType;
220 }
221
222 /**
223 * Returns whether the type of value stored is equal to the given type.
224 *
225 * @param valueType int representing the type of value stored, as used in {@link #getValueType}
226 * @return true if {@link #getValueType()} is equal to {@code valueType}.
227 */
228 public boolean isValueType(int valueType) {
229 return mValueType == valueType;
230 }
231
232 /**
233 * Returns a String representing the information in this StatsDimensionValue.
234 * No guarantees are made about the format of this String.
235 *
236 * @return String representation
237 *
238 * @hide
239 */
240 // Follows the format of statsd's dimension.h toString.
241 public String toString() {
242 try {
243 StringBuilder sb = new StringBuilder();
244 sb.append(mField);
245 sb.append(":");
246 if (mValueType == TUPLE_VALUE_TYPE) {
247 sb.append("{");
248 StatsDimensionsValue[] sbvs = (StatsDimensionsValue[]) mValue;
249 for (int i = 0; i < sbvs.length; i++) {
250 sb.append(sbvs[i].toString());
251 sb.append("|");
252 }
253 sb.append("}");
254 } else {
255 sb.append(mValue.toString());
256 }
257 return sb.toString();
258 } catch (ClassCastException e) {
259 Slog.w(TAG, "Failed to successfully get value", e);
260 }
261 return "";
262 }
263
264 /**
265 * Parcelable Creator for StatsDimensionsValue.
266 */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700267 public static final @android.annotation.NonNull Parcelable.Creator<StatsDimensionsValue> CREATOR = new
Bookatzc6977972018-01-16 16:55:05 -0800268 Parcelable.Creator<StatsDimensionsValue>() {
269 public StatsDimensionsValue createFromParcel(Parcel in) {
270 return new StatsDimensionsValue(in);
271 }
272
273 public StatsDimensionsValue[] newArray(int size) {
274 return new StatsDimensionsValue[size];
275 }
276 };
277
278 @Override
279 public int describeContents() {
280 return 0;
281 }
282
283 @Override
284 public void writeToParcel(Parcel out, int flags) {
285 out.writeInt(mField);
286 out.writeInt(mValueType);
287 writeValueToParcel(mValueType, mValue, out, flags);
288 }
289
290 /** Writes mValue to a parcel. Returns true if succeeds. */
291 private static boolean writeValueToParcel(int valueType, Object value, Parcel out, int flags) {
292 try {
293 switch (valueType) {
294 case STRING_VALUE_TYPE:
295 out.writeString((String) value);
296 return true;
297 case INT_VALUE_TYPE:
298 out.writeInt((Integer) value);
299 return true;
300 case LONG_VALUE_TYPE:
301 out.writeLong((Long) value);
302 return true;
303 case BOOLEAN_VALUE_TYPE:
304 out.writeBoolean((Boolean) value);
305 return true;
306 case FLOAT_VALUE_TYPE:
307 out.writeFloat((Float) value);
308 return true;
309 case TUPLE_VALUE_TYPE: {
310 StatsDimensionsValue[] values = (StatsDimensionsValue[]) value;
311 out.writeInt(values.length);
312 for (int i = 0; i < values.length; i++) {
313 values[i].writeToParcel(out, flags);
314 }
315 return true;
316 }
317 default:
318 Slog.w(TAG, "readValue of an impossible type " + valueType);
319 return false;
320 }
321 } catch (ClassCastException e) {
322 Slog.w(TAG, "writeValue cast failed", e);
323 return false;
324 }
325 }
326
327 /** Reads mValue from a parcel. */
328 private static Object readValueFromParcel(int valueType, Parcel parcel) {
329 switch (valueType) {
330 case STRING_VALUE_TYPE:
331 return parcel.readString();
332 case INT_VALUE_TYPE:
333 return parcel.readInt();
334 case LONG_VALUE_TYPE:
335 return parcel.readLong();
336 case BOOLEAN_VALUE_TYPE:
337 return parcel.readBoolean();
338 case FLOAT_VALUE_TYPE:
339 return parcel.readFloat();
340 case TUPLE_VALUE_TYPE: {
341 final int sz = parcel.readInt();
342 StatsDimensionsValue[] values = new StatsDimensionsValue[sz];
343 for (int i = 0; i < sz; i++) {
344 values[i] = new StatsDimensionsValue(parcel);
345 }
346 return values;
347 }
348 default:
349 Slog.w(TAG, "readValue of an impossible type " + valueType);
350 return null;
351 }
352 }
353}