blob: 855e66615f8e3d72cb998a41bdbe459761425bcd [file] [log] [blame]
Yao Chen967b2052017-11-07 16:36:43 -08001// 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#include "src/condition/SimpleConditionTracker.h"
15
16#include <gmock/gmock.h>
17#include <gtest/gtest.h>
18#include <stdio.h>
19#include <vector>
20
21using std::map;
22using std::unordered_map;
23using std::vector;
24
25#ifdef __ANDROID__
26
27namespace android {
28namespace os {
29namespace statsd {
30
31SimpleCondition getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
32 bool outputSlicedUid) {
33 SimpleCondition simpleCondition;
34 simpleCondition.set_start("WAKE_LOCK_ACQUIRE");
35 simpleCondition.set_stop("WAKE_LOCK_RELEASE");
36 simpleCondition.set_stop_all("RELEASE_ALL");
37 if (outputSlicedUid) {
38 KeyMatcher* keyMatcher = simpleCondition.add_dimension();
39 keyMatcher->set_key(1);
40 }
41
42 simpleCondition.set_count_nesting(countNesting);
43 simpleCondition.set_initial_value(defaultFalse ? SimpleCondition_InitialValue_FALSE
44 : SimpleCondition_InitialValue_UNKNOWN);
45 return simpleCondition;
46}
47
48void makeWakeLockEvent(LogEvent* event, int uid, const string& wl, int acquire) {
49 auto list = event->GetAndroidLogEventList();
50 *list << uid; // uid
51 *list << wl;
52 *list << acquire;
53 event->init();
54}
55
56map<string, HashableDimensionKey> getWakeLockQueryKey(int key, int uid,
57 const string& conditionName) {
58 // test query
59 KeyValuePair kv1;
60 kv1.set_key(key);
61 kv1.set_value_int(uid);
62 vector<KeyValuePair> kv_list;
63 kv_list.push_back(kv1);
64 map<string, HashableDimensionKey> queryKey;
65 queryKey[conditionName] = getHashableKey(kv_list);
66 return queryKey;
67}
68
69TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
70 SimpleCondition simpleCondition;
71 simpleCondition.set_start("SCREEN_TURNED_ON");
72 simpleCondition.set_stop("SCREEN_TURNED_OFF");
73 simpleCondition.set_count_nesting(false);
74
75 unordered_map<string, int> trackerNameIndexMap;
76 trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
77 trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
78
79 SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*tracker index*/, simpleCondition,
80 trackerNameIndexMap);
81
82 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
83
84 vector<MatchingState> matcherState;
85 matcherState.push_back(MatchingState::kNotMatched);
86 matcherState.push_back(MatchingState::kNotMatched);
87
88 vector<sp<ConditionTracker>> allConditions;
89 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
90 vector<bool> changedCache(1, false);
91
92 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
93 changedCache);
94 // not matched start or stop. condition doesn't change
95 EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
96 EXPECT_FALSE(changedCache[0]);
97
98 // prepare a case for match start.
99 matcherState.clear();
100 matcherState.push_back(MatchingState::kMatched);
101 matcherState.push_back(MatchingState::kNotMatched);
102 conditionCache[0] = ConditionState::kNotEvaluated;
103 changedCache[0] = false;
104
105 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
106 changedCache);
107 // now condition should change to true.
108 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
109 EXPECT_TRUE(changedCache[0]);
110
Yao Chend41c4222017-11-15 19:26:14 -0800111 // match nothing.
112 matcherState.clear();
113 matcherState.push_back(MatchingState::kNotMatched);
114 matcherState.push_back(MatchingState::kNotMatched);
115 conditionCache[0] = ConditionState::kNotEvaluated;
116 changedCache[0] = false;
117
118 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
119 changedCache);
120 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
121 EXPECT_FALSE(changedCache[0]);
122
Yao Chen967b2052017-11-07 16:36:43 -0800123 // the case for match stop.
124 matcherState.clear();
125 matcherState.push_back(MatchingState::kNotMatched);
126 matcherState.push_back(MatchingState::kMatched);
127 conditionCache[0] = ConditionState::kNotEvaluated;
128 changedCache[0] = false;
129
130 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
131 changedCache);
132
133 // condition changes to false.
134 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
135 EXPECT_TRUE(changedCache[0]);
136
137 // match stop again.
138 matcherState.clear();
139 matcherState.push_back(MatchingState::kNotMatched);
140 matcherState.push_back(MatchingState::kMatched);
141 conditionCache[0] = ConditionState::kNotEvaluated;
142 changedCache[0] = false;
143
144 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
145 changedCache);
146 // condition should still be false. not changed.
147 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
148 EXPECT_FALSE(changedCache[0]);
149}
150
151TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
152 SimpleCondition simpleCondition;
153 simpleCondition.set_start("SCREEN_TURNED_ON");
154 simpleCondition.set_stop("SCREEN_TURNED_OFF");
155 simpleCondition.set_count_nesting(true);
156
157 unordered_map<string, int> trackerNameIndexMap;
158 trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
159 trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
160
161 SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*condition tracker index*/,
162 simpleCondition, trackerNameIndexMap);
163
164 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
165
166 // one matched start
167 vector<MatchingState> matcherState;
168 matcherState.push_back(MatchingState::kMatched);
169 matcherState.push_back(MatchingState::kNotMatched);
170 vector<sp<ConditionTracker>> allConditions;
171 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
172 vector<bool> changedCache(1, false);
173
174 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
175 changedCache);
176
177 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
178 EXPECT_TRUE(changedCache[0]);
179
180 // prepare for another matched start.
181 matcherState.clear();
182 matcherState.push_back(MatchingState::kMatched);
183 matcherState.push_back(MatchingState::kNotMatched);
184 conditionCache[0] = ConditionState::kNotEvaluated;
185 changedCache[0] = false;
186
187 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
188 changedCache);
189
190 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
191 EXPECT_FALSE(changedCache[0]);
192
193 // ONE MATCHED STOP
194 matcherState.clear();
195 matcherState.push_back(MatchingState::kNotMatched);
196 matcherState.push_back(MatchingState::kMatched);
197 conditionCache[0] = ConditionState::kNotEvaluated;
198 changedCache[0] = false;
199
200 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
201 changedCache);
202 // result should still be true
203 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
204 EXPECT_FALSE(changedCache[0]);
205
206 // ANOTHER MATCHED STOP
207 matcherState.clear();
208 matcherState.push_back(MatchingState::kNotMatched);
209 matcherState.push_back(MatchingState::kMatched);
210 conditionCache[0] = ConditionState::kNotEvaluated;
211 changedCache[0] = false;
212
213 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
214 changedCache);
215 // result should still be true
216 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
217 EXPECT_TRUE(changedCache[0]);
218}
219
220TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
221 SimpleCondition simpleCondition = getWakeLockHeldCondition(
222 true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
223 string conditionName = "WL_HELD_BY_UID2";
224
225 unordered_map<string, int> trackerNameIndexMap;
226 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
227 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
228 trackerNameIndexMap["RELEASE_ALL"] = 2;
229
230 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
231 simpleCondition, trackerNameIndexMap);
232 int uid = 111;
233
234 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
235 makeWakeLockEvent(&event, uid, "wl1", 1);
236
237 // one matched start
238 vector<MatchingState> matcherState;
239 matcherState.push_back(MatchingState::kMatched);
240 matcherState.push_back(MatchingState::kNotMatched);
241 vector<sp<ConditionTracker>> allConditions;
242 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
243 vector<bool> changedCache(1, false);
244
245 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
246 changedCache);
247
248 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
249 EXPECT_TRUE(changedCache[0]);
250
251 // Now test query
252 const auto queryKey = getWakeLockQueryKey(1, uid, conditionName);
253 conditionCache[0] = ConditionState::kNotEvaluated;
254
255 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
256 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
257
258 // another wake lock acquired by this uid
259 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
260 makeWakeLockEvent(&event2, uid, "wl2", 1);
261 matcherState.clear();
262 matcherState.push_back(MatchingState::kMatched);
263 matcherState.push_back(MatchingState::kNotMatched);
264 conditionCache[0] = ConditionState::kNotEvaluated;
265 changedCache[0] = false;
266 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
267 changedCache);
268 EXPECT_FALSE(changedCache[0]);
269
270 // wake lock 1 release
271 LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
272 makeWakeLockEvent(&event3, uid, "wl1", 0); // now release it.
273 matcherState.clear();
274 matcherState.push_back(MatchingState::kNotMatched);
275 matcherState.push_back(MatchingState::kMatched);
276 conditionCache[0] = ConditionState::kNotEvaluated;
277 changedCache[0] = false;
278 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
279 changedCache);
280 // nothing changes, because wake lock 2 is still held for this uid
281 EXPECT_FALSE(changedCache[0]);
282
283 LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
284 makeWakeLockEvent(&event4, uid, "wl2", 0); // now release it.
285 matcherState.clear();
286 matcherState.push_back(MatchingState::kNotMatched);
287 matcherState.push_back(MatchingState::kMatched);
288 conditionCache[0] = ConditionState::kNotEvaluated;
289 changedCache[0] = false;
290 conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
291 changedCache);
292 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
293 EXPECT_TRUE(changedCache[0]);
294
295 // query again
296 conditionCache[0] = ConditionState::kNotEvaluated;
297 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
298 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
299}
300
301TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
302 SimpleCondition simpleCondition = getWakeLockHeldCondition(
303 true /*nesting*/, true /*default to false*/, false /*slice output by uid*/);
304 string conditionName = "WL_HELD";
305
306 unordered_map<string, int> trackerNameIndexMap;
307 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
308 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
309 trackerNameIndexMap["RELEASE_ALL"] = 2;
310
311 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
312 simpleCondition, trackerNameIndexMap);
313 int uid1 = 111;
314 string uid1_wl1 = "wl1_1";
315 int uid2 = 222;
316 string uid2_wl1 = "wl2_1";
317
318 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
319 makeWakeLockEvent(&event, uid1, uid1_wl1, 1);
320
321 // one matched start for uid1
322 vector<MatchingState> matcherState;
323 matcherState.push_back(MatchingState::kMatched);
324 matcherState.push_back(MatchingState::kNotMatched);
325 vector<sp<ConditionTracker>> allConditions;
326 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
327 vector<bool> changedCache(1, false);
328
329 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
330 changedCache);
331
332 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
333 EXPECT_TRUE(changedCache[0]);
334
335 // Now test query
336 map<string, HashableDimensionKey> queryKey;
337 conditionCache[0] = ConditionState::kNotEvaluated;
338
339 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
340 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
341
342 // another wake lock acquired by this uid
343 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
344 makeWakeLockEvent(&event2, uid2, uid2_wl1, 1);
345 matcherState.clear();
346 matcherState.push_back(MatchingState::kMatched);
347 matcherState.push_back(MatchingState::kNotMatched);
348 conditionCache[0] = ConditionState::kNotEvaluated;
349 changedCache[0] = false;
350 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
351 changedCache);
352 EXPECT_FALSE(changedCache[0]);
353
354 // uid1 wake lock 1 release
355 LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
356 makeWakeLockEvent(&event3, uid1, uid1_wl1, 0); // now release it.
357 matcherState.clear();
358 matcherState.push_back(MatchingState::kNotMatched);
359 matcherState.push_back(MatchingState::kMatched);
360 conditionCache[0] = ConditionState::kNotEvaluated;
361 changedCache[0] = false;
362 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
363 changedCache);
364 // nothing changes, because uid2 is still holding wl.
365 EXPECT_FALSE(changedCache[0]);
366
367 LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
368 makeWakeLockEvent(&event4, uid2, uid2_wl1, 0); // now release it.
369 matcherState.clear();
370 matcherState.push_back(MatchingState::kNotMatched);
371 matcherState.push_back(MatchingState::kMatched);
372 conditionCache[0] = ConditionState::kNotEvaluated;
373 changedCache[0] = false;
374 conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
375 changedCache);
376 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
377 EXPECT_TRUE(changedCache[0]);
378
379 // query again
380 conditionCache[0] = ConditionState::kNotEvaluated;
381 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
382 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
383}
384
385TEST(SimpleConditionTrackerTest, TestStopAll) {
386 SimpleCondition simpleCondition = getWakeLockHeldCondition(
387 true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
388 string conditionName = "WL_HELD_BY_UID3";
389
390 unordered_map<string, int> trackerNameIndexMap;
391 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
392 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
393 trackerNameIndexMap["RELEASE_ALL"] = 2;
394
395 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
396 simpleCondition, trackerNameIndexMap);
397 int uid1 = 111;
398 int uid2 = 222;
399
400 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
401 makeWakeLockEvent(&event, uid1, "wl1", 1);
402
403 // one matched start
404 vector<MatchingState> matcherState;
405 matcherState.push_back(MatchingState::kMatched);
406 matcherState.push_back(MatchingState::kNotMatched);
407 matcherState.push_back(MatchingState::kNotMatched);
408 vector<sp<ConditionTracker>> allConditions;
409 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
410 vector<bool> changedCache(1, false);
411
412 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
413 changedCache);
414
415 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
416 EXPECT_TRUE(changedCache[0]);
417
418 // Now test query
419 const auto queryKey = getWakeLockQueryKey(1, uid1, conditionName);
420 conditionCache[0] = ConditionState::kNotEvaluated;
421
422 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
423 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
424
425 // another wake lock acquired by uid2
426 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
427 makeWakeLockEvent(&event2, uid2, "wl2", 1);
428 matcherState.clear();
429 matcherState.push_back(MatchingState::kMatched);
430 matcherState.push_back(MatchingState::kNotMatched);
431 matcherState.push_back(MatchingState::kNotMatched);
432 conditionCache[0] = ConditionState::kNotEvaluated;
433 changedCache[0] = false;
434 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
435 changedCache);
436 EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
437 EXPECT_TRUE(changedCache[0]);
438
439 // TEST QUERY
440 const auto queryKey2 = getWakeLockQueryKey(1, uid2, conditionName);
441 conditionCache[0] = ConditionState::kNotEvaluated;
442
443 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
444 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
445
446
447 // stop all event
448 LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
449 matcherState.clear();
450 matcherState.push_back(MatchingState::kNotMatched);
451 matcherState.push_back(MatchingState::kNotMatched);
452 matcherState.push_back(MatchingState::kMatched);
453
454 conditionCache[0] = ConditionState::kNotEvaluated;
455 changedCache[0] = false;
456 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
457 changedCache);
458 EXPECT_TRUE(changedCache[0]);
459 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
460
461 // TEST QUERY
462 const auto queryKey3 = getWakeLockQueryKey(1, uid1, conditionName);
463 conditionCache[0] = ConditionState::kNotEvaluated;
464
465 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
466 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
467
468 // TEST QUERY
469 const auto queryKey4 = getWakeLockQueryKey(1, uid2, conditionName);
470 conditionCache[0] = ConditionState::kNotEvaluated;
471
472 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
473 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
474}
475
476} // namespace statsd
477} // namespace os
478} // namespace android
479#else
480GTEST_LOG_(INFO) << "This test does nothing.\n";
481#endif