blob: 05aad290e3feb22292dbabbe7b2f18e31a7743ca [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
111 // the case for match stop.
112 matcherState.clear();
113 matcherState.push_back(MatchingState::kNotMatched);
114 matcherState.push_back(MatchingState::kMatched);
115 conditionCache[0] = ConditionState::kNotEvaluated;
116 changedCache[0] = false;
117
118 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
119 changedCache);
120
121 // condition changes to false.
122 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
123 EXPECT_TRUE(changedCache[0]);
124
125 // match stop again.
126 matcherState.clear();
127 matcherState.push_back(MatchingState::kNotMatched);
128 matcherState.push_back(MatchingState::kMatched);
129 conditionCache[0] = ConditionState::kNotEvaluated;
130 changedCache[0] = false;
131
132 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
133 changedCache);
134 // condition should still be false. not changed.
135 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
136 EXPECT_FALSE(changedCache[0]);
137}
138
139TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
140 SimpleCondition simpleCondition;
141 simpleCondition.set_start("SCREEN_TURNED_ON");
142 simpleCondition.set_stop("SCREEN_TURNED_OFF");
143 simpleCondition.set_count_nesting(true);
144
145 unordered_map<string, int> trackerNameIndexMap;
146 trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
147 trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
148
149 SimpleConditionTracker conditionTracker("SCREEN_IS_ON", 0 /*condition tracker index*/,
150 simpleCondition, trackerNameIndexMap);
151
152 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
153
154 // one matched start
155 vector<MatchingState> matcherState;
156 matcherState.push_back(MatchingState::kMatched);
157 matcherState.push_back(MatchingState::kNotMatched);
158 vector<sp<ConditionTracker>> allConditions;
159 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
160 vector<bool> changedCache(1, false);
161
162 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
163 changedCache);
164
165 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
166 EXPECT_TRUE(changedCache[0]);
167
168 // prepare for another matched start.
169 matcherState.clear();
170 matcherState.push_back(MatchingState::kMatched);
171 matcherState.push_back(MatchingState::kNotMatched);
172 conditionCache[0] = ConditionState::kNotEvaluated;
173 changedCache[0] = false;
174
175 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
176 changedCache);
177
178 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
179 EXPECT_FALSE(changedCache[0]);
180
181 // ONE MATCHED STOP
182 matcherState.clear();
183 matcherState.push_back(MatchingState::kNotMatched);
184 matcherState.push_back(MatchingState::kMatched);
185 conditionCache[0] = ConditionState::kNotEvaluated;
186 changedCache[0] = false;
187
188 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
189 changedCache);
190 // result should still be true
191 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
192 EXPECT_FALSE(changedCache[0]);
193
194 // ANOTHER MATCHED STOP
195 matcherState.clear();
196 matcherState.push_back(MatchingState::kNotMatched);
197 matcherState.push_back(MatchingState::kMatched);
198 conditionCache[0] = ConditionState::kNotEvaluated;
199 changedCache[0] = false;
200
201 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
202 changedCache);
203 // result should still be true
204 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
205 EXPECT_TRUE(changedCache[0]);
206}
207
208TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
209 SimpleCondition simpleCondition = getWakeLockHeldCondition(
210 true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
211 string conditionName = "WL_HELD_BY_UID2";
212
213 unordered_map<string, int> trackerNameIndexMap;
214 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
215 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
216 trackerNameIndexMap["RELEASE_ALL"] = 2;
217
218 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
219 simpleCondition, trackerNameIndexMap);
220 int uid = 111;
221
222 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
223 makeWakeLockEvent(&event, uid, "wl1", 1);
224
225 // one matched start
226 vector<MatchingState> matcherState;
227 matcherState.push_back(MatchingState::kMatched);
228 matcherState.push_back(MatchingState::kNotMatched);
229 vector<sp<ConditionTracker>> allConditions;
230 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
231 vector<bool> changedCache(1, false);
232
233 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
234 changedCache);
235
236 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
237 EXPECT_TRUE(changedCache[0]);
238
239 // Now test query
240 const auto queryKey = getWakeLockQueryKey(1, uid, conditionName);
241 conditionCache[0] = ConditionState::kNotEvaluated;
242
243 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
244 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
245
246 // another wake lock acquired by this uid
247 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
248 makeWakeLockEvent(&event2, uid, "wl2", 1);
249 matcherState.clear();
250 matcherState.push_back(MatchingState::kMatched);
251 matcherState.push_back(MatchingState::kNotMatched);
252 conditionCache[0] = ConditionState::kNotEvaluated;
253 changedCache[0] = false;
254 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
255 changedCache);
256 EXPECT_FALSE(changedCache[0]);
257
258 // wake lock 1 release
259 LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
260 makeWakeLockEvent(&event3, uid, "wl1", 0); // now release it.
261 matcherState.clear();
262 matcherState.push_back(MatchingState::kNotMatched);
263 matcherState.push_back(MatchingState::kMatched);
264 conditionCache[0] = ConditionState::kNotEvaluated;
265 changedCache[0] = false;
266 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
267 changedCache);
268 // nothing changes, because wake lock 2 is still held for this uid
269 EXPECT_FALSE(changedCache[0]);
270
271 LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
272 makeWakeLockEvent(&event4, uid, "wl2", 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(event4, matcherState, allConditions, conditionCache,
279 changedCache);
280 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
281 EXPECT_TRUE(changedCache[0]);
282
283 // query again
284 conditionCache[0] = ConditionState::kNotEvaluated;
285 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
286 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
287}
288
289TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
290 SimpleCondition simpleCondition = getWakeLockHeldCondition(
291 true /*nesting*/, true /*default to false*/, false /*slice output by uid*/);
292 string conditionName = "WL_HELD";
293
294 unordered_map<string, int> trackerNameIndexMap;
295 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
296 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
297 trackerNameIndexMap["RELEASE_ALL"] = 2;
298
299 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
300 simpleCondition, trackerNameIndexMap);
301 int uid1 = 111;
302 string uid1_wl1 = "wl1_1";
303 int uid2 = 222;
304 string uid2_wl1 = "wl2_1";
305
306 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
307 makeWakeLockEvent(&event, uid1, uid1_wl1, 1);
308
309 // one matched start for uid1
310 vector<MatchingState> matcherState;
311 matcherState.push_back(MatchingState::kMatched);
312 matcherState.push_back(MatchingState::kNotMatched);
313 vector<sp<ConditionTracker>> allConditions;
314 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
315 vector<bool> changedCache(1, false);
316
317 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
318 changedCache);
319
320 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
321 EXPECT_TRUE(changedCache[0]);
322
323 // Now test query
324 map<string, HashableDimensionKey> queryKey;
325 conditionCache[0] = ConditionState::kNotEvaluated;
326
327 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
328 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
329
330 // another wake lock acquired by this uid
331 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
332 makeWakeLockEvent(&event2, uid2, uid2_wl1, 1);
333 matcherState.clear();
334 matcherState.push_back(MatchingState::kMatched);
335 matcherState.push_back(MatchingState::kNotMatched);
336 conditionCache[0] = ConditionState::kNotEvaluated;
337 changedCache[0] = false;
338 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
339 changedCache);
340 EXPECT_FALSE(changedCache[0]);
341
342 // uid1 wake lock 1 release
343 LogEvent event3(1 /*tagId*/, 0 /*timestamp*/);
344 makeWakeLockEvent(&event3, uid1, uid1_wl1, 0); // now release it.
345 matcherState.clear();
346 matcherState.push_back(MatchingState::kNotMatched);
347 matcherState.push_back(MatchingState::kMatched);
348 conditionCache[0] = ConditionState::kNotEvaluated;
349 changedCache[0] = false;
350 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
351 changedCache);
352 // nothing changes, because uid2 is still holding wl.
353 EXPECT_FALSE(changedCache[0]);
354
355 LogEvent event4(1 /*tagId*/, 0 /*timestamp*/);
356 makeWakeLockEvent(&event4, uid2, uid2_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(event4, matcherState, allConditions, conditionCache,
363 changedCache);
364 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
365 EXPECT_TRUE(changedCache[0]);
366
367 // query again
368 conditionCache[0] = ConditionState::kNotEvaluated;
369 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
370 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
371}
372
373TEST(SimpleConditionTrackerTest, TestStopAll) {
374 SimpleCondition simpleCondition = getWakeLockHeldCondition(
375 true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
376 string conditionName = "WL_HELD_BY_UID3";
377
378 unordered_map<string, int> trackerNameIndexMap;
379 trackerNameIndexMap["WAKE_LOCK_ACQUIRE"] = 0;
380 trackerNameIndexMap["WAKE_LOCK_RELEASE"] = 1;
381 trackerNameIndexMap["RELEASE_ALL"] = 2;
382
383 SimpleConditionTracker conditionTracker(conditionName, 0 /*condition tracker index*/,
384 simpleCondition, trackerNameIndexMap);
385 int uid1 = 111;
386 int uid2 = 222;
387
388 LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
389 makeWakeLockEvent(&event, uid1, "wl1", 1);
390
391 // one matched start
392 vector<MatchingState> matcherState;
393 matcherState.push_back(MatchingState::kMatched);
394 matcherState.push_back(MatchingState::kNotMatched);
395 matcherState.push_back(MatchingState::kNotMatched);
396 vector<sp<ConditionTracker>> allConditions;
397 vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
398 vector<bool> changedCache(1, false);
399
400 conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
401 changedCache);
402
403 EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
404 EXPECT_TRUE(changedCache[0]);
405
406 // Now test query
407 const auto queryKey = getWakeLockQueryKey(1, uid1, conditionName);
408 conditionCache[0] = ConditionState::kNotEvaluated;
409
410 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
411 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
412
413 // another wake lock acquired by uid2
414 LogEvent event2(1 /*tagId*/, 0 /*timestamp*/);
415 makeWakeLockEvent(&event2, uid2, "wl2", 1);
416 matcherState.clear();
417 matcherState.push_back(MatchingState::kMatched);
418 matcherState.push_back(MatchingState::kNotMatched);
419 matcherState.push_back(MatchingState::kNotMatched);
420 conditionCache[0] = ConditionState::kNotEvaluated;
421 changedCache[0] = false;
422 conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
423 changedCache);
424 EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
425 EXPECT_TRUE(changedCache[0]);
426
427 // TEST QUERY
428 const auto queryKey2 = getWakeLockQueryKey(1, uid2, conditionName);
429 conditionCache[0] = ConditionState::kNotEvaluated;
430
431 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
432 EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
433
434
435 // stop all event
436 LogEvent event3(2 /*tagId*/, 0 /*timestamp*/);
437 matcherState.clear();
438 matcherState.push_back(MatchingState::kNotMatched);
439 matcherState.push_back(MatchingState::kNotMatched);
440 matcherState.push_back(MatchingState::kMatched);
441
442 conditionCache[0] = ConditionState::kNotEvaluated;
443 changedCache[0] = false;
444 conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
445 changedCache);
446 EXPECT_TRUE(changedCache[0]);
447 EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
448
449 // TEST QUERY
450 const auto queryKey3 = getWakeLockQueryKey(1, uid1, conditionName);
451 conditionCache[0] = ConditionState::kNotEvaluated;
452
453 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
454 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
455
456 // TEST QUERY
457 const auto queryKey4 = getWakeLockQueryKey(1, uid2, conditionName);
458 conditionCache[0] = ConditionState::kNotEvaluated;
459
460 conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
461 EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
462}
463
464} // namespace statsd
465} // namespace os
466} // namespace android
467#else
468GTEST_LOG_(INFO) << "This test does nothing.\n";
469#endif