• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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