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 // Keep in sync with stats_event.c. Consider moving to separate header file to avoid duplication.
22 /* ERRORS */
23 #define ERROR_NO_TIMESTAMP 0x1
24 #define ERROR_NO_ATOM_ID 0x2
25 #define ERROR_OVERFLOW 0x4
26 #define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
27 #define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
28 #define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
29 #define ERROR_INVALID_ANNOTATION_ID 0x40
30 #define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
31 #define ERROR_TOO_MANY_ANNOTATIONS 0x100
32 #define ERROR_TOO_MANY_FIELDS 0x200
33 #define ERROR_INVALID_VALUE_TYPE 0x400
34 #define ERROR_STRING_NOT_NULL_TERMINATED 0x800
35 #define ERROR_ATOM_ID_INVALID_POSITION 0x2000
36
37 /* TYPE IDS */
38 #define INT32_TYPE 0x00
39 #define INT64_TYPE 0x01
40 #define STRING_TYPE 0x02
41 #define LIST_TYPE 0x03
42 #define FLOAT_TYPE 0x04
43 #define BOOL_TYPE 0x05
44 #define BYTE_ARRAY_TYPE 0x06
45 #define OBJECT_TYPE 0x07
46 #define KEY_VALUE_PAIRS_TYPE 0x08
47 #define ATTRIBUTION_CHAIN_TYPE 0x09
48 #define ERROR_TYPE 0x0F
49
50 using std::string;
51 using std::vector;
52
53 // Side-effect: this function moves the start of the buffer past the read value
54 template <class T>
readNext(uint8_t ** buffer)55 T readNext(uint8_t** buffer) {
56 T value;
57 if ((reinterpret_cast<uintptr_t>(*buffer) % alignof(T)) == 0) {
58 value = *(T*)(*buffer);
59 } else {
60 memcpy(&value, *buffer, sizeof(T));
61 }
62 *buffer += sizeof(T);
63 return value;
64 }
65
checkTypeHeader(uint8_t ** buffer,uint8_t typeId,uint8_t numAnnotations=0)66 void checkTypeHeader(uint8_t** buffer, uint8_t typeId, uint8_t numAnnotations = 0) {
67 uint8_t typeHeader = (numAnnotations << 4) | typeId;
68 EXPECT_EQ(readNext<uint8_t>(buffer), typeHeader);
69 }
70
71 template <class T>
checkScalar(uint8_t ** buffer,T expectedValue)72 void checkScalar(uint8_t** buffer, T expectedValue) {
73 EXPECT_EQ(readNext<T>(buffer), expectedValue);
74 }
75
checkString(uint8_t ** buffer,const string & expectedString)76 void checkString(uint8_t** buffer, const string& expectedString) {
77 uint32_t size = readNext<uint32_t>(buffer);
78 string parsedString((char*)(*buffer), size);
79 EXPECT_EQ(parsedString, expectedString);
80 *buffer += size; // move buffer past string we just read
81 }
82
checkByteArray(uint8_t ** buffer,const vector<uint8_t> & expectedByteArray)83 void checkByteArray(uint8_t** buffer, const vector<uint8_t>& expectedByteArray) {
84 uint32_t size = readNext<uint32_t>(buffer);
85 vector<uint8_t> parsedByteArray(*buffer, *buffer + size);
86 EXPECT_EQ(parsedByteArray, expectedByteArray);
87 *buffer += size; // move buffer past byte array we just read
88 }
89
90 template <class T>
checkAnnotation(uint8_t ** buffer,uint8_t annotationId,uint8_t typeId,T annotationValue)91 void checkAnnotation(uint8_t** buffer, uint8_t annotationId, uint8_t typeId, T annotationValue) {
92 EXPECT_EQ(readNext<uint8_t>(buffer), annotationId);
93 EXPECT_EQ(readNext<uint8_t>(buffer), typeId);
94 checkScalar<T>(buffer, annotationValue);
95 }
96
checkMetadata(uint8_t ** buffer,uint8_t numElements,int64_t startTime,int64_t endTime,uint32_t atomId,uint8_t numAtomLevelAnnotations=0)97 void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
98 uint32_t atomId, uint8_t numAtomLevelAnnotations = 0) {
99 // All events start with OBJECT_TYPE id.
100 checkTypeHeader(buffer, OBJECT_TYPE);
101
102 // We increment by 2 because the number of elements listed in the
103 // serialization accounts for the timestamp and atom id as well.
104 checkScalar(buffer, static_cast<uint8_t>(numElements + 2));
105
106 // Check timestamp
107 checkTypeHeader(buffer, INT64_TYPE);
108 int64_t timestamp = readNext<int64_t>(buffer);
109 EXPECT_GE(timestamp, startTime);
110 EXPECT_LE(timestamp, endTime);
111
112 // Check atom id
113 checkTypeHeader(buffer, INT32_TYPE, numAtomLevelAnnotations);
114 checkScalar(buffer, atomId);
115 }
116
TEST(StatsEventTest,TestScalars)117 TEST(StatsEventTest, TestScalars) {
118 uint32_t atomId = 100;
119 int32_t int32Value = -5;
120 int64_t int64Value = -2 * android::elapsedRealtimeNano();
121 float floatValue = 2.0;
122 bool boolValue = false;
123
124 int64_t startTime = android::elapsedRealtimeNano();
125 AStatsEvent* event = AStatsEvent_obtain();
126 AStatsEvent_setAtomId(event, atomId);
127 AStatsEvent_writeInt32(event, int32Value);
128 AStatsEvent_writeInt64(event, int64Value);
129 AStatsEvent_writeFloat(event, floatValue);
130 AStatsEvent_writeBool(event, boolValue);
131 AStatsEvent_build(event);
132 int64_t endTime = android::elapsedRealtimeNano();
133
134 size_t bufferSize;
135 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
136 uint8_t* bufferEnd = buffer + bufferSize;
137
138 checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
139
140 // check int32 element
141 checkTypeHeader(&buffer, INT32_TYPE);
142 checkScalar(&buffer, int32Value);
143
144 // check int64 element
145 checkTypeHeader(&buffer, INT64_TYPE);
146 checkScalar(&buffer, int64Value);
147
148 // check float element
149 checkTypeHeader(&buffer, FLOAT_TYPE);
150 checkScalar(&buffer, floatValue);
151
152 // check bool element
153 checkTypeHeader(&buffer, BOOL_TYPE);
154 checkScalar(&buffer, boolValue);
155
156 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
157 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
158 AStatsEvent_release(event);
159 }
160
TEST(StatsEventTest,TestStrings)161 TEST(StatsEventTest, TestStrings) {
162 uint32_t atomId = 100;
163 string str = "test_string";
164
165 int64_t startTime = android::elapsedRealtimeNano();
166 AStatsEvent* event = AStatsEvent_obtain();
167 AStatsEvent_setAtomId(event, atomId);
168 AStatsEvent_writeString(event, str.c_str());
169 AStatsEvent_build(event);
170 int64_t endTime = android::elapsedRealtimeNano();
171
172 size_t bufferSize;
173 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
174 uint8_t* bufferEnd = buffer + bufferSize;
175
176 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
177
178 checkTypeHeader(&buffer, STRING_TYPE);
179 checkString(&buffer, str);
180
181 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
182 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
183 AStatsEvent_release(event);
184 }
185
TEST(StatsEventTest,TestByteArrays)186 TEST(StatsEventTest, TestByteArrays) {
187 uint32_t atomId = 100;
188 vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
189
190 int64_t startTime = android::elapsedRealtimeNano();
191 AStatsEvent* event = AStatsEvent_obtain();
192 AStatsEvent_setAtomId(event, atomId);
193 AStatsEvent_writeByteArray(event, message.data(), message.size());
194 AStatsEvent_build(event);
195 int64_t endTime = android::elapsedRealtimeNano();
196
197 size_t bufferSize;
198 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
199 uint8_t* bufferEnd = buffer + bufferSize;
200
201 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
202
203 checkTypeHeader(&buffer, BYTE_ARRAY_TYPE);
204 checkByteArray(&buffer, message);
205
206 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
207 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
208 AStatsEvent_release(event);
209 }
210
TEST(StatsEventTest,TestAttributionChains)211 TEST(StatsEventTest, TestAttributionChains) {
212 uint32_t atomId = 100;
213
214 uint8_t numNodes = 50;
215 uint32_t uids[numNodes];
216 vector<string> tags(numNodes); // storage that cTag elements point to
217 const char* cTags[numNodes];
218 for (int i = 0; i < (int)numNodes; i++) {
219 uids[i] = i;
220 tags.push_back("test" + std::to_string(i));
221 cTags[i] = tags[i].c_str();
222 }
223
224 int64_t startTime = android::elapsedRealtimeNano();
225 AStatsEvent* event = AStatsEvent_obtain();
226 AStatsEvent_setAtomId(event, atomId);
227 AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
228 AStatsEvent_build(event);
229 int64_t endTime = android::elapsedRealtimeNano();
230
231 size_t bufferSize;
232 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
233 uint8_t* bufferEnd = buffer + bufferSize;
234
235 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
236
237 checkTypeHeader(&buffer, ATTRIBUTION_CHAIN_TYPE);
238 checkScalar(&buffer, numNodes);
239 for (int i = 0; i < numNodes; i++) {
240 checkScalar(&buffer, uids[i]);
241 checkString(&buffer, tags[i]);
242 }
243
244 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
245 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
246 AStatsEvent_release(event);
247 }
248
TEST(StatsEventTest,TestFieldAnnotations)249 TEST(StatsEventTest, TestFieldAnnotations) {
250 uint32_t atomId = 100;
251
252 // first element information
253 bool boolValue = false;
254 uint8_t boolAnnotation1Id = 1;
255 uint8_t boolAnnotation2Id = 2;
256 bool boolAnnotation1Value = true;
257 int32_t boolAnnotation2Value = 3;
258
259 // second element information
260 float floatValue = -5.0;
261 uint8_t floatAnnotation1Id = 3;
262 uint8_t floatAnnotation2Id = 4;
263 int32_t floatAnnotation1Value = 8;
264 bool floatAnnotation2Value = false;
265
266 int64_t startTime = android::elapsedRealtimeNano();
267 AStatsEvent* event = AStatsEvent_obtain();
268 AStatsEvent_setAtomId(event, atomId);
269 AStatsEvent_writeBool(event, boolValue);
270 AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
271 AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
272 AStatsEvent_writeFloat(event, floatValue);
273 AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
274 AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
275 AStatsEvent_build(event);
276 int64_t endTime = android::elapsedRealtimeNano();
277
278 size_t bufferSize;
279 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
280 uint8_t* bufferEnd = buffer + bufferSize;
281
282 checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
283
284 // check first element
285 checkTypeHeader(&buffer, BOOL_TYPE, /*numAnnotations=*/2);
286 checkScalar(&buffer, boolValue);
287 checkAnnotation(&buffer, boolAnnotation1Id, BOOL_TYPE, boolAnnotation1Value);
288 checkAnnotation(&buffer, boolAnnotation2Id, INT32_TYPE, boolAnnotation2Value);
289
290 // check second element
291 checkTypeHeader(&buffer, FLOAT_TYPE, /*numAnnotations=*/2);
292 checkScalar(&buffer, floatValue);
293 checkAnnotation(&buffer, floatAnnotation1Id, INT32_TYPE, floatAnnotation1Value);
294 checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
295
296 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
297 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
298 AStatsEvent_release(event);
299 }
300
TEST(StatsEventTest,TestAtomLevelAnnotations)301 TEST(StatsEventTest, TestAtomLevelAnnotations) {
302 uint32_t atomId = 100;
303 // atom-level annotation information
304 uint8_t boolAnnotationId = 1;
305 uint8_t int32AnnotationId = 2;
306 bool boolAnnotationValue = false;
307 int32_t int32AnnotationValue = 5;
308
309 float fieldValue = -3.5;
310
311 int64_t startTime = android::elapsedRealtimeNano();
312 AStatsEvent* event = AStatsEvent_obtain();
313 AStatsEvent_setAtomId(event, atomId);
314 AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
315 AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
316 AStatsEvent_writeFloat(event, fieldValue);
317 AStatsEvent_build(event);
318 int64_t endTime = android::elapsedRealtimeNano();
319
320 size_t bufferSize;
321 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
322 uint8_t* bufferEnd = buffer + bufferSize;
323
324 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId,
325 /*numAtomLevelAnnotations=*/2);
326
327 // check atom-level annotations
328 checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
329 checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
330
331 // check first element
332 checkTypeHeader(&buffer, FLOAT_TYPE);
333 checkScalar(&buffer, fieldValue);
334
335 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
336 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
337 AStatsEvent_release(event);
338 }
339
TEST(StatsEventTest,TestNoAtomIdError)340 TEST(StatsEventTest, TestNoAtomIdError) {
341 AStatsEvent* event = AStatsEvent_obtain();
342 // Don't set the atom id in order to trigger the error.
343 AStatsEvent_build(event);
344
345 uint32_t errors = AStatsEvent_getErrors(event);
346 EXPECT_EQ(errors & ERROR_NO_ATOM_ID, ERROR_NO_ATOM_ID);
347
348 AStatsEvent_release(event);
349 }
350
TEST(StatsEventTest,TestPushOverflowError)351 TEST(StatsEventTest, TestPushOverflowError) {
352 const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
353 const int writeCount = 120; // Number of times to write str in the event.
354
355 AStatsEvent* event = AStatsEvent_obtain();
356 AStatsEvent_setAtomId(event, 100);
357
358 // Add str to the event 120 times. Each str takes >35 bytes so this will
359 // overflow the 4068 byte buffer.
360 // We want to keep writeCount less than 127 to avoid hitting
361 // ERROR_TOO_MANY_FIELDS.
362 for (int i = 0; i < writeCount; i++) {
363 AStatsEvent_writeString(event, str);
364 }
365 AStatsEvent_write(event);
366
367 uint32_t errors = AStatsEvent_getErrors(event);
368 EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
369
370 AStatsEvent_release(event);
371 }
372
TEST(StatsEventTest,TestPullOverflowError)373 TEST(StatsEventTest, TestPullOverflowError) {
374 const uint32_t atomId = 10100;
375 const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);
376 const int writeCount = 120; // Number of times to write bytes in the event.
377
378 AStatsEvent* event = AStatsEvent_obtain();
379 AStatsEvent_setAtomId(event, atomId);
380
381 // Add bytes to the event 120 times. Size of bytes is 430 so this will
382 // overflow the 50 KB pulled event buffer.
383 // We want to keep writeCount less than 127 to avoid hitting
384 // ERROR_TOO_MANY_FIELDS.
385 for (int i = 0; i < writeCount; i++) {
386 AStatsEvent_writeByteArray(event, bytes.data(), bytes.size());
387 }
388 AStatsEvent_build(event);
389
390 uint32_t errors = AStatsEvent_getErrors(event);
391 EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
392
393 AStatsEvent_release(event);
394 }
395
TEST(StatsEventTest,TestLargePull)396 TEST(StatsEventTest, TestLargePull) {
397 const uint32_t atomId = 100;
398 const string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
399 const int writeCount = 120; // Number of times to write str in the event.
400 const int64_t startTime = android::elapsedRealtimeNano();
401
402 AStatsEvent* event = AStatsEvent_obtain();
403 AStatsEvent_setAtomId(event, atomId);
404
405 // Add str to the event 120 times.
406 // We want to keep writeCount less than 127 to avoid hitting
407 // ERROR_TOO_MANY_FIELDS.
408 for (int i = 0; i < writeCount; i++) {
409 AStatsEvent_writeString(event, str.c_str());
410 }
411 AStatsEvent_build(event);
412 int64_t endTime = android::elapsedRealtimeNano();
413
414 size_t bufferSize;
415 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
416 uint8_t* bufferEnd = buffer + bufferSize;
417
418 checkMetadata(&buffer, writeCount, startTime, endTime, atomId);
419
420 // Check all instances of str have been written.
421 for (int i = 0; i < writeCount; i++) {
422 checkTypeHeader(&buffer, STRING_TYPE);
423 checkString(&buffer, str);
424 }
425
426 EXPECT_EQ(buffer, bufferEnd); // Ensure that we have read the entire buffer.
427 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
428 AStatsEvent_release(event);
429 }
430
TEST(StatsEventTest,TestAtomIdInvalidPositionError)431 TEST(StatsEventTest, TestAtomIdInvalidPositionError) {
432 AStatsEvent* event = AStatsEvent_obtain();
433 AStatsEvent_writeInt32(event, 0);
434 AStatsEvent_setAtomId(event, 100);
435 AStatsEvent_writeBool(event, true);
436 AStatsEvent_build(event);
437
438 uint32_t errors = AStatsEvent_getErrors(event);
439 EXPECT_EQ(errors & ERROR_ATOM_ID_INVALID_POSITION, ERROR_ATOM_ID_INVALID_POSITION);
440
441 AStatsEvent_release(event);
442 }
443
TEST(StatsEventTest,TestOverwriteTimestamp)444 TEST(StatsEventTest, TestOverwriteTimestamp) {
445 uint32_t atomId = 100;
446 int64_t expectedTimestamp = 0x123456789;
447 AStatsEvent* event = AStatsEvent_obtain();
448 AStatsEvent_setAtomId(event, atomId);
449 AStatsEvent_overwriteTimestamp(event, expectedTimestamp);
450 AStatsEvent_build(event);
451
452 uint8_t* buffer = AStatsEvent_getBuffer(event, NULL);
453
454 // Make sure that the timestamp is being overwritten.
455 checkMetadata(&buffer, /*numElements=*/0, /*startTime=*/expectedTimestamp,
456 /*endTime=*/expectedTimestamp, atomId);
457
458 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
459 AStatsEvent_release(event);
460 }
461