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 java.io.ByteArrayOutputStream; 19 import java.nio.charset.StandardCharsets; 20 21 /** 22 * Wrapper class for sending data from Android OS to StatsD. 23 * 24 * @hide 25 */ 26 public final class StatsLogEventWrapper implements Parcelable { 27 private ByteArrayOutputStream mStorage = new ByteArrayOutputStream(); 28 29 // Below are constants copied from log/log.h 30 private static final int EVENT_TYPE_INT = 0; /* int32_t */ 31 private static final int EVENT_TYPE_LONG = 1; /* int64_t */ 32 private static final int EVENT_TYPE_STRING = 2; 33 private static final int EVENT_TYPE_LIST = 3; 34 private static final int EVENT_TYPE_FLOAT = 4; 35 36 // Keep this in sync with system/core/logcat/event.logtags 37 private static final int STATS_BUFFER_TAG_ID = 1937006964; 38 /** 39 * Creates a log_event that is binary-encoded as implemented in 40 * system/core/liblog/log_event_list.c; this allows us to use the same parsing logic in statsd 41 * for pushed and pulled data. The write* methods must be called in the same order as their 42 * field number. There is no checking that the correct number of write* methods is called. 43 * We also write an END_LIST character before beginning to write to parcel, but this END_LIST 44 * may be unnecessary. 45 * 46 * @param tag The integer representing the tag for this event. 47 * @param fields The number of fields specified in this event. 48 */ StatsLogEventWrapper(long elapsedNanos, int tag, int fields)49 public StatsLogEventWrapper(long elapsedNanos, int tag, int fields) { 50 // Write four bytes from tag, starting with least-significant bit. 51 // For pulled data, this tag number is not really used. We use the same tag number as 52 // pushed ones to be consistent. 53 write4Bytes(STATS_BUFFER_TAG_ID); 54 mStorage.write(EVENT_TYPE_LIST); // This is required to start the log entry. 55 mStorage.write(fields + 2); // Indicate number of elements in this list. +1 for the tag 56 // The first element is the elapsed realtime. 57 writeLong(elapsedNanos); 58 // The second element is the real atom tag number 59 writeInt(tag); 60 } 61 62 /** 63 * Boilerplate for Parcel. 64 */ 65 public static final Parcelable.Creator<StatsLogEventWrapper> CREATOR = new 66 Parcelable.Creator<StatsLogEventWrapper>() { 67 public StatsLogEventWrapper createFromParcel(Parcel in) { 68 return new StatsLogEventWrapper(in); 69 } 70 71 public StatsLogEventWrapper[] newArray(int size) { 72 return new StatsLogEventWrapper[size]; 73 } 74 }; 75 write4Bytes(int val)76 private void write4Bytes(int val) { 77 mStorage.write(val); 78 mStorage.write(val >>> 8); 79 mStorage.write(val >>> 16); 80 mStorage.write(val >>> 24); 81 } 82 write8Bytes(long val)83 private void write8Bytes(long val) { 84 write4Bytes((int) (val & 0xFFFFFFFF)); // keep the lowe 32-bits 85 write4Bytes((int) (val >>> 32)); // Write the high 32-bits. 86 } 87 88 /** 89 * Adds 32-bit integer to output. 90 */ writeInt(int val)91 public void writeInt(int val) { 92 mStorage.write(EVENT_TYPE_INT); 93 write4Bytes(val); 94 } 95 96 /** 97 * Adds 64-bit long to output. 98 */ writeLong(long val)99 public void writeLong(long val) { 100 mStorage.write(EVENT_TYPE_LONG); 101 write8Bytes(val); 102 } 103 104 /** 105 * Adds a 4-byte floating point value to output. 106 */ writeFloat(float val)107 public void writeFloat(float val) { 108 int v = Float.floatToIntBits(val); 109 mStorage.write(EVENT_TYPE_FLOAT); 110 write4Bytes(v); 111 } 112 113 /** 114 * Adds a string to the output. 115 */ writeString(String val)116 public void writeString(String val) { 117 mStorage.write(EVENT_TYPE_STRING); 118 write4Bytes(val.length()); 119 byte[] bytes = val.getBytes(StandardCharsets.UTF_8); 120 mStorage.write(bytes, 0, bytes.length); 121 } 122 StatsLogEventWrapper(Parcel in)123 private StatsLogEventWrapper(Parcel in) { 124 readFromParcel(in); 125 } 126 127 /** 128 * Writes the stored fields to a byte array. Will first write a new-line character to denote 129 * END_LIST before writing contents to byte array. 130 */ writeToParcel(Parcel out, int flags)131 public void writeToParcel(Parcel out, int flags) { 132 mStorage.write(10); // new-line character is same as END_LIST 133 out.writeByteArray(mStorage.toByteArray()); 134 } 135 136 /** 137 * Not implemented. 138 */ readFromParcel(Parcel in)139 public void readFromParcel(Parcel in) { 140 // Not needed since this java class is for sending to statsd only. 141 } 142 143 /** 144 * Boilerplate for Parcel. 145 */ describeContents()146 public int describeContents() { 147 return 0; 148 } 149 } 150