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