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