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 android.util.EventLog.writeEvent(0x534e4554, "112550251", 69 android.os.Binder.getCallingUid(), ""); 70 // Purposefully leaving this method not implemented. 71 throw new RuntimeException("Not implemented"); 72 } 73 74 public StatsLogEventWrapper[] newArray(int size) { 75 android.util.EventLog.writeEvent(0x534e4554, "112550251", 76 android.os.Binder.getCallingUid(), ""); 77 // Purposefully leaving this method not implemented. 78 throw new RuntimeException("Not implemented"); 79 } 80 }; 81 write4Bytes(int val)82 private void write4Bytes(int val) { 83 mStorage.write(val); 84 mStorage.write(val >>> 8); 85 mStorage.write(val >>> 16); 86 mStorage.write(val >>> 24); 87 } 88 write8Bytes(long val)89 private void write8Bytes(long val) { 90 write4Bytes((int) (val & 0xFFFFFFFF)); // keep the lowe 32-bits 91 write4Bytes((int) (val >>> 32)); // Write the high 32-bits. 92 } 93 94 /** 95 * Adds 32-bit integer to output. 96 */ writeInt(int val)97 public void writeInt(int val) { 98 mStorage.write(EVENT_TYPE_INT); 99 write4Bytes(val); 100 } 101 102 /** 103 * Adds 64-bit long to output. 104 */ writeLong(long val)105 public void writeLong(long val) { 106 mStorage.write(EVENT_TYPE_LONG); 107 write8Bytes(val); 108 } 109 110 /** 111 * Adds a 4-byte floating point value to output. 112 */ writeFloat(float val)113 public void writeFloat(float val) { 114 int v = Float.floatToIntBits(val); 115 mStorage.write(EVENT_TYPE_FLOAT); 116 write4Bytes(v); 117 } 118 119 /** 120 * Adds a string to the output. 121 */ writeString(String val)122 public void writeString(String val) { 123 mStorage.write(EVENT_TYPE_STRING); 124 write4Bytes(val.length()); 125 byte[] bytes = val.getBytes(StandardCharsets.UTF_8); 126 mStorage.write(bytes, 0, bytes.length); 127 } 128 129 /** 130 * Writes the stored fields to a byte array. Will first write a new-line character to denote 131 * END_LIST before writing contents to byte array. 132 */ writeToParcel(Parcel out, int flags)133 public void writeToParcel(Parcel out, int flags) { 134 mStorage.write(10); // new-line character is same as END_LIST 135 out.writeByteArray(mStorage.toByteArray()); 136 } 137 138 /** 139 * Boilerplate for Parcel. 140 */ describeContents()141 public int describeContents() { 142 return 0; 143 } 144 } 145