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/condition/SimpleConditionTracker.h"
16 #include "stats_event.h"
17 #include "tests/statsd_test_util.h"
18
19 #include <gmock/gmock.h>
20 #include <gtest/gtest.h>
21 #include <stdio.h>
22 #include <vector>
23 #include <numeric>
24
25 using std::map;
26 using std::unordered_map;
27 using std::vector;
28
29 #ifdef __ANDROID__
30
31 namespace android {
32 namespace os {
33 namespace statsd {
34
35 namespace {
36
37 const ConfigKey kConfigKey(0, 12345);
38
39 const int ATTRIBUTION_NODE_FIELD_ID = 1;
40 const int ATTRIBUTION_UID_FIELD_ID = 1;
41 const int TAG_ID = 1;
42 const uint64_t protoHash = 0x123456789;
43
getWakeLockHeldCondition(bool countNesting,bool defaultFalse,bool outputSlicedUid,Position position)44 SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
45 bool outputSlicedUid, Position position) {
46 SimplePredicate simplePredicate;
47 simplePredicate.set_start(StringToId("WAKE_LOCK_ACQUIRE"));
48 simplePredicate.set_stop(StringToId("WAKE_LOCK_RELEASE"));
49 simplePredicate.set_stop_all(StringToId("RELEASE_ALL"));
50 if (outputSlicedUid) {
51 simplePredicate.mutable_dimensions()->set_field(TAG_ID);
52 simplePredicate.mutable_dimensions()->add_child()->set_field(ATTRIBUTION_NODE_FIELD_ID);
53 simplePredicate.mutable_dimensions()->mutable_child(0)->set_position(position);
54 simplePredicate.mutable_dimensions()->mutable_child(0)->add_child()->set_field(
55 ATTRIBUTION_UID_FIELD_ID);
56 }
57
58 simplePredicate.set_count_nesting(countNesting);
59 simplePredicate.set_initial_value(defaultFalse ? SimplePredicate_InitialValue_FALSE
60 : SimplePredicate_InitialValue_UNKNOWN);
61 return simplePredicate;
62 }
63
makeWakeLockEvent(LogEvent * logEvent,uint32_t atomId,uint64_t timestamp,const vector<int> & uids,const string & wl,int acquire)64 void makeWakeLockEvent(LogEvent* logEvent, uint32_t atomId, uint64_t timestamp,
65 const vector<int>& uids, const string& wl, int acquire) {
66 AStatsEvent* statsEvent = AStatsEvent_obtain();
67 AStatsEvent_setAtomId(statsEvent, atomId);
68 AStatsEvent_overwriteTimestamp(statsEvent, timestamp);
69
70 vector<std::string> tags(uids.size()); // vector of empty strings
71 writeAttribution(statsEvent, uids, tags);
72
73 AStatsEvent_writeString(statsEvent, wl.c_str());
74 AStatsEvent_writeInt32(statsEvent, acquire);
75
76 parseStatsEventToLogEvent(statsEvent, logEvent);
77 }
78
79 } // anonymous namespace
80
81
getWakeLockQueryKey(const Position position,const std::vector<int> & uids,const string & conditionName)82 std::map<int64_t, HashableDimensionKey> getWakeLockQueryKey(
83 const Position position,
84 const std::vector<int> &uids, const string& conditionName) {
85 std::map<int64_t, HashableDimensionKey> outputKeyMap;
86 std::vector<int> uid_indexes;
87 int pos[] = {1, 1, 1};
88 int depth = 2;
89 Field field(1, pos, depth);
90 switch(position) {
91 case Position::FIRST:
92 uid_indexes.push_back(0);
93 break;
94 case Position::LAST:
95 uid_indexes.push_back(uids.size() - 1);
96 field.setField(0x02018001);
97 break;
98 case Position::ANY:
99 uid_indexes.resize(uids.size());
100 std::iota(uid_indexes.begin(), uid_indexes.end(), 0);
101 field.setField(0x02010001);
102 break;
103 default:
104 break;
105 }
106
107 for (const int idx : uid_indexes) {
108 Value value((int32_t)uids[idx]);
109 HashableDimensionKey dim;
110 dim.addValue(FieldValue(field, value));
111 outputKeyMap[StringToId(conditionName)] = dim;
112 }
113 return outputKeyMap;
114 }
115
TEST(SimpleConditionTrackerTest,TestNonSlicedInitialValueFalse)116 TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueFalse) {
117 SimplePredicate simplePredicate;
118 simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
119 simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
120 simplePredicate.set_count_nesting(false);
121 simplePredicate.set_initial_value(SimplePredicate_InitialValue_FALSE);
122
123 unordered_map<int64_t, int> trackerNameIndexMap;
124 trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
125 trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
126
127 SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
128 0 /*tracker index*/, simplePredicate,
129 trackerNameIndexMap);
130
131 ConditionKey queryKey;
132 vector<sp<ConditionTracker>> allPredicates;
133 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
134
135 // Check that initial condition is false.
136 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
137 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
138
139 vector<MatchingState> matcherState;
140 vector<bool> changedCache(1, false);
141
142 // Matched stop event.
143 // Check that condition is still false.
144 unique_ptr<LogEvent> screenOffEvent =
145 CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
146 matcherState.clear();
147 matcherState.push_back(MatchingState::kNotMatched); // On matcher not matched
148 matcherState.push_back(MatchingState::kMatched); // Off matcher matched
149 conditionCache[0] = ConditionState::kNotEvaluated;
150 conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
151 changedCache);
152 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
153 EXPECT_FALSE(changedCache[0]);
154
155 // Matched start event.
156 // Check that condition has changed to true.
157 unique_ptr<LogEvent> screenOnEvent =
158 CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
159 matcherState.clear();
160 matcherState.push_back(MatchingState::kMatched); // On matcher matched
161 matcherState.push_back(MatchingState::kNotMatched); // Off matcher not matched
162 conditionCache[0] = ConditionState::kNotEvaluated;
163 changedCache[0] = false;
164 conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
165 changedCache);
166 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
167 EXPECT_TRUE(changedCache[0]);
168 }
169
TEST(SimpleConditionTrackerTest,TestNonSlicedInitialValueUnknown)170 TEST(SimpleConditionTrackerTest, TestNonSlicedInitialValueUnknown) {
171 SimplePredicate simplePredicate;
172 simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
173 simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
174 simplePredicate.set_count_nesting(false);
175 simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
176
177 unordered_map<int64_t, int> trackerNameIndexMap;
178 trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
179 trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
180
181 SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
182 0 /*tracker index*/, simplePredicate,
183 trackerNameIndexMap);
184
185 ConditionKey queryKey;
186 vector<sp<ConditionTracker>> allPredicates;
187 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
188
189 // Check that initial condition is unknown.
190 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
191 EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
192
193 vector<MatchingState> matcherState;
194 vector<bool> changedCache(1, false);
195
196 // Matched stop event.
197 // Check that condition is changed to false.
198 unique_ptr<LogEvent> screenOffEvent =
199 CreateScreenStateChangedEvent(/*timestamp=*/50, android::view::DISPLAY_STATE_OFF);
200 matcherState.clear();
201 matcherState.push_back(MatchingState::kNotMatched); // On matcher not matched
202 matcherState.push_back(MatchingState::kMatched); // Off matcher matched
203 conditionCache[0] = ConditionState::kNotEvaluated;
204 conditionTracker.evaluateCondition(*screenOffEvent, matcherState, allPredicates, conditionCache,
205 changedCache);
206 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
207 EXPECT_TRUE(changedCache[0]);
208
209 // Matched start event.
210 // Check that condition has changed to true.
211 unique_ptr<LogEvent> screenOnEvent =
212 CreateScreenStateChangedEvent(/*timestamp=*/100, android::view::DISPLAY_STATE_ON);
213 matcherState.clear();
214 matcherState.push_back(MatchingState::kMatched); // On matcher matched
215 matcherState.push_back(MatchingState::kNotMatched); // Off matcher not matched
216 conditionCache[0] = ConditionState::kNotEvaluated;
217 changedCache[0] = false;
218 conditionTracker.evaluateCondition(*screenOnEvent, matcherState, allPredicates, conditionCache,
219 changedCache);
220 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
221 EXPECT_TRUE(changedCache[0]);
222 }
223
TEST(SimpleConditionTrackerTest,TestNonSlicedCondition)224 TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
225 SimplePredicate simplePredicate;
226 simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
227 simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
228 simplePredicate.set_count_nesting(false);
229 simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
230
231 unordered_map<int64_t, int> trackerNameIndexMap;
232 trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
233 trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
234
235 SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
236 0 /*tracker index*/, simplePredicate,
237 trackerNameIndexMap);
238 EXPECT_FALSE(conditionTracker.isSliced());
239
240 // This event is not accessed in this test besides dimensions which is why this is okay.
241 // This is technically an invalid LogEvent because we do not call parseBuffer.
242 LogEvent event(/*uid=*/0, /*pid=*/0);
243
244 vector<MatchingState> matcherState;
245 matcherState.push_back(MatchingState::kNotMatched);
246 matcherState.push_back(MatchingState::kNotMatched);
247
248 vector<sp<ConditionTracker>> allPredicates;
249 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
250 vector<bool> changedCache(1, false);
251
252 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
253 changedCache);
254 // not matched start or stop. condition doesn't change
255 EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
256 EXPECT_FALSE(changedCache[0]);
257
258 // prepare a case for match start.
259 matcherState.clear();
260 matcherState.push_back(MatchingState::kMatched);
261 matcherState.push_back(MatchingState::kNotMatched);
262 conditionCache[0] = ConditionState::kNotEvaluated;
263 changedCache[0] = false;
264
265 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
266 changedCache);
267 // now condition should change to true.
268 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
269 EXPECT_TRUE(changedCache[0]);
270
271 // match nothing.
272 matcherState.clear();
273 matcherState.push_back(MatchingState::kNotMatched);
274 matcherState.push_back(MatchingState::kNotMatched);
275 conditionCache[0] = ConditionState::kNotEvaluated;
276 changedCache[0] = false;
277
278 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
279 changedCache);
280 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
281 EXPECT_FALSE(changedCache[0]);
282
283 // the case for match stop.
284 matcherState.clear();
285 matcherState.push_back(MatchingState::kNotMatched);
286 matcherState.push_back(MatchingState::kMatched);
287 conditionCache[0] = ConditionState::kNotEvaluated;
288 changedCache[0] = false;
289
290 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
291 changedCache);
292
293 // condition changes to false.
294 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
295 EXPECT_TRUE(changedCache[0]);
296
297 // match stop again.
298 matcherState.clear();
299 matcherState.push_back(MatchingState::kNotMatched);
300 matcherState.push_back(MatchingState::kMatched);
301 conditionCache[0] = ConditionState::kNotEvaluated;
302 changedCache[0] = false;
303
304 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
305 changedCache);
306 // condition should still be false. not changed.
307 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
308 EXPECT_FALSE(changedCache[0]);
309 }
310
TEST(SimpleConditionTrackerTest,TestNonSlicedConditionNestCounting)311 TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
312 std::vector<sp<ConditionTracker>> allConditions;
313 SimplePredicate simplePredicate;
314 simplePredicate.set_start(StringToId("SCREEN_TURNED_ON"));
315 simplePredicate.set_stop(StringToId("SCREEN_TURNED_OFF"));
316 simplePredicate.set_count_nesting(true);
317
318 unordered_map<int64_t, int> trackerNameIndexMap;
319 trackerNameIndexMap[StringToId("SCREEN_TURNED_ON")] = 0;
320 trackerNameIndexMap[StringToId("SCREEN_TURNED_OFF")] = 1;
321
322 SimpleConditionTracker conditionTracker(kConfigKey, StringToId("SCREEN_IS_ON"), protoHash,
323 0 /*condition tracker index*/, simplePredicate,
324 trackerNameIndexMap);
325 EXPECT_FALSE(conditionTracker.isSliced());
326
327 // This event is not accessed in this test besides dimensions which is why this is okay.
328 // This is technically an invalid LogEvent because we do not call parseBuffer.
329 LogEvent event(/*uid=*/0, /*pid=*/0);
330
331 // one matched start
332 vector<MatchingState> matcherState;
333 matcherState.push_back(MatchingState::kMatched);
334 matcherState.push_back(MatchingState::kNotMatched);
335 vector<sp<ConditionTracker>> allPredicates;
336 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
337 vector<bool> changedCache(1, false);
338
339 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
340 changedCache);
341
342 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
343 EXPECT_TRUE(changedCache[0]);
344
345 // prepare for another matched start.
346 matcherState.clear();
347 matcherState.push_back(MatchingState::kMatched);
348 matcherState.push_back(MatchingState::kNotMatched);
349 conditionCache[0] = ConditionState::kNotEvaluated;
350 changedCache[0] = false;
351
352 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
353 changedCache);
354
355 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
356 EXPECT_FALSE(changedCache[0]);
357
358 // ONE MATCHED STOP
359 matcherState.clear();
360 matcherState.push_back(MatchingState::kNotMatched);
361 matcherState.push_back(MatchingState::kMatched);
362 conditionCache[0] = ConditionState::kNotEvaluated;
363 changedCache[0] = false;
364
365 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
366 changedCache);
367 // result should still be true
368 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
369 EXPECT_FALSE(changedCache[0]);
370
371 // ANOTHER MATCHED STOP
372 matcherState.clear();
373 matcherState.push_back(MatchingState::kNotMatched);
374 matcherState.push_back(MatchingState::kMatched);
375 conditionCache[0] = ConditionState::kNotEvaluated;
376 changedCache[0] = false;
377
378 conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
379 changedCache);
380 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
381 EXPECT_TRUE(changedCache[0]);
382 }
383
TEST(SimpleConditionTrackerTest,TestSlicedCondition)384 TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
385 std::vector<sp<ConditionTracker>> allConditions;
386 for (Position position : {Position::FIRST, Position::LAST}) {
387 SimplePredicate simplePredicate = getWakeLockHeldCondition(
388 true /*nesting*/, true /*default to false*/, true /*output slice by uid*/,
389 position);
390 string conditionName = "WL_HELD_BY_UID2";
391
392 unordered_map<int64_t, int> trackerNameIndexMap;
393 trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
394 trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
395 trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
396
397 SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
398 0 /*condition tracker index*/, simplePredicate,
399 trackerNameIndexMap);
400
401 std::vector<int> uids = {111, 222, 333};
402
403 LogEvent event1(/*uid=*/0, /*pid=*/0);
404 makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/1);
405
406 // one matched start
407 vector<MatchingState> matcherState;
408 matcherState.push_back(MatchingState::kMatched);
409 matcherState.push_back(MatchingState::kNotMatched);
410 matcherState.push_back(MatchingState::kNotMatched);
411 vector<sp<ConditionTracker>> allPredicates;
412 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
413 vector<bool> changedCache(1, false);
414
415 conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
416 changedCache);
417
418 if (position == Position::FIRST || position == Position::LAST) {
419 ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
420 } else {
421 ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
422 }
423 EXPECT_TRUE(changedCache[0]);
424 if (position == Position::FIRST || position == Position::LAST) {
425 ASSERT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(), 1u);
426 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
427 } else {
428 EXPECT_EQ(conditionTracker.getChangedToTrueDimensions(allConditions)->size(),
429 uids.size());
430 }
431
432 // Now test query
433 const auto queryKey = getWakeLockQueryKey(position, uids, conditionName);
434 conditionCache[0] = ConditionState::kNotEvaluated;
435
436 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
437 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
438
439 // another wake lock acquired by this uid
440 LogEvent event2(/*uid=*/0, /*pid=*/0);
441 makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/1);
442 matcherState.clear();
443 matcherState.push_back(MatchingState::kMatched);
444 matcherState.push_back(MatchingState::kNotMatched);
445 conditionCache[0] = ConditionState::kNotEvaluated;
446 changedCache[0] = false;
447 conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
448 changedCache);
449 EXPECT_FALSE(changedCache[0]);
450 if (position == Position::FIRST || position == Position::LAST) {
451 ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
452 } else {
453 ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
454 }
455 EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
456 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
457
458
459 // wake lock 1 release
460 LogEvent event3(/*uid=*/0, /*pid=*/0);
461 makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids, "wl1", /*acquire=*/0);
462 matcherState.clear();
463 matcherState.push_back(MatchingState::kNotMatched);
464 matcherState.push_back(MatchingState::kMatched);
465 conditionCache[0] = ConditionState::kNotEvaluated;
466 changedCache[0] = false;
467 conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
468 changedCache);
469 // nothing changes, because wake lock 2 is still held for this uid
470 EXPECT_FALSE(changedCache[0]);
471 if (position == Position::FIRST || position == Position::LAST) {
472 ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
473 } else {
474 ASSERT_EQ(uids.size(), conditionTracker.mSlicedConditionState.size());
475 }
476 EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
477 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
478
479 LogEvent event4(/*uid=*/0, /*pid=*/0);
480 makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids, "wl2", /*acquire=*/0);
481 matcherState.clear();
482 matcherState.push_back(MatchingState::kNotMatched);
483 matcherState.push_back(MatchingState::kMatched);
484 conditionCache[0] = ConditionState::kNotEvaluated;
485 changedCache[0] = false;
486 conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
487 changedCache);
488 ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
489 EXPECT_TRUE(changedCache[0]);
490 if (position == Position::FIRST || position == Position::LAST) {
491 ASSERT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(), 1u);
492 EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
493 } else {
494 EXPECT_EQ(conditionTracker.getChangedToFalseDimensions(allConditions)->size(),
495 uids.size());
496 }
497
498 // query again
499 conditionCache[0] = ConditionState::kNotEvaluated;
500 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
501 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
502 }
503
504 }
505
TEST(SimpleConditionTrackerTest,TestSlicedWithNoOutputDim)506 TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
507 std::vector<sp<ConditionTracker>> allConditions;
508
509 SimplePredicate simplePredicate =
510 getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
511 false /*slice output by uid*/, Position::ANY /* position */);
512 string conditionName = "WL_HELD";
513
514 unordered_map<int64_t, int> trackerNameIndexMap;
515 trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
516 trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
517 trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
518
519 SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
520 0 /*condition tracker index*/, simplePredicate,
521 trackerNameIndexMap);
522
523 EXPECT_FALSE(conditionTracker.isSliced());
524
525 std::vector<int> uids1 = {111, 1111, 11111};
526 string uid1_wl1 = "wl1_1";
527 std::vector<int> uids2 = {222, 2222, 22222};
528 string uid2_wl1 = "wl2_1";
529
530 LogEvent event1(/*uid=*/0, /*pid=*/0);
531 makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1, /*acquire=*/1);
532
533 // one matched start for uid1
534 vector<MatchingState> matcherState;
535 matcherState.push_back(MatchingState::kMatched);
536 matcherState.push_back(MatchingState::kNotMatched);
537 matcherState.push_back(MatchingState::kNotMatched);
538 vector<sp<ConditionTracker>> allPredicates;
539 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
540 vector<bool> changedCache(1, false);
541
542 conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
543 changedCache);
544
545 ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
546 EXPECT_TRUE(changedCache[0]);
547
548 // Now test query
549 ConditionKey queryKey;
550 conditionCache[0] = ConditionState::kNotEvaluated;
551
552 conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
553 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
554
555 // another wake lock acquired by this uid
556 LogEvent event2(/*uid=*/0, /*pid=*/0);
557 makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1, /*acquire=*/1);
558
559 matcherState.clear();
560 matcherState.push_back(MatchingState::kMatched);
561 matcherState.push_back(MatchingState::kNotMatched);
562 conditionCache[0] = ConditionState::kNotEvaluated;
563 changedCache[0] = false;
564 conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
565 changedCache);
566 EXPECT_FALSE(changedCache[0]);
567
568 // uid1 wake lock 1 release
569 LogEvent event3(/*uid=*/0, /*pid=*/0);
570 makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids1, uid1_wl1,
571 /*release=*/0); // now release it.
572
573 matcherState.clear();
574 matcherState.push_back(MatchingState::kNotMatched);
575 matcherState.push_back(MatchingState::kMatched);
576 conditionCache[0] = ConditionState::kNotEvaluated;
577 changedCache[0] = false;
578 conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
579 changedCache);
580 // nothing changes, because uid2 is still holding wl.
581 EXPECT_FALSE(changedCache[0]);
582
583 LogEvent event4(/*uid=*/0, /*pid=*/0);
584 makeWakeLockEvent(&event4, /*atomId=*/1, /*timestamp=*/0, uids2, uid2_wl1,
585 /*acquire=*/0); // now release it.
586 matcherState.clear();
587 matcherState.push_back(MatchingState::kNotMatched);
588 matcherState.push_back(MatchingState::kMatched);
589 conditionCache[0] = ConditionState::kNotEvaluated;
590 changedCache[0] = false;
591 conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
592 changedCache);
593 ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
594 EXPECT_TRUE(changedCache[0]);
595
596 // query again
597 conditionCache[0] = ConditionState::kNotEvaluated;
598 conditionTracker.isConditionMet(queryKey, allPredicates, true, conditionCache);
599 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
600 }
601
TEST(SimpleConditionTrackerTest,TestStopAll)602 TEST(SimpleConditionTrackerTest, TestStopAll) {
603 std::vector<sp<ConditionTracker>> allConditions;
604 for (Position position : {Position::FIRST, Position::LAST}) {
605 SimplePredicate simplePredicate =
606 getWakeLockHeldCondition(true /*nesting*/, true /*default to false*/,
607 true /*output slice by uid*/, position);
608 string conditionName = "WL_HELD_BY_UID3";
609
610 unordered_map<int64_t, int> trackerNameIndexMap;
611 trackerNameIndexMap[StringToId("WAKE_LOCK_ACQUIRE")] = 0;
612 trackerNameIndexMap[StringToId("WAKE_LOCK_RELEASE")] = 1;
613 trackerNameIndexMap[StringToId("RELEASE_ALL")] = 2;
614
615 SimpleConditionTracker conditionTracker(kConfigKey, StringToId(conditionName), protoHash,
616 0 /*condition tracker index*/, simplePredicate,
617 trackerNameIndexMap);
618
619 std::vector<int> uids1 = {111, 1111, 11111};
620 std::vector<int> uids2 = {222, 2222, 22222};
621
622 LogEvent event1(/*uid=*/0, /*pid=*/0);
623 makeWakeLockEvent(&event1, /*atomId=*/1, /*timestamp=*/0, uids1, "wl1", /*acquire=*/1);
624
625 // one matched start
626 vector<MatchingState> matcherState;
627 matcherState.push_back(MatchingState::kMatched);
628 matcherState.push_back(MatchingState::kNotMatched);
629 matcherState.push_back(MatchingState::kNotMatched);
630 vector<sp<ConditionTracker>> allPredicates;
631 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
632 vector<bool> changedCache(1, false);
633
634 conditionTracker.evaluateCondition(event1, matcherState, allPredicates, conditionCache,
635 changedCache);
636 if (position == Position::FIRST || position == Position::LAST) {
637 ASSERT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
638 } else {
639 ASSERT_EQ(uids1.size(), conditionTracker.mSlicedConditionState.size());
640 }
641 EXPECT_TRUE(changedCache[0]);
642 {
643 if (position == Position::FIRST || position == Position::LAST) {
644 ASSERT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
645 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
646 } else {
647 EXPECT_EQ(uids1.size(),
648 conditionTracker.getChangedToTrueDimensions(allConditions)->size());
649 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
650 }
651 }
652
653 // Now test query
654 const auto queryKey = getWakeLockQueryKey(position, uids1, conditionName);
655 conditionCache[0] = ConditionState::kNotEvaluated;
656
657 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
658 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
659
660 // another wake lock acquired by uid2
661 LogEvent event2(/*uid=*/0, /*pid=*/0);
662 makeWakeLockEvent(&event2, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
663
664 matcherState.clear();
665 matcherState.push_back(MatchingState::kMatched);
666 matcherState.push_back(MatchingState::kNotMatched);
667 matcherState.push_back(MatchingState::kNotMatched);
668 conditionCache[0] = ConditionState::kNotEvaluated;
669 changedCache[0] = false;
670 conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
671 changedCache);
672 if (position == Position::FIRST || position == Position::LAST) {
673 ASSERT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
674 } else {
675 ASSERT_EQ(uids1.size() + uids2.size(), conditionTracker.mSlicedConditionState.size());
676 }
677 EXPECT_TRUE(changedCache[0]);
678 {
679 if (position == Position::FIRST || position == Position::LAST) {
680 ASSERT_EQ(1UL, conditionTracker.getChangedToTrueDimensions(allConditions)->size());
681 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
682 } else {
683 EXPECT_EQ(uids2.size(),
684 conditionTracker.getChangedToTrueDimensions(allConditions)->size());
685 EXPECT_TRUE(conditionTracker.getChangedToFalseDimensions(allConditions)->empty());
686 }
687 }
688
689 // TEST QUERY
690 const auto queryKey2 = getWakeLockQueryKey(position, uids2, conditionName);
691 conditionCache[0] = ConditionState::kNotEvaluated;
692 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
693
694 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
695
696 // stop all event
697 LogEvent event3(/*uid=*/0, /*pid=*/0);
698 makeWakeLockEvent(&event3, /*atomId=*/1, /*timestamp=*/0, uids2, "wl2", /*acquire=*/1);
699
700 matcherState.clear();
701 matcherState.push_back(MatchingState::kNotMatched);
702 matcherState.push_back(MatchingState::kNotMatched);
703 matcherState.push_back(MatchingState::kMatched);
704
705 conditionCache[0] = ConditionState::kNotEvaluated;
706 changedCache[0] = false;
707 conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
708 changedCache);
709 EXPECT_TRUE(changedCache[0]);
710 ASSERT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
711 {
712 if (position == Position::FIRST || position == Position::LAST) {
713 ASSERT_EQ(2UL, conditionTracker.getChangedToFalseDimensions(allConditions)->size());
714 EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
715 } else {
716 EXPECT_EQ(uids1.size() + uids2.size(),
717 conditionTracker.getChangedToFalseDimensions(allConditions)->size());
718 EXPECT_TRUE(conditionTracker.getChangedToTrueDimensions(allConditions)->empty());
719 }
720 }
721
722 // TEST QUERY
723 const auto queryKey3 = getWakeLockQueryKey(position, uids1, conditionName);
724 conditionCache[0] = ConditionState::kNotEvaluated;
725 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
726 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
727
728 // TEST QUERY
729 const auto queryKey4 = getWakeLockQueryKey(position, uids2, conditionName);
730 conditionCache[0] = ConditionState::kNotEvaluated;
731 conditionTracker.isConditionMet(queryKey, allPredicates, false, conditionCache);
732 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
733 }
734 }
735
736 } // namespace statsd
737 } // namespace os
738 } // namespace android
739 #else
740 GTEST_LOG_(INFO) << "This test does nothing.\n";
741 #endif
742