Home | History | Annotate | Download | only in os
      1 /*
      2  * Copyright (C) 2017 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.util.Slog;
     19 
     20 import java.util.ArrayList;
     21 import java.util.List;
     22 
     23 /**
     24  * Wrapper class for sending data from Android OS to StatsD.
     25  *
     26  * @hide
     27  */
     28 public final class StatsLogEventWrapper implements Parcelable {
     29     static final boolean DEBUG = false;
     30     static final String TAG = "StatsLogEventWrapper";
     31 
     32     // Keep in sync with FieldValue.h enums
     33     private static final int EVENT_TYPE_UNKNOWN = 0;
     34     private static final int EVENT_TYPE_INT = 1; /* int32_t */
     35     private static final int EVENT_TYPE_LONG = 2; /* int64_t */
     36     private static final int EVENT_TYPE_FLOAT = 3;
     37     private static final int EVENT_TYPE_DOUBLE = 4;
     38     private static final int EVENT_TYPE_STRING = 5;
     39     private static final int EVENT_TYPE_STORAGE = 6;
     40 
     41     List<Integer> mTypes = new ArrayList<>();
     42     List<Object> mValues = new ArrayList<>();
     43     int mTag;
     44     long mElapsedTimeNs;
     45     long mWallClockTimeNs;
     46     WorkSource mWorkSource = null;
     47 
     48     public StatsLogEventWrapper(int tag, long elapsedTimeNs, long wallClockTimeNs) {
     49         this.mTag = tag;
     50         this.mElapsedTimeNs = elapsedTimeNs;
     51         this.mWallClockTimeNs = wallClockTimeNs;
     52     }
     53 
     54     /**
     55      * Boilerplate for Parcel.
     56      */
     57     public static final @android.annotation.NonNull Parcelable.Creator<StatsLogEventWrapper> CREATOR = new
     58             Parcelable.Creator<StatsLogEventWrapper>() {
     59                 public StatsLogEventWrapper createFromParcel(Parcel in) {
     60                     return new StatsLogEventWrapper(in);
     61                 }
     62 
     63                 public StatsLogEventWrapper[] newArray(int size) {
     64                     return new StatsLogEventWrapper[size];
     65                 }
     66             };
     67 
     68     private StatsLogEventWrapper(Parcel in) {
     69         readFromParcel(in);
     70     }
     71 
     72     /**
     73      * Set work source if any.
     74      */
     75     public void setWorkSource(WorkSource ws) {
     76         if (ws.getWorkChains() == null || ws.getWorkChains().size() == 0) {
     77             Slog.w(TAG, "Empty worksource!");
     78             return;
     79         }
     80         mWorkSource = ws;
     81     }
     82 
     83     /**
     84      * Write a int value.
     85      */
     86     public void writeInt(int val) {
     87         mTypes.add(EVENT_TYPE_INT);
     88         mValues.add(val);
     89     }
     90 
     91     /**
     92      * Write a long value.
     93      */
     94     public void writeLong(long val) {
     95         mTypes.add(EVENT_TYPE_LONG);
     96         mValues.add(val);
     97     }
     98 
     99     /**
    100      * Write a string value.
    101      */
    102     public void writeString(String val) {
    103         mTypes.add(EVENT_TYPE_STRING);
    104         // use empty string for null
    105         mValues.add(val == null ? "" : val);
    106     }
    107 
    108     /**
    109      * Write a float value.
    110      */
    111     public void writeFloat(float val) {
    112         mTypes.add(EVENT_TYPE_FLOAT);
    113         mValues.add(val);
    114     }
    115 
    116     /**
    117      * Write a storage value.
    118      */
    119     public void writeStorage(byte[] val) {
    120         mTypes.add(EVENT_TYPE_STORAGE);
    121         mValues.add(val);
    122     }
    123 
    124     /**
    125      * Write a boolean value.
    126      */
    127     public void writeBoolean(boolean val) {
    128         mTypes.add(EVENT_TYPE_INT);
    129         mValues.add(val ? 1 : 0);
    130     }
    131 
    132     public void writeToParcel(Parcel out, int flags) {
    133         if (DEBUG) {
    134             Slog.d(TAG,
    135                     "Writing " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs + " and "
    136                             + mTypes.size() + " elements.");
    137         }
    138         out.writeInt(mTag);
    139         out.writeLong(mElapsedTimeNs);
    140         out.writeLong(mWallClockTimeNs);
    141         if (mWorkSource != null) {
    142             ArrayList<android.os.WorkSource.WorkChain> workChains = mWorkSource.getWorkChains();
    143             // number of chains
    144             out.writeInt(workChains.size());
    145             for (int i = 0; i < workChains.size(); i++) {
    146                 android.os.WorkSource.WorkChain wc = workChains.get(i);
    147                 if (wc.getSize() == 0) {
    148                     Slog.w(TAG, "Empty work chain.");
    149                     out.writeInt(0);
    150                     continue;
    151                 }
    152                 if (wc.getUids().length != wc.getTags().length
    153                         || wc.getUids().length != wc.getSize()) {
    154                     Slog.w(TAG, "Malformated work chain.");
    155                     out.writeInt(0);
    156                     continue;
    157                 }
    158                 // number of nodes
    159                 out.writeInt(wc.getSize());
    160                 for (int j = 0; j < wc.getSize(); j++) {
    161                     out.writeInt(wc.getUids()[j]);
    162                     out.writeString(wc.getTags()[j] == null ? "" : wc.getTags()[j]);
    163                 }
    164             }
    165         } else {
    166             // no chains
    167             out.writeInt(0);
    168         }
    169         out.writeInt(mTypes.size());
    170         for (int i = 0; i < mTypes.size(); i++) {
    171             out.writeInt(mTypes.get(i));
    172             switch (mTypes.get(i)) {
    173                 case EVENT_TYPE_INT:
    174                     out.writeInt((int) mValues.get(i));
    175                     break;
    176                 case EVENT_TYPE_LONG:
    177                     out.writeLong((long) mValues.get(i));
    178                     break;
    179                 case EVENT_TYPE_FLOAT:
    180                     out.writeFloat((float) mValues.get(i));
    181                     break;
    182                 case EVENT_TYPE_DOUBLE:
    183                     out.writeDouble((double) mValues.get(i));
    184                     break;
    185                 case EVENT_TYPE_STRING:
    186                     out.writeString((String) mValues.get(i));
    187                     break;
    188                 case EVENT_TYPE_STORAGE:
    189                     out.writeByteArray((byte[]) mValues.get(i));
    190                     break;
    191                 default:
    192                     break;
    193             }
    194         }
    195     }
    196 
    197     /**
    198      * Reads from parcel and appropriately fills member fields.
    199      */
    200     public void readFromParcel(Parcel in) {
    201         mTypes = new ArrayList<>();
    202         mValues = new ArrayList<>();
    203         mWorkSource = null;
    204 
    205         mTag = in.readInt();
    206         mElapsedTimeNs = in.readLong();
    207         mWallClockTimeNs = in.readLong();
    208 
    209         // Clear any data.
    210         if (DEBUG) {
    211             Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs);
    212         }
    213         // Set up worksource if present.
    214         int numWorkChains = in.readInt();
    215         if (numWorkChains > 0) {
    216             mWorkSource = new WorkSource();
    217             for (int i = 0; i < numWorkChains; i++) {
    218                 android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain();
    219                 int workChainSize = in.readInt();
    220                 for (int j = 0; j < workChainSize; j++) {
    221                     int uid = in.readInt();
    222                     String tag = in.readString();
    223                     workChain.addNode(uid, tag);
    224                 }
    225             }
    226         }
    227 
    228         // Do the rest of the types.
    229         int numTypes = in.readInt();
    230         if (DEBUG) {
    231             Slog.d(TAG, "Reading " + numTypes + " elements");
    232         }
    233         for (int i = 0; i < numTypes; i++) {
    234             int type = in.readInt();
    235             mTypes.add(type);
    236             switch (type) {
    237                 case EVENT_TYPE_INT:
    238                     mValues.add(in.readInt());
    239                     break;
    240                 case EVENT_TYPE_LONG:
    241                     mValues.add(in.readLong());
    242                     break;
    243                 case EVENT_TYPE_FLOAT:
    244                     mValues.add(in.readFloat());
    245                     break;
    246                 case EVENT_TYPE_DOUBLE:
    247                     mValues.add(in.readDouble());
    248                     break;
    249                 case EVENT_TYPE_STRING:
    250                     mValues.add(in.readString());
    251                     break;
    252                 case EVENT_TYPE_STORAGE:
    253                     mValues.add(in.createByteArray());
    254                     break;
    255                 default:
    256                     break;
    257             }
    258         }
    259     }
    260 
    261     /**
    262      * Boilerplate for Parcel.
    263      */
    264     public int describeContents() {
    265         return 0;
    266     }
    267 }
    268