Home | History | Annotate | Download | only in os
      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.Slog;
     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 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      */
    267     public static final Parcelable.Creator<StatsDimensionsValue> CREATOR = new
    268             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 }
    354