blob: e0aac1137c4cacb53536a4788d36035064705eea [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) {
Yao Chen80235402017-11-13 20:42:25 -080049 event->write(uid); // uid
50 event->write(wl);
51 event->write(acquire);
Yao Chen967b2052017-11-07 16:36:43 -080052 event->init();
53}
54
55map<string, HashableDimensionKey> getWakeLockQueryKey(int key, int uid,
56 const string& conditionName) {
57 // test query
58 KeyValuePair kv1;
59 kv1.set_key(key);
60 kv1.set_value_int(uid);
61 vector<KeyValuePair> kv_list;
62 kv_list.push_back(kv1);
63 map<string, HashableDimensionKey> queryKey;
64 queryKey[conditionName] = getHashableKey(kv_list);
65 return queryKey;
66}
67
68TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
69 SimpleCondition simpleCondition;
70 simpleCondition.set_start("SCREEN_TURNED_ON");
71 simpleCondition.set_stop("SCREEN_TURNED_OFF");
72 simpleCondition.set_count_nesting(false);
Yao Chena81a0ffa2017-11-16 10:10:30 -080073 simpleCondition.set_initial_value(SimpleCondition_InitialValue_UNKNOWN);
Yao Chen967b2052017-11-07 16:36:43 -080074
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);
Yao Chen99752052017-11-27 11:40:45 -0800241 matcherState.push_back(MatchingState::kNotMatched);
Yao Chen967b2052017-11-07 16:36:43 -0800242 vector<sp<ConditionTracker>> allConditions;
243 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
244 vector<bool> changedCache(1, false);
245
246 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
247 changedCache);
248
249 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
250 EXPECT_TRUE(changedCache[0]);
251
252 // Now test query
253 const auto queryKey = getWakeLockQueryKey(1, uid, conditionName);
254 conditionCache[0] = ConditionState::kNotEvaluated;
255
256 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
257 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
258
259 // another wake lock acquired by this uid
260 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
261 makeWakeLockEvent(&event2, uid, "wl2", 1);
262 matcherState.clear();
263 matcherState.push_back(MatchingState::kMatched);
264 matcherState.push_back(MatchingState::kNotMatched);
265 conditionCache[0] = ConditionState::kNotEvaluated;
266 changedCache[0] = false;
267 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
268 changedCache);
269 EXPECT_FALSE(changedCache[0]);
270
271 // wake lock 1 release
272 LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
273 makeWakeLockEvent(&event3, uid, "wl1", 0); // now release it.
274 matcherState.clear();
275 matcherState.push_back(MatchingState::kNotMatched);
276 matcherState.push_back(MatchingState::kMatched);
277 conditionCache[0] = ConditionState::kNotEvaluated;
278 changedCache[0] = false;
279 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
280 changedCache);
281 // nothing changes, because wake lock 2 is still held for this uid
282 EXPECT_FALSE(changedCache[0]);
283
284 LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
285 makeWakeLockEvent(&event4, uid, "wl2", 0); // now release it.
286 matcherState.clear();
287 matcherState.push_back(MatchingState::kNotMatched);
288 matcherState.push_back(MatchingState::kMatched);
289 conditionCache[0] = ConditionState::kNotEvaluated;
290 changedCache[0] = false;
291 conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
292 changedCache);
293 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
294 EXPECT_TRUE(changedCache[0]);
295
296 // query again
297 conditionCache[0] = ConditionState::kNotEvaluated;
298 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
299 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
300}
301
302TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
303 SimpleCondition simpleCondition = getWakeLockHeldCondition(
304 true /*nesting*/, true /*default to false*/, false /*slice output by uid*/);
305 string conditionName = "WL_HELD";
306
307 unordered_map<string, int> trackerNameIndexMap;
308 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
309 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
310 trackerNameIndexMap["RELEASE_ALL"] = 2;
311
312 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
313 simpleCondition, trackerNameIndexMap);
314 int uid1 = 111;
315 string uid1_wl1 = "wl1_1";
316 int uid2 = 222;
317 string uid2_wl1 = "wl2_1";
318
319 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
320 makeWakeLockEvent(&event, uid1, uid1_wl1, 1);
321
322 // one matched start for uid1
323 vector<MatchingState> matcherState;
324 matcherState.push_back(MatchingState::kMatched);
325 matcherState.push_back(MatchingState::kNotMatched);
Yao Chen99752052017-11-27 11:40:45 -0800326 matcherState.push_back(MatchingState::kNotMatched);
Yao Chen967b2052017-11-07 16:36:43 -0800327 vector<sp<ConditionTracker>> allConditions;
328 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
329 vector<bool> changedCache(1, false);
330
331 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
332 changedCache);
333
334 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
335 EXPECT_TRUE(changedCache[0]);
336
337 // Now test query
338 map<string, HashableDimensionKey> queryKey;
339 conditionCache[0] = ConditionState::kNotEvaluated;
340
341 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
342 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
343
344 // another wake lock acquired by this uid
345 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
346 makeWakeLockEvent(&event2, uid2, uid2_wl1, 1);
347 matcherState.clear();
348 matcherState.push_back(MatchingState::kMatched);
349 matcherState.push_back(MatchingState::kNotMatched);
350 conditionCache[0] = ConditionState::kNotEvaluated;
351 changedCache[0] = false;
352 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
353 changedCache);
354 EXPECT_FALSE(changedCache[0]);
355
356 // uid1 wake lock 1 release
357 LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
358 makeWakeLockEvent(&event3, uid1, uid1_wl1, 0); // now release it.
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 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
365 changedCache);
366 // nothing changes, because uid2 is still holding wl.
367 EXPECT_FALSE(changedCache[0]);
368
369 LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
370 makeWakeLockEvent(&event4, uid2, uid2_wl1, 0); // now release it.
371 matcherState.clear();
372 matcherState.push_back(MatchingState::kNotMatched);
373 matcherState.push_back(MatchingState::kMatched);
374 conditionCache[0] = ConditionState::kNotEvaluated;
375 changedCache[0] = false;
376 conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
377 changedCache);
378 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
379 EXPECT_TRUE(changedCache[0]);
380
381 // query again
382 conditionCache[0] = ConditionState::kNotEvaluated;
383 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
384 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
385}
386
387TEST(SimpleConditionTrackerTest, TestStopAll) {
388 SimpleCondition simpleCondition = getWakeLockHeldCondition(
389 true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
390 string conditionName = "WL_HELD_BY_UID3";
391
392 unordered_map<string, int> trackerNameIndexMap;
393 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
394 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
395 trackerNameIndexMap["RELEASE_ALL"] = 2;
396
397 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
398 simpleCondition, trackerNameIndexMap);
399 int uid1 = 111;
400 int uid2 = 222;
401
402 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
403 makeWakeLockEvent(&event, uid1, "wl1", 1);
404
405 // one matched start
406 vector<MatchingState> matcherState;
407 matcherState.push_back(MatchingState::kMatched);
408 matcherState.push_back(MatchingState::kNotMatched);
409 matcherState.push_back(MatchingState::kNotMatched);
410 vector<sp<ConditionTracker>> allConditions;
411 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
412 vector<bool> changedCache(1, false);
413
414 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
415 changedCache);
416
417 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
418 EXPECT_TRUE(changedCache[0]);
419
420 // Now test query
421 const auto queryKey = getWakeLockQueryKey(1, uid1, conditionName);
422 conditionCache[0] = ConditionState::kNotEvaluated;
423
424 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
425 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
426
427 // another wake lock acquired by uid2
428 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
429 makeWakeLockEvent(&event2, uid2, "wl2", 1);
430 matcherState.clear();
431 matcherState.push_back(MatchingState::kMatched);
432 matcherState.push_back(MatchingState::kNotMatched);
433 matcherState.push_back(MatchingState::kNotMatched);
434 conditionCache[0] = ConditionState::kNotEvaluated;
435 changedCache[0] = false;
436 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
437 changedCache);
438 EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
439 EXPECT_TRUE(changedCache[0]);
440
441 // TEST QUERY
442 const auto queryKey2 = getWakeLockQueryKey(1, uid2, conditionName);
443 conditionCache[0] = ConditionState::kNotEvaluated;
444
445 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
446 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
447
448
449 // stop all event
450 LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
451 matcherState.clear();
452 matcherState.push_back(MatchingState::kNotMatched);
453 matcherState.push_back(MatchingState::kNotMatched);
454 matcherState.push_back(MatchingState::kMatched);
455
456 conditionCache[0] = ConditionState::kNotEvaluated;
457 changedCache[0] = false;
458 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
459 changedCache);
460 EXPECT_TRUE(changedCache[0]);
461 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
462
463 // TEST QUERY
464 const auto queryKey3 = getWakeLockQueryKey(1, uid1, conditionName);
465 conditionCache[0] = ConditionState::kNotEvaluated;
466
467 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
468 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
469
470 // TEST QUERY
471 const auto queryKey4 = getWakeLockQueryKey(1, uid2, conditionName);
472 conditionCache[0] = ConditionState::kNotEvaluated;
473
474 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
475 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
476}
477
478} // namespace statsd
479} // namespace os
480} // namespace android
481#else
482GTEST_LOG_(INFO) << "This test does nothing.\n";
483#endif