1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "src/logd/LogEvent.h"
16
17 #include <gtest/gtest.h>
18
19 #include "frameworks/proto_logging/stats/atoms.pb.h"
20 #include "frameworks/proto_logging/stats/enums/stats/launcher/launcher.pb.h"
21 #include "log/log_event_list.h"
22 #include "stats_event.h"
23
24 #ifdef __ANDROID__
25
26 namespace android {
27 namespace os {
28 namespace statsd {
29
30 using std::string;
31 using std::vector;
32 using util::ProtoOutputStream;
33 using util::ProtoReader;
34
35 namespace {
36
getField(int32_t tag,const vector<int32_t> & pos,int32_t depth,const vector<bool> & last)37 Field getField(int32_t tag, const vector<int32_t>& pos, int32_t depth, const vector<bool>& last) {
38 Field f(tag, (int32_t*)pos.data(), depth);
39
40 // For loop starts at 1 because the last field at depth 0 is not decorated.
41 for (int i = 1; i < depth; i++) {
42 if (last[i]) f.decorateLastPos(i);
43 }
44
45 return f;
46 }
47
createIntWithBoolAnnotationLogEvent(LogEvent * logEvent,uint8_t annotationId,bool annotationValue)48 void createIntWithBoolAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
49 bool annotationValue) {
50 AStatsEvent* statsEvent = AStatsEvent_obtain();
51 AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
52 AStatsEvent_writeInt32(statsEvent, 10);
53 AStatsEvent_addBoolAnnotation(statsEvent, annotationId, annotationValue);
54 AStatsEvent_build(statsEvent);
55
56 size_t size;
57 uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
58 EXPECT_TRUE(logEvent->parseBuffer(buf, size));
59
60 AStatsEvent_release(statsEvent);
61 }
62
createIntWithIntAnnotationLogEvent(LogEvent * logEvent,uint8_t annotationId,int annotationValue)63 void createIntWithIntAnnotationLogEvent(LogEvent* logEvent, uint8_t annotationId,
64 int annotationValue) {
65 AStatsEvent* statsEvent = AStatsEvent_obtain();
66 AStatsEvent_setAtomId(statsEvent, /*atomId=*/100);
67 AStatsEvent_writeInt32(statsEvent, 10);
68 AStatsEvent_addInt32Annotation(statsEvent, annotationId, annotationValue);
69 AStatsEvent_build(statsEvent);
70
71 size_t size;
72 uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
73 EXPECT_TRUE(logEvent->parseBuffer(buf, size));
74
75 AStatsEvent_release(statsEvent);
76 }
77
78 } // anonymous namespace
79
TEST(LogEventTest,TestPrimitiveParsing)80 TEST(LogEventTest, TestPrimitiveParsing) {
81 AStatsEvent* event = AStatsEvent_obtain();
82 AStatsEvent_setAtomId(event, 100);
83 AStatsEvent_writeInt32(event, 10);
84 AStatsEvent_writeInt64(event, 0x123456789);
85 AStatsEvent_writeFloat(event, 2.0);
86 AStatsEvent_writeBool(event, true);
87 AStatsEvent_build(event);
88
89 size_t size;
90 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
91
92 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
93 EXPECT_TRUE(logEvent.parseBuffer(buf, size));
94
95 EXPECT_EQ(100, logEvent.GetTagId());
96 EXPECT_EQ(1000, logEvent.GetUid());
97 EXPECT_EQ(1001, logEvent.GetPid());
98 EXPECT_FALSE(logEvent.hasAttributionChain());
99
100 const vector<FieldValue>& values = logEvent.getValues();
101 ASSERT_EQ(4, values.size());
102
103 const FieldValue& int32Item = values[0];
104 Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
105 EXPECT_EQ(expectedField, int32Item.mField);
106 EXPECT_EQ(Type::INT, int32Item.mValue.getType());
107 EXPECT_EQ(10, int32Item.mValue.int_value);
108
109 const FieldValue& int64Item = values[1];
110 expectedField = getField(100, {2, 1, 1}, 0, {false, false, false});
111 EXPECT_EQ(expectedField, int64Item.mField);
112 EXPECT_EQ(Type::LONG, int64Item.mValue.getType());
113 EXPECT_EQ(0x123456789, int64Item.mValue.long_value);
114
115 const FieldValue& floatItem = values[2];
116 expectedField = getField(100, {3, 1, 1}, 0, {false, false, false});
117 EXPECT_EQ(expectedField, floatItem.mField);
118 EXPECT_EQ(Type::FLOAT, floatItem.mValue.getType());
119 EXPECT_EQ(2.0, floatItem.mValue.float_value);
120
121 const FieldValue& boolItem = values[3];
122 expectedField = getField(100, {4, 1, 1}, 0, {true, false, false});
123 EXPECT_EQ(expectedField, boolItem.mField);
124 EXPECT_EQ(Type::INT, boolItem.mValue.getType()); // FieldValue does not support boolean type
125 EXPECT_EQ(1, boolItem.mValue.int_value);
126
127 AStatsEvent_release(event);
128 }
129
TEST(LogEventTest,TestStringAndByteArrayParsing)130 TEST(LogEventTest, TestStringAndByteArrayParsing) {
131 AStatsEvent* event = AStatsEvent_obtain();
132 AStatsEvent_setAtomId(event, 100);
133 string str = "test";
134 AStatsEvent_writeString(event, str.c_str());
135 AStatsEvent_writeByteArray(event, (uint8_t*)str.c_str(), str.length());
136 AStatsEvent_build(event);
137
138 size_t size;
139 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
140
141 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
142 EXPECT_TRUE(logEvent.parseBuffer(buf, size));
143
144 EXPECT_EQ(100, logEvent.GetTagId());
145 EXPECT_EQ(1000, logEvent.GetUid());
146 EXPECT_EQ(1001, logEvent.GetPid());
147 EXPECT_FALSE(logEvent.hasAttributionChain());
148
149 const vector<FieldValue>& values = logEvent.getValues();
150 ASSERT_EQ(2, values.size());
151
152 const FieldValue& stringItem = values[0];
153 Field expectedField = getField(100, {1, 1, 1}, 0, {false, false, false});
154 EXPECT_EQ(expectedField, stringItem.mField);
155 EXPECT_EQ(Type::STRING, stringItem.mValue.getType());
156 EXPECT_EQ(str, stringItem.mValue.str_value);
157
158 const FieldValue& storageItem = values[1];
159 expectedField = getField(100, {2, 1, 1}, 0, {true, false, false});
160 EXPECT_EQ(expectedField, storageItem.mField);
161 EXPECT_EQ(Type::STORAGE, storageItem.mValue.getType());
162 vector<uint8_t> expectedValue = {'t', 'e', 's', 't'};
163 EXPECT_EQ(expectedValue, storageItem.mValue.storage_value);
164
165 AStatsEvent_release(event);
166 }
167
TEST(LogEventTest,TestEmptyString)168 TEST(LogEventTest, TestEmptyString) {
169 AStatsEvent* event = AStatsEvent_obtain();
170 AStatsEvent_setAtomId(event, 100);
171 string empty = "";
172 AStatsEvent_writeString(event, empty.c_str());
173 AStatsEvent_build(event);
174
175 size_t size;
176 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
177
178 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
179 EXPECT_TRUE(logEvent.parseBuffer(buf, size));
180
181 EXPECT_EQ(100, logEvent.GetTagId());
182 EXPECT_EQ(1000, logEvent.GetUid());
183 EXPECT_EQ(1001, logEvent.GetPid());
184 EXPECT_FALSE(logEvent.hasAttributionChain());
185
186 const vector<FieldValue>& values = logEvent.getValues();
187 ASSERT_EQ(1, values.size());
188
189 const FieldValue& item = values[0];
190 Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
191 EXPECT_EQ(expectedField, item.mField);
192 EXPECT_EQ(Type::STRING, item.mValue.getType());
193 EXPECT_EQ(empty, item.mValue.str_value);
194
195 AStatsEvent_release(event);
196 }
197
TEST(LogEventTest,TestByteArrayWithNullCharacter)198 TEST(LogEventTest, TestByteArrayWithNullCharacter) {
199 AStatsEvent* event = AStatsEvent_obtain();
200 AStatsEvent_setAtomId(event, 100);
201 uint8_t message[] = {'\t', 'e', '\0', 's', 't'};
202 AStatsEvent_writeByteArray(event, message, 5);
203 AStatsEvent_build(event);
204
205 size_t size;
206 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
207
208 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
209 EXPECT_TRUE(logEvent.parseBuffer(buf, size));
210
211 EXPECT_EQ(100, logEvent.GetTagId());
212 EXPECT_EQ(1000, logEvent.GetUid());
213 EXPECT_EQ(1001, logEvent.GetPid());
214
215 const vector<FieldValue>& values = logEvent.getValues();
216 ASSERT_EQ(1, values.size());
217
218 const FieldValue& item = values[0];
219 Field expectedField = getField(100, {1, 1, 1}, 0, {true, false, false});
220 EXPECT_EQ(expectedField, item.mField);
221 EXPECT_EQ(Type::STORAGE, item.mValue.getType());
222 vector<uint8_t> expectedValue(message, message + 5);
223 EXPECT_EQ(expectedValue, item.mValue.storage_value);
224
225 AStatsEvent_release(event);
226 }
227
TEST(LogEventTest,TestAttributionChain)228 TEST(LogEventTest, TestAttributionChain) {
229 AStatsEvent* event = AStatsEvent_obtain();
230 AStatsEvent_setAtomId(event, 100);
231
232 string tag1 = "tag1";
233 string tag2 = "tag2";
234
235 uint32_t uids[] = {1001, 1002};
236 const char* tags[] = {tag1.c_str(), tag2.c_str()};
237
238 AStatsEvent_writeAttributionChain(event, uids, tags, 2);
239 AStatsEvent_build(event);
240
241 size_t size;
242 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
243
244 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
245 EXPECT_TRUE(logEvent.parseBuffer(buf, size));
246
247 EXPECT_EQ(100, logEvent.GetTagId());
248 EXPECT_EQ(1000, logEvent.GetUid());
249 EXPECT_EQ(1001, logEvent.GetPid());
250
251 const vector<FieldValue>& values = logEvent.getValues();
252 ASSERT_EQ(4, values.size()); // 2 per attribution node
253
254 std::pair<int, int> attrIndexRange;
255 EXPECT_TRUE(logEvent.hasAttributionChain(&attrIndexRange));
256 EXPECT_EQ(0, attrIndexRange.first);
257 EXPECT_EQ(3, attrIndexRange.second);
258
259 // Check first attribution node
260 const FieldValue& uid1Item = values[0];
261 Field expectedField = getField(100, {1, 1, 1}, 2, {true, false, false});
262 EXPECT_EQ(expectedField, uid1Item.mField);
263 EXPECT_EQ(Type::INT, uid1Item.mValue.getType());
264 EXPECT_EQ(1001, uid1Item.mValue.int_value);
265
266 const FieldValue& tag1Item = values[1];
267 expectedField = getField(100, {1, 1, 2}, 2, {true, false, true});
268 EXPECT_EQ(expectedField, tag1Item.mField);
269 EXPECT_EQ(Type::STRING, tag1Item.mValue.getType());
270 EXPECT_EQ(tag1, tag1Item.mValue.str_value);
271
272 // Check second attribution nodes
273 const FieldValue& uid2Item = values[2];
274 expectedField = getField(100, {1, 2, 1}, 2, {true, true, false});
275 EXPECT_EQ(expectedField, uid2Item.mField);
276 EXPECT_EQ(Type::INT, uid2Item.mValue.getType());
277 EXPECT_EQ(1002, uid2Item.mValue.int_value);
278
279 const FieldValue& tag2Item = values[3];
280 expectedField = getField(100, {1, 2, 2}, 2, {true, true, true});
281 EXPECT_EQ(expectedField, tag2Item.mField);
282 EXPECT_EQ(Type::STRING, tag2Item.mValue.getType());
283 EXPECT_EQ(tag2, tag2Item.mValue.str_value);
284
285 AStatsEvent_release(event);
286 }
287
TEST(LogEventTest,TestAnnotationIdIsUid)288 TEST(LogEventTest, TestAnnotationIdIsUid) {
289 LogEvent event(/*uid=*/0, /*pid=*/0);
290 createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_IS_UID, true);
291
292 const vector<FieldValue>& values = event.getValues();
293 ASSERT_EQ(values.size(), 1);
294 EXPECT_EQ(event.getUidFieldIndex(), 0);
295 }
296
TEST(LogEventTest,TestAnnotationIdStateNested)297 TEST(LogEventTest, TestAnnotationIdStateNested) {
298 LogEvent event(/*uid=*/0, /*pid=*/0);
299 createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_STATE_NESTED, true);
300
301 const vector<FieldValue>& values = event.getValues();
302 ASSERT_EQ(values.size(), 1);
303 EXPECT_TRUE(values[0].mAnnotations.isNested());
304 }
305
TEST(LogEventTest,TestPrimaryFieldAnnotation)306 TEST(LogEventTest, TestPrimaryFieldAnnotation) {
307 LogEvent event(/*uid=*/0, /*pid=*/0);
308 createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_PRIMARY_FIELD, true);
309
310 const vector<FieldValue>& values = event.getValues();
311 ASSERT_EQ(values.size(), 1);
312 EXPECT_TRUE(values[0].mAnnotations.isPrimaryField());
313 }
314
TEST(LogEventTest,TestExclusiveStateAnnotation)315 TEST(LogEventTest, TestExclusiveStateAnnotation) {
316 LogEvent event(/*uid=*/0, /*pid=*/0);
317 createIntWithBoolAnnotationLogEvent(&event, ANNOTATION_ID_EXCLUSIVE_STATE, true);
318
319 const vector<FieldValue>& values = event.getValues();
320 ASSERT_EQ(values.size(), 1);
321 EXPECT_TRUE(values[0].mAnnotations.isExclusiveState());
322 }
323
TEST(LogEventTest,TestPrimaryFieldFirstUidAnnotation)324 TEST(LogEventTest, TestPrimaryFieldFirstUidAnnotation) {
325 // Event has 10 ints and then an attribution chain
326 int numInts = 10;
327 int firstUidInChainIndex = numInts;
328 string tag1 = "tag1";
329 string tag2 = "tag2";
330 uint32_t uids[] = {1001, 1002};
331 const char* tags[] = {tag1.c_str(), tag2.c_str()};
332
333 // Construct AStatsEvent
334 AStatsEvent* statsEvent = AStatsEvent_obtain();
335 AStatsEvent_setAtomId(statsEvent, 100);
336 for (int i = 0; i < numInts; i++) {
337 AStatsEvent_writeInt32(statsEvent, 10);
338 }
339 AStatsEvent_writeAttributionChain(statsEvent, uids, tags, 2);
340 AStatsEvent_addBoolAnnotation(statsEvent, ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
341 AStatsEvent_build(statsEvent);
342
343 // Construct LogEvent
344 size_t size;
345 uint8_t* buf = AStatsEvent_getBuffer(statsEvent, &size);
346 LogEvent logEvent(/*uid=*/0, /*pid=*/0);
347 EXPECT_TRUE(logEvent.parseBuffer(buf, size));
348 AStatsEvent_release(statsEvent);
349
350 // Check annotation
351 const vector<FieldValue>& values = logEvent.getValues();
352 ASSERT_EQ(values.size(), numInts + 4);
353 EXPECT_TRUE(values[firstUidInChainIndex].mAnnotations.isPrimaryField());
354 }
355
TEST(LogEventTest,TestResetStateAnnotation)356 TEST(LogEventTest, TestResetStateAnnotation) {
357 int32_t resetState = 10;
358 LogEvent event(/*uid=*/0, /*pid=*/0);
359 createIntWithIntAnnotationLogEvent(&event, ANNOTATION_ID_TRIGGER_STATE_RESET, resetState);
360
361 const vector<FieldValue>& values = event.getValues();
362 ASSERT_EQ(values.size(), 1);
363 EXPECT_EQ(event.getResetState(), resetState);
364 }
365
TEST(LogEventTest,TestExclusiveStateAnnotationAfterTooManyFields)366 TEST(LogEventTest, TestExclusiveStateAnnotationAfterTooManyFields) {
367 AStatsEvent* event = AStatsEvent_obtain();
368 AStatsEvent_setAtomId(event, 100);
369
370 const unsigned int numAttributionNodes = 64;
371
372 uint32_t uids[numAttributionNodes];
373 const char* tags[numAttributionNodes];
374
375 for (unsigned int i = 1; i <= numAttributionNodes; i++) {
376 uids[i-1] = i;
377 tags[i-1] = std::to_string(i).c_str();
378 }
379
380 AStatsEvent_writeAttributionChain(event, uids, tags, numAttributionNodes);
381 AStatsEvent_writeInt32(event, 1);
382 AStatsEvent_addBoolAnnotation(event, ANNOTATION_ID_EXCLUSIVE_STATE, true);
383
384 AStatsEvent_build(event);
385
386 size_t size;
387 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
388
389 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
390 EXPECT_FALSE(logEvent.parseBuffer(buf, size));
391 EXPECT_EQ(-1, logEvent.getExclusiveStateFieldIndex());
392
393 AStatsEvent_release(event);
394 }
395
TEST(LogEventTest,TestUidAnnotationAfterTooManyFields)396 TEST(LogEventTest, TestUidAnnotationAfterTooManyFields) {
397 AStatsEvent* event = AStatsEvent_obtain();
398 AStatsEvent_setAtomId(event, 100);
399
400 const unsigned int numAttributionNodes = 64;
401
402 uint32_t uids[numAttributionNodes];
403 const char* tags[numAttributionNodes];
404
405 for (unsigned int i = 1; i <= numAttributionNodes; i++) {
406 uids[i-1] = i;
407 tags[i-1] = std::to_string(i).c_str();
408 }
409
410 AStatsEvent_writeAttributionChain(event, uids, tags, numAttributionNodes);
411 AStatsEvent_writeInt32(event, 1);
412 AStatsEvent_addBoolAnnotation(event, ANNOTATION_ID_IS_UID, true);
413
414 AStatsEvent_build(event);
415
416 size_t size;
417 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
418
419 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
420 EXPECT_FALSE(logEvent.parseBuffer(buf, size));
421 EXPECT_EQ(-1, logEvent.getUidFieldIndex());
422
423 AStatsEvent_release(event);
424 }
425
TEST(LogEventTest,TestAttributionChainEndIndexAfterTooManyFields)426 TEST(LogEventTest, TestAttributionChainEndIndexAfterTooManyFields) {
427 AStatsEvent* event = AStatsEvent_obtain();
428 AStatsEvent_setAtomId(event, 100);
429
430 const unsigned int numAttributionNodes = 65;
431
432 uint32_t uids[numAttributionNodes];
433 const char* tags[numAttributionNodes];
434
435 for (unsigned int i = 1; i <= numAttributionNodes; i++) {
436 uids[i-1] = i;
437 tags[i-1] = std::to_string(i).c_str();
438 }
439
440 AStatsEvent_writeAttributionChain(event, uids, tags, numAttributionNodes);
441
442 AStatsEvent_build(event);
443
444 size_t size;
445 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
446
447 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
448 EXPECT_FALSE(logEvent.parseBuffer(buf, size));
449 EXPECT_FALSE(logEvent.hasAttributionChain());
450
451 AStatsEvent_release(event);
452 }
453
TEST(LogEventTest,TestEmptyAttributionChainWithPrimaryFieldFirstUidAnnotation)454 TEST(LogEventTest, TestEmptyAttributionChainWithPrimaryFieldFirstUidAnnotation) {
455 AStatsEvent* event = AStatsEvent_obtain();
456 AStatsEvent_setAtomId(event, 100);
457
458 uint32_t uids[] = {};
459 const char* tags[] = {};
460
461 AStatsEvent_writeInt32(event, 10);
462 AStatsEvent_writeAttributionChain(event, uids, tags, 0);
463 AStatsEvent_addBoolAnnotation(event, ANNOTATION_ID_PRIMARY_FIELD_FIRST_UID, true);
464
465 AStatsEvent_build(event);
466
467 size_t size;
468 uint8_t* buf = AStatsEvent_getBuffer(event, &size);
469
470 LogEvent logEvent(/*uid=*/1000, /*pid=*/1001);
471 EXPECT_FALSE(logEvent.parseBuffer(buf, size));
472
473 AStatsEvent_release(event);
474 }
475
476 } // namespace statsd
477 } // namespace os
478 } // namespace android
479 #else
480 GTEST_LOG_(INFO) << "This test does nothing.\n";
481 #endif
482