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
19 #include <gtest/gtest.h>
20 #include <utils/SystemClock.h>
21
22 #include "sdk_guard_util.h"
23
24 // Keep in sync with stats_event.c. Consider moving to separate header file to avoid duplication.
25 /* ERRORS */
26 #define ERROR_NO_TIMESTAMP 0x1
27 #define ERROR_NO_ATOM_ID 0x2
28 #define ERROR_OVERFLOW 0x4
29 #define ERROR_ATTRIBUTION_CHAIN_TOO_LONG 0x8
30 #define ERROR_TOO_MANY_KEY_VALUE_PAIRS 0x10
31 #define ERROR_ANNOTATION_DOES_NOT_FOLLOW_FIELD 0x20
32 #define ERROR_INVALID_ANNOTATION_ID 0x40
33 #define ERROR_ANNOTATION_ID_TOO_LARGE 0x80
34 #define ERROR_TOO_MANY_ANNOTATIONS 0x100
35 #define ERROR_TOO_MANY_FIELDS 0x200
36 #define ERROR_INVALID_VALUE_TYPE 0x400
37 #define ERROR_STRING_NOT_NULL_TERMINATED 0x800
38 #define ERROR_ATOM_ID_INVALID_POSITION 0x2000
39 #define ERROR_LIST_TOO_LONG 0x4000
40
41 /* TYPE IDS */
42 #define INT32_TYPE 0x00
43 #define INT64_TYPE 0x01
44 #define STRING_TYPE 0x02
45 #define LIST_TYPE 0x03
46 #define FLOAT_TYPE 0x04
47 #define BOOL_TYPE 0x05
48 #define BYTE_ARRAY_TYPE 0x06
49 #define OBJECT_TYPE 0x07
50 #define KEY_VALUE_PAIRS_TYPE 0x08
51 #define ATTRIBUTION_CHAIN_TYPE 0x09
52 #define ERROR_TYPE 0x0F
53
54 using std::string;
55 using std::vector;
56
57 // Side-effect: this function moves the start of the buffer past the read value
58 template <class T>
readNext(uint8_t ** buffer)59 T readNext(uint8_t** buffer) {
60 T value;
61 if ((reinterpret_cast<uintptr_t>(*buffer) % alignof(T)) == 0) {
62 value = *(T*)(*buffer);
63 } else {
64 memcpy(&value, *buffer, sizeof(T));
65 }
66 *buffer += sizeof(T);
67 return value;
68 }
69
checkTypeHeader(uint8_t ** buffer,uint8_t typeId,uint8_t numAnnotations=0)70 void checkTypeHeader(uint8_t** buffer, uint8_t typeId, uint8_t numAnnotations = 0) {
71 uint8_t typeHeader = (numAnnotations << 4) | typeId;
72 EXPECT_EQ(readNext<uint8_t>(buffer), typeHeader);
73 }
74
75 template <class T>
checkScalar(uint8_t ** buffer,T expectedValue)76 void checkScalar(uint8_t** buffer, T expectedValue) {
77 EXPECT_EQ(readNext<T>(buffer), expectedValue);
78 }
79
checkString(uint8_t ** buffer,const string & expectedString)80 void checkString(uint8_t** buffer, const string& expectedString) {
81 uint32_t size = readNext<uint32_t>(buffer);
82 string parsedString((char*)(*buffer), size);
83 EXPECT_EQ(parsedString, expectedString);
84 *buffer += size; // move buffer past string we just read
85 }
86
checkByteArray(uint8_t ** buffer,const vector<uint8_t> & expectedByteArray)87 void checkByteArray(uint8_t** buffer, const vector<uint8_t>& expectedByteArray) {
88 uint32_t size = readNext<uint32_t>(buffer);
89 vector<uint8_t> parsedByteArray(*buffer, *buffer + size);
90 EXPECT_EQ(parsedByteArray, expectedByteArray);
91 *buffer += size; // move buffer past byte array we just read
92 }
93
checkArrayMetadata(uint8_t ** buffer,uint8_t numElements,uint8_t elementTypeId,uint8_t numAnnotations=0)94 void checkArrayMetadata(uint8_t** buffer, uint8_t numElements, uint8_t elementTypeId,
95 uint8_t numAnnotations = 0) {
96 checkTypeHeader(buffer, LIST_TYPE, numAnnotations);
97 EXPECT_EQ(readNext<uint8_t>(buffer), numElements);
98 checkTypeHeader(buffer, elementTypeId);
99 }
100
101 template <class T>
checkScalarArray(uint8_t ** buffer,uint8_t numElements,uint8_t elementTypeId,const T * expectedArrayValues,uint8_t numAnnotations=0)102 void checkScalarArray(uint8_t** buffer, uint8_t numElements, uint8_t elementTypeId,
103 const T* expectedArrayValues, uint8_t numAnnotations = 0) {
104 checkArrayMetadata(buffer, numElements, elementTypeId, numAnnotations);
105
106 for (int i = 0; i < numElements; i++) {
107 checkScalar(buffer, expectedArrayValues[i]);
108 }
109 }
110
111 template <class T>
checkAnnotation(uint8_t ** buffer,uint8_t annotationId,uint8_t typeId,T annotationValue)112 void checkAnnotation(uint8_t** buffer, uint8_t annotationId, uint8_t typeId, T annotationValue) {
113 EXPECT_EQ(readNext<uint8_t>(buffer), annotationId);
114 EXPECT_EQ(readNext<uint8_t>(buffer), typeId);
115 checkScalar<T>(buffer, annotationValue);
116 }
117
checkMetadata(uint8_t ** buffer,uint8_t numElements,int64_t startTime,int64_t endTime,uint32_t atomId,uint8_t numAtomLevelAnnotations=0)118 void checkMetadata(uint8_t** buffer, uint8_t numElements, int64_t startTime, int64_t endTime,
119 uint32_t atomId, uint8_t numAtomLevelAnnotations = 0) {
120 // All events start with OBJECT_TYPE id.
121 checkTypeHeader(buffer, OBJECT_TYPE);
122
123 // We increment by 2 because the number of elements listed in the
124 // serialization accounts for the timestamp and atom id as well.
125 checkScalar(buffer, static_cast<uint8_t>(numElements + 2));
126
127 // Check timestamp
128 checkTypeHeader(buffer, INT64_TYPE);
129 int64_t timestamp = readNext<int64_t>(buffer);
130 EXPECT_GE(timestamp, startTime);
131 EXPECT_LE(timestamp, endTime);
132
133 // Check atom id
134 checkTypeHeader(buffer, INT32_TYPE, numAtomLevelAnnotations);
135 checkScalar(buffer, atomId);
136 }
137
TEST(StatsEventTest,TestScalars)138 TEST(StatsEventTest, TestScalars) {
139 uint32_t atomId = 100;
140 int32_t int32Value = -5;
141 int64_t int64Value = -2 * android::elapsedRealtimeNano();
142 float floatValue = 2.0;
143 bool boolValue = false;
144
145 int64_t startTime = android::elapsedRealtimeNano();
146 AStatsEvent* event = AStatsEvent_obtain();
147 AStatsEvent_setAtomId(event, atomId);
148 AStatsEvent_writeInt32(event, int32Value);
149 AStatsEvent_writeInt64(event, int64Value);
150 AStatsEvent_writeFloat(event, floatValue);
151 AStatsEvent_writeBool(event, boolValue);
152 AStatsEvent_build(event);
153 int64_t endTime = android::elapsedRealtimeNano();
154
155 size_t bufferSize;
156 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
157 uint8_t* bufferEnd = buffer + bufferSize;
158
159 checkMetadata(&buffer, /*numElements=*/4, startTime, endTime, atomId);
160
161 // check int32 element
162 checkTypeHeader(&buffer, INT32_TYPE);
163 checkScalar(&buffer, int32Value);
164
165 // check int64 element
166 checkTypeHeader(&buffer, INT64_TYPE);
167 checkScalar(&buffer, int64Value);
168
169 // check float element
170 checkTypeHeader(&buffer, FLOAT_TYPE);
171 checkScalar(&buffer, floatValue);
172
173 // check bool element
174 checkTypeHeader(&buffer, BOOL_TYPE);
175 checkScalar(&buffer, boolValue);
176
177 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
178 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
179 AStatsEvent_release(event);
180 }
181
TEST(StatsEventTest,TestStrings)182 TEST(StatsEventTest, TestStrings) {
183 uint32_t atomId = 100;
184 string str = "test_string";
185
186 int64_t startTime = android::elapsedRealtimeNano();
187 AStatsEvent* event = AStatsEvent_obtain();
188 AStatsEvent_setAtomId(event, atomId);
189 AStatsEvent_writeString(event, str.c_str());
190 AStatsEvent_build(event);
191 int64_t endTime = android::elapsedRealtimeNano();
192
193 size_t bufferSize;
194 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
195 uint8_t* bufferEnd = buffer + bufferSize;
196
197 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
198
199 checkTypeHeader(&buffer, STRING_TYPE);
200 checkString(&buffer, str);
201
202 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
203 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
204 AStatsEvent_release(event);
205 }
206
TEST(StatsEventTest,TestNullString)207 TEST(StatsEventTest, TestNullString) {
208 uint32_t atomId = 100;
209 char* str = nullptr;
210
211 int64_t startTime = android::elapsedRealtimeNano();
212 AStatsEvent* event = AStatsEvent_obtain();
213 AStatsEvent_setAtomId(event, atomId);
214 AStatsEvent_writeString(event, str);
215 AStatsEvent_build(event);
216 int64_t endTime = android::elapsedRealtimeNano();
217
218 size_t bufferSize;
219 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
220 uint8_t* bufferEnd = buffer + bufferSize;
221
222 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
223
224 checkTypeHeader(&buffer, STRING_TYPE);
225 checkString(&buffer, "");
226
227 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
228 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
229 AStatsEvent_release(event);
230 }
231
TEST(StatsEventTest,TestByteArrays)232 TEST(StatsEventTest, TestByteArrays) {
233 uint32_t atomId = 100;
234 vector<uint8_t> message = {'b', 'y', 't', '\0', 'e', 's'};
235
236 int64_t startTime = android::elapsedRealtimeNano();
237 AStatsEvent* event = AStatsEvent_obtain();
238 AStatsEvent_setAtomId(event, atomId);
239 AStatsEvent_writeByteArray(event, message.data(), message.size());
240 AStatsEvent_build(event);
241 int64_t endTime = android::elapsedRealtimeNano();
242
243 size_t bufferSize;
244 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
245 uint8_t* bufferEnd = buffer + bufferSize;
246
247 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
248
249 checkTypeHeader(&buffer, BYTE_ARRAY_TYPE);
250 checkByteArray(&buffer, message);
251
252 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
253 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
254 AStatsEvent_release(event);
255 }
256
TEST(StatsEventTest,TestNullByteArrays)257 TEST(StatsEventTest, TestNullByteArrays) {
258 uint32_t atomId = 100;
259 uint8_t* buf = nullptr;
260 vector<uint8_t> message;
261
262 int64_t startTime = android::elapsedRealtimeNano();
263 AStatsEvent* event = AStatsEvent_obtain();
264 AStatsEvent_setAtomId(event, atomId);
265 AStatsEvent_writeByteArray(event, buf, 2);
266 AStatsEvent_build(event);
267 int64_t endTime = android::elapsedRealtimeNano();
268
269 size_t bufferSize;
270 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
271 uint8_t* bufferEnd = buffer + bufferSize;
272
273 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
274
275 checkTypeHeader(&buffer, BYTE_ARRAY_TYPE);
276 checkByteArray(&buffer, message);
277
278 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
279 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
280 AStatsEvent_release(event);
281 }
282
TEST_GUARDED(StatsEventTest,TestAllArrays,__ANDROID_API_T__)283 TEST_GUARDED(StatsEventTest, TestAllArrays, __ANDROID_API_T__) {
284 uint32_t atomId = 100;
285
286 uint8_t numElements = 3;
287 int32_t int32Array[3] = {3, 6, 9};
288 int64_t int64Array[3] = {1000L, 1001L, 1002L};
289 float floatArray[3] = {0.1f, 0.3f, 0.09f};
290 bool boolArray[3] = {0, 1, 1};
291
292 vector<string> stringArray = {"str1", "str2", "str3"};
293 const char* cStringArray[3];
294 for (int i = 0; i < numElements; i++) {
295 cStringArray[i] = stringArray[i].c_str();
296 }
297
298 int64_t startTime = android::elapsedRealtimeNano();
299 AStatsEvent* event = AStatsEvent_obtain();
300 AStatsEvent_setAtomId(event, atomId);
301 AStatsEvent_writeInt32Array(event, int32Array, numElements);
302 AStatsEvent_writeInt64Array(event, int64Array, numElements);
303 AStatsEvent_writeFloatArray(event, floatArray, numElements);
304 AStatsEvent_writeBoolArray(event, boolArray, numElements);
305 AStatsEvent_writeStringArray(event, cStringArray, numElements);
306 AStatsEvent_build(event);
307 int64_t endTime = android::elapsedRealtimeNano();
308
309 size_t bufferSize;
310 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
311 uint8_t* bufferEnd = buffer + bufferSize;
312
313 checkMetadata(&buffer, /*numTopLevelElements=*/5, startTime, endTime, atomId);
314
315 // check int32Array element
316 checkScalarArray(&buffer, numElements, INT32_TYPE, int32Array);
317
318 // check int64Array element
319 checkScalarArray(&buffer, numElements, INT64_TYPE, int64Array);
320
321 // check floatArray element
322 checkScalarArray(&buffer, numElements, FLOAT_TYPE, floatArray);
323
324 // check boolArray element
325 checkScalarArray(&buffer, numElements, BOOL_TYPE, boolArray);
326
327 // check stringArray element
328 checkArrayMetadata(&buffer, numElements, STRING_TYPE);
329 for (int i = 0; i < numElements; i++) {
330 checkString(&buffer, stringArray[i]);
331 }
332
333 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
334 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
335 AStatsEvent_release(event);
336 }
337
TEST(StatsEventTest,TestAttributionChains)338 TEST(StatsEventTest, TestAttributionChains) {
339 uint32_t atomId = 100;
340
341 uint8_t numNodes = 50;
342 uint32_t uids[numNodes];
343 vector<string> tags(numNodes); // storage that cTag elements point to
344 const char* cTags[numNodes];
345 for (int i = 0; i < (int)numNodes; i++) {
346 uids[i] = i;
347 if (0 == i) {
348 tags.push_back("");
349 cTags[i] = nullptr;
350 } else {
351 tags.push_back("test" + std::to_string(i));
352 cTags[i] = tags[i].c_str();
353 }
354 }
355
356 int64_t startTime = android::elapsedRealtimeNano();
357 AStatsEvent* event = AStatsEvent_obtain();
358 AStatsEvent_setAtomId(event, atomId);
359 AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
360 AStatsEvent_build(event);
361 int64_t endTime = android::elapsedRealtimeNano();
362
363 size_t bufferSize;
364 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
365 uint8_t* bufferEnd = buffer + bufferSize;
366
367 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
368
369 checkTypeHeader(&buffer, ATTRIBUTION_CHAIN_TYPE);
370 checkScalar(&buffer, numNodes);
371 for (int i = 0; i < numNodes; i++) {
372 checkScalar(&buffer, uids[i]);
373 checkString(&buffer, tags[i]);
374 }
375
376 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
377 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
378 AStatsEvent_release(event);
379 }
380
TEST(StatsEventTest,TestFieldAnnotations)381 TEST(StatsEventTest, TestFieldAnnotations) {
382 uint32_t atomId = 100;
383
384 // first element information
385 bool boolValue = false;
386 uint8_t boolAnnotation1Id = 1;
387 uint8_t boolAnnotation2Id = 2;
388 bool boolAnnotation1Value = true;
389 int32_t boolAnnotation2Value = 3;
390
391 // second element information
392 float floatValue = -5.0;
393 uint8_t floatAnnotation1Id = 3;
394 uint8_t floatAnnotation2Id = 4;
395 int32_t floatAnnotation1Value = 8;
396 bool floatAnnotation2Value = false;
397
398 int64_t startTime = android::elapsedRealtimeNano();
399 AStatsEvent* event = AStatsEvent_obtain();
400 AStatsEvent_setAtomId(event, atomId);
401 AStatsEvent_writeBool(event, boolValue);
402 AStatsEvent_addBoolAnnotation(event, boolAnnotation1Id, boolAnnotation1Value);
403 AStatsEvent_addInt32Annotation(event, boolAnnotation2Id, boolAnnotation2Value);
404 AStatsEvent_writeFloat(event, floatValue);
405 AStatsEvent_addInt32Annotation(event, floatAnnotation1Id, floatAnnotation1Value);
406 AStatsEvent_addBoolAnnotation(event, floatAnnotation2Id, floatAnnotation2Value);
407 AStatsEvent_build(event);
408 int64_t endTime = android::elapsedRealtimeNano();
409
410 size_t bufferSize;
411 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
412 uint8_t* bufferEnd = buffer + bufferSize;
413
414 checkMetadata(&buffer, /*numElements=*/2, startTime, endTime, atomId);
415
416 // check first element
417 checkTypeHeader(&buffer, BOOL_TYPE, /*numAnnotations=*/2);
418 checkScalar(&buffer, boolValue);
419 checkAnnotation(&buffer, boolAnnotation1Id, BOOL_TYPE, boolAnnotation1Value);
420 checkAnnotation(&buffer, boolAnnotation2Id, INT32_TYPE, boolAnnotation2Value);
421
422 // check second element
423 checkTypeHeader(&buffer, FLOAT_TYPE, /*numAnnotations=*/2);
424 checkScalar(&buffer, floatValue);
425 checkAnnotation(&buffer, floatAnnotation1Id, INT32_TYPE, floatAnnotation1Value);
426 checkAnnotation(&buffer, floatAnnotation2Id, BOOL_TYPE, floatAnnotation2Value);
427
428 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
429 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
430 AStatsEvent_release(event);
431 }
432
TEST_GUARDED(StatsEventTest,TestArrayFieldAnnotations,__ANDROID_API_T__)433 TEST_GUARDED(StatsEventTest, TestArrayFieldAnnotations, __ANDROID_API_T__) {
434 uint32_t atomId = 100;
435
436 // array annotation info
437 uint8_t boolAnnotationId = 1;
438 uint8_t int32AnnotationId = 2;
439 bool boolAnnotationValue = true;
440 int32_t int32AnnotationValue = 4;
441
442 uint8_t numElements = 3;
443 int32_t int32Array[3] = {3, 6, 9};
444
445 int64_t startTime = android::elapsedRealtimeNano();
446 AStatsEvent* event = AStatsEvent_obtain();
447 AStatsEvent_setAtomId(event, atomId);
448 AStatsEvent_writeInt32Array(event, int32Array, numElements);
449 AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
450 AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
451 AStatsEvent_build(event);
452 int64_t endTime = android::elapsedRealtimeNano();
453
454 size_t bufferSize;
455 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
456 uint8_t* bufferEnd = buffer + bufferSize;
457
458 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId);
459
460 // check first element
461 checkScalarArray(&buffer, numElements, INT32_TYPE, int32Array, /*numAnnotations=*/2);
462 checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
463 checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
464
465 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
466 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
467 AStatsEvent_release(event);
468 }
469
TEST(StatsEventTest,TestAtomLevelAnnotations)470 TEST(StatsEventTest, TestAtomLevelAnnotations) {
471 uint32_t atomId = 100;
472 // atom-level annotation information
473 uint8_t boolAnnotationId = 1;
474 uint8_t int32AnnotationId = 2;
475 bool boolAnnotationValue = false;
476 int32_t int32AnnotationValue = 5;
477
478 float fieldValue = -3.5;
479
480 int64_t startTime = android::elapsedRealtimeNano();
481 AStatsEvent* event = AStatsEvent_obtain();
482 AStatsEvent_setAtomId(event, atomId);
483 AStatsEvent_addBoolAnnotation(event, boolAnnotationId, boolAnnotationValue);
484 AStatsEvent_addInt32Annotation(event, int32AnnotationId, int32AnnotationValue);
485 AStatsEvent_writeFloat(event, fieldValue);
486 AStatsEvent_build(event);
487 int64_t endTime = android::elapsedRealtimeNano();
488
489 size_t bufferSize;
490 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
491 uint8_t* bufferEnd = buffer + bufferSize;
492
493 checkMetadata(&buffer, /*numElements=*/1, startTime, endTime, atomId,
494 /*numAtomLevelAnnotations=*/2);
495
496 // check atom-level annotations
497 checkAnnotation(&buffer, boolAnnotationId, BOOL_TYPE, boolAnnotationValue);
498 checkAnnotation(&buffer, int32AnnotationId, INT32_TYPE, int32AnnotationValue);
499
500 // check first element
501 checkTypeHeader(&buffer, FLOAT_TYPE);
502 checkScalar(&buffer, fieldValue);
503
504 EXPECT_EQ(buffer, bufferEnd); // ensure that we have read the entire buffer
505 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
506 AStatsEvent_release(event);
507 }
508
TEST(StatsEventTest,TestNoAtomIdError)509 TEST(StatsEventTest, TestNoAtomIdError) {
510 AStatsEvent* event = AStatsEvent_obtain();
511 // Don't set the atom id in order to trigger the error.
512 AStatsEvent_build(event);
513
514 uint32_t errors = AStatsEvent_getErrors(event);
515 EXPECT_EQ(errors & ERROR_NO_ATOM_ID, ERROR_NO_ATOM_ID);
516
517 AStatsEvent_release(event);
518 }
519
TEST(StatsEventTest,TestPushOverflowError)520 TEST(StatsEventTest, TestPushOverflowError) {
521 const char* str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
522 const int writeCount = 120; // Number of times to write str in the event.
523
524 AStatsEvent* event = AStatsEvent_obtain();
525 AStatsEvent_setAtomId(event, 100);
526
527 // Add str to the event 120 times. Each str takes >35 bytes so this will
528 // overflow the 4068 byte buffer.
529 // We want to keep writeCount less than 127 to avoid hitting
530 // ERROR_TOO_MANY_FIELDS.
531 for (int i = 0; i < writeCount; i++) {
532 AStatsEvent_writeString(event, str);
533 }
534 AStatsEvent_write(event);
535
536 uint32_t errors = AStatsEvent_getErrors(event);
537 EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
538
539 AStatsEvent_release(event);
540 }
541
TEST(StatsEventTest,TestHeapBufferOverflowError)542 TEST(StatsEventTest, TestHeapBufferOverflowError) {
543 const std::string testString(4039, 'A');
544 const std::string testString2(47135, 'B');
545
546 AStatsEvent* event = AStatsEvent_obtain();
547 AStatsEvent_setAtomId(event, 100);
548
549 AStatsEvent_writeString(event, testString.c_str());
550 size_t bufferSize = 0;
551 AStatsEvent_getBuffer(event, &bufferSize);
552 EXPECT_EQ(bufferSize, 4060);
553 uint32_t errors = AStatsEvent_getErrors(event);
554 EXPECT_EQ(errors, 0);
555
556 // expand the buffer and fill with data up to the very last byte
557 AStatsEvent_writeString(event, testString2.c_str());
558 bufferSize = 0;
559 AStatsEvent_getBuffer(event, &bufferSize);
560 EXPECT_EQ(bufferSize, 50 * 1024);
561
562 errors = AStatsEvent_getErrors(event);
563 EXPECT_EQ(errors, 0);
564
565 // this write is no-op due to buffer reached its max capacity
566 // should set the overflow flag
567 AStatsEvent_writeString(event, testString2.c_str());
568 bufferSize = 0;
569 AStatsEvent_getBuffer(event, &bufferSize);
570 EXPECT_EQ(bufferSize, 50 * 1024);
571
572 errors = AStatsEvent_getErrors(event);
573 EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
574
575 // here should be crash
576 AStatsEvent_addBoolAnnotation(event, 1, false);
577
578 AStatsEvent_write(event);
579
580 errors = AStatsEvent_getErrors(event);
581 EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
582
583 AStatsEvent_release(event);
584 }
585
TEST(StatsEventTest,TestPullOverflowError)586 TEST(StatsEventTest, TestPullOverflowError) {
587 const uint32_t atomId = 10100;
588 const vector<uint8_t> bytes(430 /* number of elements */, 1 /* value of each element */);
589 const int writeCount = 120; // Number of times to write bytes in the event.
590
591 AStatsEvent* event = AStatsEvent_obtain();
592 AStatsEvent_setAtomId(event, atomId);
593
594 // Add bytes to the event 120 times. Size of bytes is 430 so this will
595 // overflow the 50 KB pulled event buffer.
596 // We want to keep writeCount less than 127 to avoid hitting
597 // ERROR_TOO_MANY_FIELDS.
598 for (int i = 0; i < writeCount; i++) {
599 AStatsEvent_writeByteArray(event, bytes.data(), bytes.size());
600 }
601 AStatsEvent_build(event);
602
603 uint32_t errors = AStatsEvent_getErrors(event);
604 EXPECT_EQ(errors & ERROR_OVERFLOW, ERROR_OVERFLOW);
605
606 AStatsEvent_release(event);
607 }
608
TEST(StatsEventTest,TestLargePull)609 TEST(StatsEventTest, TestLargePull) {
610 const uint32_t atomId = 100;
611 const string str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
612 const int writeCount = 120; // Number of times to write str in the event.
613 const int64_t startTime = android::elapsedRealtimeNano();
614
615 AStatsEvent* event = AStatsEvent_obtain();
616 AStatsEvent_setAtomId(event, atomId);
617
618 // Add str to the event 120 times.
619 // We want to keep writeCount less than 127 to avoid hitting
620 // ERROR_TOO_MANY_FIELDS.
621 for (int i = 0; i < writeCount; i++) {
622 AStatsEvent_writeString(event, str.c_str());
623 }
624 AStatsEvent_build(event);
625 int64_t endTime = android::elapsedRealtimeNano();
626
627 size_t bufferSize;
628 uint8_t* buffer = AStatsEvent_getBuffer(event, &bufferSize);
629 uint8_t* bufferEnd = buffer + bufferSize;
630
631 checkMetadata(&buffer, writeCount, startTime, endTime, atomId);
632
633 // Check all instances of str have been written.
634 for (int i = 0; i < writeCount; i++) {
635 checkTypeHeader(&buffer, STRING_TYPE);
636 checkString(&buffer, str);
637 }
638
639 EXPECT_EQ(buffer, bufferEnd); // Ensure that we have read the entire buffer.
640 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
641 AStatsEvent_release(event);
642 }
643
TEST(StatsEventTest,TestAtomIdInvalidPositionError)644 TEST(StatsEventTest, TestAtomIdInvalidPositionError) {
645 AStatsEvent* event = AStatsEvent_obtain();
646 AStatsEvent_writeInt32(event, 0);
647 AStatsEvent_setAtomId(event, 100);
648 AStatsEvent_writeBool(event, true);
649 AStatsEvent_build(event);
650
651 uint32_t errors = AStatsEvent_getErrors(event);
652 EXPECT_EQ(errors & ERROR_ATOM_ID_INVALID_POSITION, ERROR_ATOM_ID_INVALID_POSITION);
653
654 AStatsEvent_release(event);
655 }
656
TEST(StatsEventTest,TestOverwriteTimestamp)657 TEST(StatsEventTest, TestOverwriteTimestamp) {
658 uint32_t atomId = 100;
659 int64_t expectedTimestamp = 0x123456789;
660 AStatsEvent* event = AStatsEvent_obtain();
661 AStatsEvent_setAtomId(event, atomId);
662 AStatsEvent_overwriteTimestamp(event, expectedTimestamp);
663 AStatsEvent_build(event);
664
665 uint8_t* buffer = AStatsEvent_getBuffer(event, NULL);
666
667 // Make sure that the timestamp is being overwritten.
668 checkMetadata(&buffer, /*numElements=*/0, /*startTime=*/expectedTimestamp,
669 /*endTime=*/expectedTimestamp, atomId);
670
671 EXPECT_EQ(AStatsEvent_getErrors(event), 0);
672 AStatsEvent_release(event);
673 }
674
TEST(StatsEventTest,TestAttributionChainTooLongError)675 TEST(StatsEventTest, TestAttributionChainTooLongError) {
676 uint32_t atomId = 100;
677 uint8_t numNodes = 128;
678 uint32_t uids[numNodes];
679 vector<string> tags(numNodes); // storage that cTag elements point to
680 const char* cTags[numNodes];
681 for (int i = 0; i < (int)numNodes; i++) {
682 uids[i] = i;
683 if (0 == i) {
684 tags.push_back("");
685 cTags[i] = nullptr;
686 } else {
687 tags.push_back("test" + std::to_string(i));
688 cTags[i] = tags[i].c_str();
689 }
690 }
691
692 AStatsEvent* event = AStatsEvent_obtain();
693 AStatsEvent_setAtomId(event, atomId);
694 AStatsEvent_writeAttributionChain(event, uids, cTags, numNodes);
695 AStatsEvent_build(event);
696
697 uint32_t errors = AStatsEvent_getErrors(event);
698 EXPECT_EQ(errors & ERROR_ATTRIBUTION_CHAIN_TOO_LONG, ERROR_ATTRIBUTION_CHAIN_TOO_LONG);
699 }
700
TEST_GUARDED(StatsEventTest,TestListTooLongError,__ANDROID_API_T__)701 TEST_GUARDED(StatsEventTest, TestListTooLongError, __ANDROID_API_T__) {
702 uint32_t atomId = 100;
703 uint8_t numElements = 128;
704 int32_t int32Array[128] = {1};
705
706 AStatsEvent* event = AStatsEvent_obtain();
707 AStatsEvent_setAtomId(event, atomId);
708 AStatsEvent_writeInt32Array(event, int32Array, numElements);
709 AStatsEvent_build(event);
710
711 uint32_t errors = AStatsEvent_getErrors(event);
712 EXPECT_EQ(errors & ERROR_LIST_TOO_LONG, ERROR_LIST_TOO_LONG);
713 }
714