summaryrefslogtreecommitdiff
path: root/android/os/StatsDimensionsValue.java
blob: 257cc5250dadb4f3329f75c2ce93605523c948ed (plain)
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
/*
 * Copyright 2018 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.SystemApi;
import android.util.Slog;

import java.util.ArrayList;
import java.util.List;

/**
 * Container for statsd dimension value information, corresponding to a
 * stats_log.proto's DimensionValue.
 *
 * This consists of a field (an int representing a statsd atom field)
 * and a value (which may be one of a number of types).
 *
 * <p>
 * Only a single value is held, and it is necessarily one of the following types:
 * {@link String}, int, long, boolean, float,
 * or tuple (i.e. {@link List} of {@code StatsDimensionsValue}).
 *
 * The type of value held can be retrieved using {@link #getValueType()}, which returns one of the
 * following ints, depending on the type of value:
 * <ul>
 *  <li>{@link #STRING_VALUE_TYPE}</li>
 *  <li>{@link #INT_VALUE_TYPE}</li>
 *  <li>{@link #LONG_VALUE_TYPE}</li>
 *  <li>{@link #BOOLEAN_VALUE_TYPE}</li>
 *  <li>{@link #FLOAT_VALUE_TYPE}</li>
 *  <li>{@link #TUPLE_VALUE_TYPE}</li>
 * </ul>
 * Alternatively, this can be determined using {@link #isValueType(int)} with one of these constants
 * as a parameter.
 * The value itself can be retrieved using the correct get...Value() function for its type.
 *
 * <p>
 * The field is always an int, and always exists; it can be obtained using {@link #getField()}.
 *
 *
 * @hide
 */
@SystemApi
public final class StatsDimensionsValue implements Parcelable {
    private static final String TAG = "StatsDimensionsValue";

    // Values of the value type correspond to stats_log.proto's DimensionValue fields.
    // Keep constants in sync with services/include/android/os/StatsDimensionsValue.h.
    /** Indicates that this holds a String. */
    public static final int STRING_VALUE_TYPE = 2;
    /** Indicates that this holds an int. */
    public static final int INT_VALUE_TYPE = 3;
    /** Indicates that this holds a long. */
    public static final int LONG_VALUE_TYPE = 4;
    /** Indicates that this holds a boolean. */
    public static final int BOOLEAN_VALUE_TYPE = 5;
    /** Indicates that this holds a float. */
    public static final int FLOAT_VALUE_TYPE = 6;
    /** Indicates that this holds a List of StatsDimensionsValues. */
    public static final int TUPLE_VALUE_TYPE = 7;

    /** Value of a stats_log.proto DimensionsValue.field. */
    private final int mField;

    /** Type of stats_log.proto DimensionsValue.value, according to the VALUE_TYPEs above. */
    private final int mValueType;

    /**
     * Value of a stats_log.proto DimensionsValue.value.
     * String, Integer, Long, Boolean, Float, or StatsDimensionsValue[].
     */
    private final Object mValue; // immutable or array of immutables

    /**
     * Creates a {@code StatsDimensionValue} from a parcel.
     *
     * @hide
     */
    public StatsDimensionsValue(Parcel in) {
        mField = in.readInt();
        mValueType = in.readInt();
        mValue = readValueFromParcel(mValueType, in);
    }

    /**
     * Return the field, i.e. the tag of a statsd atom.
     *
     * @return the field
     */
    public int getField() {
        return mField;
    }

    /**
     * Retrieve the String held, if any.
     *
     * @return the {@link String} held if {@link #getValueType()} == {@link #STRING_VALUE_TYPE},
     *         null otherwise
     */
    public String getStringValue() {
        try {
            if (mValueType == STRING_VALUE_TYPE) return (String) mValue;
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
        }
        return null;
    }

    /**
     * Retrieve the int held, if any.
     *
     * @return the int held if {@link #getValueType()} == {@link #INT_VALUE_TYPE}, 0 otherwise
     */
    public int getIntValue() {
        try {
            if (mValueType == INT_VALUE_TYPE) return (Integer) mValue;
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
        }
        return 0;
    }

    /**
     * Retrieve the long held, if any.
     *
     * @return the long held if {@link #getValueType()} == {@link #LONG_VALUE_TYPE}, 0 otherwise
     */
    public long getLongValue() {
        try {
            if (mValueType == LONG_VALUE_TYPE) return (Long) mValue;
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
        }
        return 0;
    }

    /**
     * Retrieve the boolean held, if any.
     *
     * @return the boolean held if {@link #getValueType()} == {@link #BOOLEAN_VALUE_TYPE},
     *         false otherwise
     */
    public boolean getBooleanValue() {
        try {
            if (mValueType == BOOLEAN_VALUE_TYPE) return (Boolean) mValue;
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
        }
        return false;
    }

    /**
     * Retrieve the float held, if any.
     *
     * @return the float held if {@link #getValueType()} == {@link #FLOAT_VALUE_TYPE}, 0 otherwise
     */
    public float getFloatValue() {
        try {
            if (mValueType == FLOAT_VALUE_TYPE) return (Float) mValue;
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
        }
        return 0;
    }

