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