blob: 89c9bb253524711c27c4129eb3f6a0837f586bbc [file] [log] [blame]
/*
* Copyright (C) 2017 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.util.Slog;
import java.util.ArrayList;
import java.util.List;
/**
* Wrapper class for sending data from Android OS to StatsD.
*
* @hide
*/
public final class StatsLogEventWrapper implements Parcelable {
static final boolean DEBUG = false;
static final String TAG = "StatsLogEventWrapper";
// Keep in sync with FieldValue.h enums
private static final int EVENT_TYPE_UNKNOWN = 0;
private static final int EVENT_TYPE_INT = 1; /* int32_t */
private static final int EVENT_TYPE_LONG = 2; /* int64_t */
private static final int EVENT_TYPE_FLOAT = 3;
private static final int EVENT_TYPE_DOUBLE = 4;
private static final int EVENT_TYPE_STRING = 5;
private static final int EVENT_TYPE_STORAGE = 6;
List<Integer> mTypes = new ArrayList<>();
List<Object> mValues = new ArrayList<>();
int mTag;
long mElapsedTimeNs;
long mWallClockTimeNs;
WorkSource mWorkSource = null;
public StatsLogEventWrapper(int tag, long elapsedTimeNs, long wallClockTimeNs) {
this.mTag = tag;
this.mElapsedTimeNs = elapsedTimeNs;
this.mWallClockTimeNs = wallClockTimeNs;
}
/**
* Boilerplate for Parcel.
*/
public static final @android.annotation.NonNull Parcelable.Creator<StatsLogEventWrapper> CREATOR = new
Parcelable.Creator<StatsLogEventWrapper>() {
public StatsLogEventWrapper createFromParcel(Parcel in) {
return new StatsLogEventWrapper(in);
}
public StatsLogEventWrapper[] newArray(int size) {
return new StatsLogEventWrapper[size];
}
};
private StatsLogEventWrapper(Parcel in) {
readFromParcel(in);
}
/**
* Set work source if any.
*/
public void setWorkSource(WorkSource ws) {
if (ws.getWorkChains() == null || ws.getWorkChains().size() == 0) {
Slog.w(TAG, "Empty worksource!");
return;
}
mWorkSource = ws;
}
/**
* Write a int value.
*/
public void writeInt(int val) {
mTypes.add(EVENT_TYPE_INT);
mValues.add(val);
}
/**
* Write a long value.
*/
public void writeLong(long val) {
mTypes.add(EVENT_TYPE_LONG);
mValues.add(val);
}
/**
* Write a string value.
*/
public void writeString(String val) {
mTypes.add(EVENT_TYPE_STRING);
// use empty string for null
mValues.add(val == null ? "" : val);
}
/**
* Write a float value.
*/
public void writeFloat(float val) {
mTypes.add(EVENT_TYPE_FLOAT);
mValues.add(val);
}
/**
* Write a storage value.
*/
public void writeStorage(byte[] val) {
mTypes.add(EVENT_TYPE_STORAGE);
mValues.add(val);
}
/**
* Write a boolean value.
*/
public void writeBoolean(boolean val) {
mTypes.add(EVENT_TYPE_INT);
mValues.add(val ? 1 : 0);
}
public void writeToParcel(Parcel out, int flags) {
if (DEBUG) {
Slog.d(TAG,
"Writing " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs + " and "
+ mTypes.size() + " elements.");
}
out.writeInt(mTag);
out.writeLong(mElapsedTimeNs);
out.writeLong(mWallClockTimeNs);
if (mWorkSource != null) {
ArrayList<android.os.WorkSource.WorkChain> workChains = mWorkSource.getWorkChains();
// number of chains
out.writeInt(workChains.size());
for (int i = 0; i < workChains.size(); i++) {
android.os.WorkSource.WorkChain wc = workChains.get(i);
if (wc.getSize() == 0) {
Slog.w(TAG, "Empty work chain.");
out.writeInt(0);
continue;
}
if (wc.getUids().length != wc.getTags().length
|| wc.getUids().length != wc.getSize()) {
Slog.w(TAG, "Malformated work chain.");
out.writeInt(0);
continue;
}
// number of nodes
out.writeInt(wc.getSize());
for (int j = 0; j < wc.getSize(); j++) {
out.writeInt(wc.getUids()[j]);
out.writeString(wc.getTags()[j] == null ? "" : wc.getTags()[j]);
}
}
} else {
// no chains
out.writeInt(0);
}
out.writeInt(mTypes.size());
for (int i = 0; i < mTypes.size(); i++) {
out.writeInt(mTypes.get(i));
switch (mTypes.get(i)) {
case EVENT_TYPE_INT:
out.writeInt((int) mValues.get(i));
break;
case EVENT_TYPE_LONG:
out.writeLong((long) mValues.get(i));
break;
case EVENT_TYPE_FLOAT:
out.writeFloat((float) mValues.get(i));
break;
case EVENT_TYPE_DOUBLE:
out.writeDouble((double) mValues.get(i));
break;
case EVENT_TYPE_STRING:
out.writeString((String) mValues.get(i));
break;
case EVENT_TYPE_STORAGE:
out.writeByteArray((byte[]) mValues.get(i));
break;
default:
break;
}
}
}
/**
* Reads from parcel and appropriately fills member fields.
*/
public void readFromParcel(Parcel in) {
mTypes = new ArrayList<>();
mValues = new ArrayList<>();
mWorkSource = null;
mTag = in.readInt();
mElapsedTimeNs = in.readLong();
mWallClockTimeNs = in.readLong();
// Clear any data.
if (DEBUG) {
Slog.d(TAG, "Reading " + mTag + " " + mElapsedTimeNs + " " + mWallClockTimeNs);
}
// Set up worksource if present.
int numWorkChains = in.readInt();
if (numWorkChains > 0) {
mWorkSource = new WorkSource();
for (int i = 0; i < numWorkChains; i++) {
android.os.WorkSource.WorkChain workChain = mWorkSource.createWorkChain();
int workChainSize = in.readInt();
for (int j = 0; j < workChainSize; j++) {
int uid = in.readInt();
String tag = in.readString();
workChain.addNode(uid, tag);
}
}
}
// Do the rest of the types.
int numTypes = in.readInt();
if (DEBUG) {
Slog.d(TAG, "Reading " + numTypes + " elements");
}
for (int i = 0; i < numTypes; i++) {
int type = in.readInt();
mTypes.add(type);
switch (type) {
case EVENT_TYPE_INT:
mValues.add(in.readInt());
break;
case EVENT_TYPE_LONG:
mValues.add(in.readLong());
break;
case EVENT_TYPE_FLOAT:
mValues.add(in.readFloat());
break;
case EVENT_TYPE_DOUBLE:
mValues.add(in.readDouble());
break;
case EVENT_TYPE_STRING:
mValues.add(in.readString());
break;
case EVENT_TYPE_STORAGE:
mValues.add(in.createByteArray());
break;
default:
break;
}
}
}
/**
* Boilerplate for Parcel.
*/
public int describeContents() {
return 0;
}
}