1 /*
2 * Copyright (C) 2019 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
17 #include "stats_event.h"
18 #include <gtest/gtest.h>
19 #include <utils/SystemClock.h>
20
21 using std::string;
22 using std::vector;
23
24 // Side-effect: this function moves the start of the buffer past the read value
25 template <class T>
readNext(uint8_t ** buffer)26 T readNext(uint8_t** buffer) {
27 T value = *(T*)(*buffer);
28 *buffer += sizeof(T);
29 return value;
30 }
31
checkTypeHeader(uint8_t ** buffer,uint8_t typeId,uint8_t numAnnotations=0)32 void checkTypeHeader(uint8_t** buffer, uint8_t typeId, uint8_t numAnnotations = 0) {
33 uint8_t typeHeader = (numAnnotations << 4) | typeId;
34 EXPECT_EQ(readNext<uint8_t>(buffer), typeHeader);
35 }
36
37 template <class T>
checkScalar(uint8_t ** buffer,T expectedValue)38 void checkScalar(uint8_t** buffer, T expectedValue) {
39 EXPECT_EQ(readNext<T>(buffer), expectedValue);
40 }
41
checkString(uint8_t ** buffer,const string & expectedString)42 void checkString(uint8_t** buffer, const string& expectedString) {
43 uint32_t size = readNext<uint32_t>(buffer);
44 string parsedString((char*)(*buffer), size);
45 EXPECT_EQ(parsedString, expectedString);
46 *buffer += size; // move buffer past string we just read
47 }
48
checkByteArray(uint8_t ** buffer,const vector<uint8_t> & expectedByteArray)49 void checkByteArray(uint8_t** buffer, const vector<uint8_t>& expectedByteArray) {
50 uint32_t size = readNext<uint32_t>(buffer);
51 vector<uint8_t> parsedByteArray(*buffer, *buffer + size);
52 EXPECT_EQ(parsedByteArray, expectedByteArray);
53 *buffer += size; // move buffer past byte array we just read
54 }
55
56 template <class T>
checkAnnotation(uint8_t ** buffer,uint8_t annotationId,uint8_t typeId,T annotationValue)57 void checkAnnotation(uint8_t** buffer, uint8_t annotationId, uint8_t typeId, T annotationValue) {
58 EXPECT_EQ(readNext<uint8_t>(buffer), annotationId);
59 EXPECT_EQ(readNext<uint8_t>(buffer), typeId);
60 checkScalar<T>(buffer, annotationValue);
61 }
62
checkMetadata(uint8_t ** buffer,uint8_t numElements,int64_t startTime,int64_t endTime,uint32_t atomId)63 void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
64 uint32_t atomId) {
65 // All events start with OBJECT_TYPE id.
66 checkTypeHeader(buffer, OBJECT_TYPE);
67
68 // We increment by 2 because the number of elements listed in the
69 // serialization accounts for the timestamp and atom id as well.
70 checkScalar(buffer, static_cast<uint8_t>(numElements + 2));
71
72 // Check timestamp
73 checkTypeHeader(buffer, INT64_TYPE);
74 int64_t timestamp = readNext<int64_t>(buffer);
75 EXPECT_GE(timestamp, startTime);
76 EXPECT_LE(timestamp, endTime);
77
78 // Check atom id
79 checkTypeHeader(buffer, INT32_TYPE);
80 checkScalar(buffer, atomId);
81 }
82
TEST(StatsEventTest,TestScalars)83 TEST(StatsEventTest, TestScalars) {
84 uint32_t atomId = 100;
85 int32_t int32Value = -5;
86 int64_t int64Value = -2 * android::elapsedRealtimeNano();
87 float floatValue = 2.0;
88 bool boolValue = false;
89
90 int64_t startTime = android::elapsedRealtimeNano();
91 struct stats_event* event = stats_event_obtain();
92 stats_event_set_atom_id(event, atomId);
93 stats_event_write_int32(event, int32Value);
94 stats_event_write_int64(event, int64Value);
95 stats_event_write_float(event, floatValue);
96 stats_event_write_bool(event, boolValue);
97 stats_event_build(event);
98 int64_t endTime = android::elapsedRealtimeNano();
99
100 size_t bufferSize;
101 uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
102 uint8_t* bufferEnd = buffer + bufferSize;
103
104 checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
105
106 // check int32 element
107 checkTypeHeader(&buffer, INT32_TYPE);
108 checkScalar(&buffer, int32Value);
109
110 // check int64 element
111 checkTypeHeader(&buffer, INT64_TYPE);
112 checkScalar(&buffer, int64Value);
113
114 // check float element
115 checkTypeHeader(&buffer, FLOAT_TYPE);
116 checkScalar(&buffer, floatValue);
117
118 // check bool element
119 checkTypeHeader(&buffer, BOOL_TYPE);
120 checkScalar(&buffer, boolValue);
121
122 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
123 EXPECT_EQ(stats_event_get_errors(event), 0);
124 stats_event_release(event);
125 }
126
TEST(StatsEventTest,TestStrings)127 TEST(StatsEventTest, TestStrings) {
128 uint32_t atomId = 100;
129 string str = "test_string";
130
131 int64_t startTime = android::elapsedRealtimeNano();
132 struct stats_event* event = stats_event_obtain();
133 stats_event_set_atom_id(event, atomId);
134 stats_event_write_string8(event, str.c_str());
135 stats_event_build(event);
136 int64_t endTime = android::elapsedRealtimeNano();
137
138 size_t bufferSize;
139 uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
140 uint8_t* bufferEnd = buffer + bufferSize;
141
142 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
143
144 checkTypeHeader(&buffer, STRING_TYPE);
145 checkString(&buffer, str);
146
147 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
148 EXPECT_EQ(stats_event_get_errors(event), 0);
149 stats_event_release(event);
150 }
151
TEST(StatsEventTest,TestByteArrays)152 TEST(StatsEventTest, TestByteArrays) {
153 uint32_t atomId = 100;
154 vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
155
156 int64_t startTime = android::elapsedRealtimeNano();
157 struct stats_event* event = stats_event_obtain();
158 stats_event_set_atom_id(event, atomId);
159 stats_event_write_byte_array(event, message.data(), message.size());
160 stats_event_build(event);
161 int64_t endTime = android::elapsedRealtimeNano();
162
163 size_t bufferSize;
164 uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
165 uint8_t* bufferEnd = buffer + bufferSize;
166
167 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
168
169 checkTypeHeader(&buffer, BYTE_ARRAY_TYPE);
170 checkByteArray(&buffer, message);
171
172 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
173 EXPECT_EQ(stats_event_get_errors(event), 0);
174 stats_event_release(event);
175 }
176
TEST(StatsEventTest,TestAttributionChains)177 TEST(StatsEventTest, TestAttributionChains) {
178 uint32_t atomId = 100;
179
180 uint8_t numNodes = 50;
181 uint32_t uids[numNodes];
182 vector<string> tags(numNodes); // storage that cTag elements point to
183 const char* cTags[numNodes];
184 for (int i = 0; i < (int)numNodes; i++) {
185 uids[i] = i;
186 tags.push_back("test" + std::to_string(i));
187 cTags[i] = tags[i].c_str();
188 }
189
190 int64_t startTime = android::elapsedRealtimeNano();
191 struct stats_event* event = stats_event_obtain();
192 stats_event_set_atom_id(event, atomId);
193 stats_event_write_attribution_chain(event, uids, cTags, numNodes);
194 stats_event_build(event);
195 int64_t endTime = android::elapsedRealtimeNano();
196
197 size_t bufferSize;
198 uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
199 uint8_t* bufferEnd = buffer + bufferSize;
200
201 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
202
203 checkTypeHeader(&buffer, ATTRIBUTION_CHAIN_TYPE);
204 checkScalar(&buffer, numNodes);
205 for (int i = 0; i < numNodes; i++) {
206 checkScalar(&buffer, uids[i]);
207 checkString(&buffer, tags[i]);
208 }
209
210 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
211 EXPECT_EQ(stats_event_get_errors(event), 0);
212 stats_event_release(event);
213 }
214
TEST(StatsEventTest,TestKeyValuePairs)215 TEST(StatsEventTest, TestKeyValuePairs) {
216 uint32_t atomId = 100;
217
218 uint8_t numPairs = 4;
219 struct key_value_pair pairs[numPairs];
220 pairs[0] = {.key = 0, .valueType = INT32_TYPE, .int32Value = -1};
221 pairs[1] = {.key = 1, .valueType = INT64_TYPE, .int64Value = 0x123456789};
222 pairs[2] = {.key = 2, .valueType = FLOAT_TYPE, .floatValue = 5.5};
223 string str = "test_key_value_pair_string";
224 pairs[3] = {.key = 3, .valueType = STRING_TYPE, .stringValue = str.c_str()};
225
226 int64_t startTime = android::elapsedRealtimeNano();
227 struct stats_event* event = stats_event_obtain();
228 stats_event_set_atom_id(event, atomId);
229 stats_event_write_key_value_pairs(event, pairs, numPairs);
230 stats_event_build(event);
231 int64_t endTime = android::elapsedRealtimeNano();
232
233 size_t bufferSize;
234 uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
235 uint8_t* bufferEnd = buffer + bufferSize;
236
237 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
238
239 checkTypeHeader(&buffer, KEY_VALUE_PAIRS_TYPE);
240 checkScalar(&buffer, numPairs);
241
242 // first pair
243 checkScalar(&buffer, pairs[0].key);
244 checkTypeHeader(&buffer, pairs[0].valueType);
245 checkScalar(&buffer, pairs[0].int32Value);
246
247 // second pair
248 checkScalar(&buffer, pairs[1].key);
249 checkTypeHeader(&buffer, pairs[1].valueType);
250 checkScalar(&buffer, pairs[1].int64Value);
251
252 // third pair
253 checkScalar(&buffer, pairs[2].key);
254 checkTypeHeader(&buffer, pairs[2].valueType);
255 checkScalar(&buffer, pairs[2].floatValue);
256
257 // fourth pair
258 checkScalar(&buffer, pairs[3].key);
259 checkTypeHeader(&buffer, pairs[3].valueType);
260 checkString(&buffer, str);
261
262 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
263 EXPECT_EQ(stats_event_get_errors(event), 0);
264 stats_event_release(event);
265 }
266
TEST(StatsEventTest,TestAnnotations)267 TEST(StatsEventTest, TestAnnotations) {
268 uint32_t atomId = 100;
269
270 // first element information
271 bool boolValue = false;
272 uint8_t boolAnnotation1Id = 1;
273 uint8_t boolAnnotation2Id = 2;
274 bool boolAnnotation1Value = true;
275 int32_t boolAnnotation2Value = 3;
276
277 // second element information
278 float floatValue = -5.0;
279 uint8_t floatAnnotation1Id = 3;
280 uint8_t floatAnnotation2Id = 4;
281 int32_t floatAnnotation1Value = 8;
282 bool floatAnnotation2Value = false;
283
284 int64_t startTime = android::elapsedRealtimeNano();
285 struct stats_event* event = stats_event_obtain();
286 stats_event_set_atom_id(event, 100);
287 stats_event_write_bool(event, boolValue);
288 stats_event_add_bool_annotation(event, boolAnnotation1Id, boolAnnotation1Value);
289 stats_event_add_int32_annotation(event, boolAnnotation2Id, boolAnnotation2Value);
290 stats_event_write_float(event, floatValue);
291 stats_event_add_int32_annotation(event, floatAnnotation1Id, floatAnnotation1Value);
292 stats_event_add_bool_annotation(event, floatAnnotation2Id, floatAnnotation2Value);
293 stats_event_build(event);
294 int64_t endTime = android::elapsedRealtimeNano();
295
296 size_t bufferSize;
297 uint8_t* buffer = stats_event_get_buffer(event, &bufferSize);
298 uint8_t* bufferEnd = buffer + bufferSize;
299
300 checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
301
302 // check first element
303 checkTypeHeader(&buffer, BOOL_TYPE, /*numAnnotations=*/2);
304 checkScalar(&buffer, boolValue);
305 checkAnnotation(&buffer, boolAnnotation1Id, BOOL_TYPE, boolAnnotation1Value);
306 checkAnnotation(&buffer, boolAnnotation2Id, INT32_TYPE, boolAnnotation2Value);
307
308 // check second element
309 checkTypeHeader(&buffer, FLOAT_TYPE, /*numAnnotations=*/2);
310 checkScalar(&buffer, floatValue);
311 checkAnnotation(&buffer, floatAnnotation1Id, INT32_TYPE, floatAnnotation1Value);
312 checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
313
314 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
315 EXPECT_EQ(stats_event_get_errors(event), 0);
316 stats_event_release(event);
317 }
318
TEST(StatsEventTest,TestNoAtomIdError)319 TEST(StatsEventTest, TestNoAtomIdError) {
320 struct stats_event* event = stats_event_obtain();
321 // Don't set the atom id in order to trigger the error.
322 stats_event_build(event);
323
324 uint32_t errors = stats_event_get_errors(event);
325 EXPECT_NE(errors | ERROR_NO_ATOM_ID, 0);
326
327 stats_event_release(event);
328 }
329
TEST(StatsEventTest,TestOverflowError)330 TEST(StatsEventTest, TestOverflowError) {
331 struct stats_event* event = stats_event_obtain();
332 stats_event_set_atom_id(event, 100);
333 // Add 1000 int32s to the event. Each int32 takes 5 bytes so this will
334 // overflow the 4068 byte buffer.
335 for (int i = 0; i < 1000; i++) {
336 stats_event_write_int32(event, 0);
337 }
338 stats_event_build(event);
339
340 uint32_t errors = stats_event_get_errors(event);
341 EXPECT_NE(errors | ERROR_OVERFLOW, 0);
342
343 stats_event_release(event);
344 }
345