    /**
     * Retrieve the tuple, in the form of a {@link List} of {@link StatsDimensionsValue}, held,
     * if any.
     *
     * @return the {@link List} of {@link StatsDimensionsValue} held
     *         if {@link #getValueType()} == {@link #TUPLE_VALUE_TYPE},
     *         null otherwise
     */
    public List<StatsDimensionsValue> getTupleValueList() {
        if (mValueType != TUPLE_VALUE_TYPE) {
            return null;
        }
        try {
            StatsDimensionsValue[] orig = (StatsDimensionsValue[]) mValue;
            List<StatsDimensionsValue> copy = new ArrayList<>(orig.length);
            // Shallow copy since StatsDimensionsValue is immutable anyway
            for (int i = 0; i < orig.length; i++) {
                copy.add(orig[i]);
            }
            return copy;
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
            return null;
        }
    }

    /**
     * Returns the constant representing the type of value stored, namely one of
     * <ul>
     *   <li>{@link #STRING_VALUE_TYPE}</li>
     *   <li>{@link #INT_VALUE_TYPE}</li>
     *   <li>{@link #LONG_VALUE_TYPE}</li>
     *   <li>{@link #BOOLEAN_VALUE_TYPE}</li>
     *   <li>{@link #FLOAT_VALUE_TYPE}</li>
     *   <li>{@link #TUPLE_VALUE_TYPE}</li>
     * </ul>
     *
     * @return the constant representing the type of value stored
     */
    public int getValueType() {
        return mValueType;
    }

    /**
     * Returns whether the type of value stored is equal to the given type.
     *
     * @param valueType int representing the type of value stored, as used in {@link #getValueType}
     * @return true if {@link #getValueType()} is equal to {@code valueType}.
     */
    public boolean isValueType(int valueType) {
        return mValueType == valueType;
    }

    /**
     * Returns a String representing the information in this StatsDimensionValue.
     * No guarantees are made about the format of this String.
     *
     * @return String representation
     *
     * @hide
     */
    // Follows the format of statsd's dimension.h toString.
    public String toString() {
        try {
            StringBuilder sb = new StringBuilder();
            sb.append(mField);
            sb.append(":");
            if (mValueType == TUPLE_VALUE_TYPE) {
                sb.append("{");
                StatsDimensionsValue[] sbvs = (StatsDimensionsValue[]) mValue;
                for (int i = 0; i < sbvs.length; i++) {
                    sb.append(sbvs[i].toString());
                    sb.append("|");
                }
                sb.append("}");
            } else {
                sb.append(mValue.toString());
            }
            return sb.toString();
        } catch (ClassCastException e) {
            Slog.w(TAG, "Failed to successfully get value", e);
        }
        return "";
    }

    /**
     * Parcelable Creator for StatsDimensionsValue.
     */
    public static final Parcelable.Creator<StatsDimensionsValue> CREATOR = new
            Parcelable.Creator<StatsDimensionsValue>() {
                public StatsDimensionsValue createFromParcel(Parcel in) {
                    return new StatsDimensionsValue(in);
                }

                public StatsDimensionsValue[] newArray(int size) {
                    return new StatsDimensionsValue[size];
                }
            };

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel out, int flags) {
        out.writeInt(mField);
        out.writeInt(mValueType);
        writeValueToParcel(mValueType, mValue, out, flags);
    }

    /** Writes mValue to a parcel. Returns true if succeeds. */
    private static boolean writeValueToParcel(int valueType, Object value, Parcel out, int flags) {
        try {
            switch (valueType) {
                case STRING_VALUE_TYPE:
                    out.writeString((String) value);
                    return true;
                case INT_VALUE_TYPE:
                    out.writeInt((Integer) value);
                    return true;
                case LONG_VALUE_TYPE:
                    out.writeLong((Long) value);
                    return true;
                case BOOLEAN_VALUE_TYPE:
                    out.writeBoolean((Boolean) value);
                    return true;
                case FLOAT_VALUE_TYPE:
                    out.writeFloat((Float) value);
                    return true;
                case TUPLE_VALUE_TYPE: {
                    StatsDimensionsValue[] values = (StatsDimensionsValue[]) value;
                    out.writeInt(values.length);
                    for (int i = 0; i < values.length; i++) {
                        values[i].writeToParcel(out, flags);
                    }
                    return true;
                }
                default:
                    Slog.w(TAG, "readValue of an impossible type " + valueType);
                    return false;
            }
        } catch (ClassCastException e) {
            Slog.w(TAG, "writeValue cast failed", e);
            return false;
        }
    }

    /** Reads mValue from a parcel. */
    private static Object readValueFromParcel(int valueType, Parcel parcel) {
        switch (valueType) {
            case STRING_VALUE_TYPE:
                return parcel.readString();
            case INT_VALUE_TYPE:
                return parcel.readInt();
            case LONG_VALUE_TYPE:
                return parcel.readLong();
            case BOOLEAN_VALUE_TYPE:
                return parcel.readBoolean();
            case FLOAT_VALUE_TYPE:
                return parcel.readFloat();
            case TUPLE_VALUE_TYPE: {
                final int sz = parcel.readInt();
                StatsDimensionsValue[] values = new StatsDimensionsValue[sz];
                for (int i = 0; i < sz; i++) {
                    values[i] = new StatsDimensionsValue(parcel);
                }
                return values;
            }
            default:
                Slog.w(TAG, "readValue of an impossible type " + valueType);
                return null;
        }
    }
}