blob: c89ffea857091aac5859276f898ec9cb26dbd619 [file] [log] [blame]
tsaichristine10978642019-09-10 14:12:49 -07001/*
2 * Copyright (C) 2019, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <gtest/gtest.h>
17#include "state/StateManager.h"
18#include "state/StateTracker.h"
19#include "state/StateListener.h"
20
21#include "tests/statsd_test_util.h"
22
23#ifdef __ANDROID__
24
25namespace android {
26namespace os {
27namespace statsd {
28
29/**
30 * Mock StateListener class for testing.
31 * Stores primary key and state pairs.
32 */
33class TestStateListener : public virtual StateListener {
34public:
35 TestStateListener(){};
36
37 virtual ~TestStateListener(){};
38
39 struct Update {
40 Update(const HashableDimensionKey& key, int state) : mKey(key), mState(state){};
41 HashableDimensionKey mKey;
42 int mState;
43 };
44
45 std::vector<Update> updates;
46
47 void onStateChanged(int stateAtomId, const HashableDimensionKey& primaryKey, int oldState,
48 int newState) {
49 updates.emplace_back(primaryKey, newState);
50 }
51};
52
53// START: build event functions.
54// State with no primary fields - ScreenStateChanged
55std::shared_ptr<LogEvent> buildScreenEvent(int state) {
56 std::shared_ptr<LogEvent> event =
57 std::make_shared<LogEvent>(android::util::SCREEN_STATE_CHANGED, 1000 /*timestamp*/);
58 event->write((int32_t)state);
59 event->init();
60 return event;
61}
62
63// State with one primary field - UidProcessStateChanged
64std::shared_ptr<LogEvent> buildUidProcessEvent(int uid, int state) {
65 std::shared_ptr<LogEvent> event =
66 std::make_shared<LogEvent>(android::util::UID_PROCESS_STATE_CHANGED, 1000 /*timestamp*/);
67 event->write((int32_t)uid);
68 event->write((int32_t)state);
69 event->init();
70 return event;
71}
72
73// State with multiple primary fields - OverlayStateChanged
74std::shared_ptr<LogEvent> buildOverlayEvent(int uid, const std::string& packageName, int state) {
75 std::shared_ptr<LogEvent> event =
76 std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
77 event->write((int32_t)uid);
78 event->write(packageName);
79 event->write(true); // using_alert_window
80 event->write((int32_t)state);
81 event->init();
82 return event;
83}
84
85std::shared_ptr<LogEvent> buildIncorrectOverlayEvent(int uid, const std::string& packageName, int state) {
86 std::shared_ptr<LogEvent> event =
87 std::make_shared<LogEvent>(android::util::OVERLAY_STATE_CHANGED, 1000 /*timestamp*/);
88 event->write((int32_t)uid);
89 event->write(packageName);
90 event->write((int32_t)state);
91 event->init();
92 return event;
93}
94// END: build event functions.
95
96// START: get primary key functions
97void getUidProcessKey(int uid, HashableDimensionKey* key) {
98 int pos1[] = {1, 0, 0};
99 Field field1(27 /* atom id */, pos1, 0 /* depth */);
100 Value value1((int32_t)uid);
101
102 key->addValue(FieldValue(field1, value1));
103}
104
105void getOverlayKey(int uid, string packageName, HashableDimensionKey* key) {
106 int pos1[] = {1, 0, 0};
107 int pos2[] = {2, 0, 0};
108
109 Field field1(59 /* atom id */, pos1, 0 /* depth */);
110 Field field2(59 /* atom id */, pos2, 0 /* depth */);
111
112 Value value1((int32_t)uid);
113 Value value2(packageName);
114
115 key->addValue(FieldValue(field1, value1));
116 key->addValue(FieldValue(field2, value2));
117}
118// END: get primary key functions
119
120TEST(StateListenerTest, TestStateListenerWeakPointer) {
121 sp<TestStateListener> listener = new TestStateListener();
122 wp<TestStateListener> wListener = listener;
123 listener = nullptr; // let go of listener
124 EXPECT_TRUE(wListener.promote() == nullptr);
125}
126
127TEST(StateManagerTest, TestStateManagerGetInstance) {
128 sp<TestStateListener> listener1 = new TestStateListener();
129 StateManager& mgr = StateManager::getInstance();
130
131 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
132 EXPECT_EQ(1, mgr.getStateTrackersCount());
133 EXPECT_EQ(1, StateManager::getInstance().getStateTrackersCount());
134}
135
136/**
137 * Test registering listeners to StateTrackers
138 *
139 * - StateManager will create a new StateTracker if it doesn't already exist
140 * and then register the listener to the StateTracker.
141 * - If a listener is already registered to a StateTracker, it is not added again.
142 * - StateTrackers are only created for atoms that are state atoms.
143 */
144TEST(StateTrackerTest, TestRegisterListener) {
145 sp<TestStateListener> listener1 = new TestStateListener();
146 sp<TestStateListener> listener2 = new TestStateListener();
147 StateManager mgr;
148
149 // Register listener to non-existing StateTracker
150 EXPECT_EQ(0, mgr.getStateTrackersCount());
151 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
152 EXPECT_EQ(1, mgr.getStateTrackersCount());
153 EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
154
155 // Register listener to existing StateTracker
156 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
157 EXPECT_EQ(1, mgr.getStateTrackersCount());
158 EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
159
160 // Register already registered listener to existing StateTracker
161 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
162 EXPECT_EQ(1, mgr.getStateTrackersCount());
163 EXPECT_EQ(2, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
164
165 // Register listener to non-state atom
166 mgr.registerListener(android::util::BATTERY_LEVEL_CHANGED, listener2);
167 EXPECT_EQ(1, mgr.getStateTrackersCount());
168}
169
170/**
171 * Test unregistering listeners from StateTrackers
172 *
173 * - StateManager will unregister listeners from a StateTracker only if the
174 * StateTracker exists and the listener is registered to the StateTracker.
175 * - Once all listeners are removed from a StateTracker, the StateTracker
176 * is also removed.
177 */
178TEST(StateTrackerTest, TestUnregisterListener) {
179 sp<TestStateListener> listener1 = new TestStateListener();
180 sp<TestStateListener> listener2 = new TestStateListener();
181 StateManager mgr;
182
183 // Unregister listener from non-existing StateTracker
184 EXPECT_EQ(0, mgr.getStateTrackersCount());
185 mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
186 EXPECT_EQ(0, mgr.getStateTrackersCount());
187 EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
188
189 // Unregister non-registered listener from existing StateTracker
190 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
191 EXPECT_EQ(1, mgr.getStateTrackersCount());
192 EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
193 mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
194 EXPECT_EQ(1, mgr.getStateTrackersCount());
195 EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
196
197 // Unregister second-to-last listener from StateTracker
198 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener2);
199 mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener1);
200 EXPECT_EQ(1, mgr.getStateTrackersCount());
201 EXPECT_EQ(1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
202
203 // Unregister last listener from StateTracker
204 mgr.unregisterListener(android::util::SCREEN_STATE_CHANGED, listener2);
205 EXPECT_EQ(0, mgr.getStateTrackersCount());
206 EXPECT_EQ(-1, mgr.getListenersCount(android::util::SCREEN_STATE_CHANGED));
207}
208
209/**
210 * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
211 * updates listener for states without primary keys.
212 */
213TEST(StateTrackerTest, TestStateChangeNoPrimaryFields) {
214 sp<TestStateListener> listener1 = new TestStateListener();
215 StateManager mgr;
216 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
217
218 // log event
219 std::shared_ptr<LogEvent> event =
220 buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON);
221 mgr.onLogEvent(*event);
222
223 // check listener was updated
224 EXPECT_EQ(1, listener1->updates.size());
225 EXPECT_EQ(DEFAULT_DIMENSION_KEY, listener1->updates[0].mKey);
226 EXPECT_EQ(2, listener1->updates[0].mState);
227
228 // check StateTracker was updated by querying for state
229 HashableDimensionKey queryKey = DEFAULT_DIMENSION_KEY;
230 EXPECT_EQ(2, mgr.getState(android::util::SCREEN_STATE_CHANGED, queryKey));
231}
232
233/**
234 * Test StateManager's onLogEvent and StateListener's onStateChanged correctly
235 * updates listener for states with primary keys.
236 */
237TEST(StateTrackerTest, TestStateChangeOnePrimaryField) {
238 sp<TestStateListener> listener1 = new TestStateListener();
239 StateManager mgr;
240 mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener1);
241
242 // log event
243 std::shared_ptr<LogEvent> event = buildUidProcessEvent(
244 1000,
245 android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
246 mgr.onLogEvent(*event);
247
248 // check listener was updated
249 EXPECT_EQ(1, listener1->updates.size());
250 EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
251 EXPECT_EQ(1002, listener1->updates[0].mState);
252
253 // check StateTracker was updated by querying for state
254 HashableDimensionKey queryKey;
255 getUidProcessKey(1000, &queryKey);
256 EXPECT_EQ(1002, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey));
257}
258
259TEST(StateTrackerTest, TestStateChangeMultiplePrimaryFields) {
260 sp<TestStateListener> listener1 = new TestStateListener();
261 StateManager mgr;
262 mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
263
264 // log event
265 std::shared_ptr<LogEvent> event = buildOverlayEvent(1000, "package1", 1); // state: ENTERED
266 mgr.onLogEvent(*event);
267
268 // check listener update
269 EXPECT_EQ(1, listener1->updates.size());
270 EXPECT_EQ(1000, listener1->updates[0].mKey.getValues()[0].mValue.int_value);
271 EXPECT_EQ(1, listener1->updates[0].mState);
272}
273
274/**
275 * Test StateManager's onLogEvent and StateListener's onStateChanged
276 * when there is an error extracting state from log event. Listener is not
277 * updated of state change.
278 */
279TEST(StateTrackerTest, TestStateChangeEventError) {
280 sp<TestStateListener> listener1 = new TestStateListener();
281 StateManager mgr;
282 mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener1);
283
284 // log event
285 std::shared_ptr<LogEvent> event =
286 buildIncorrectOverlayEvent(1000, "package1", 1); // state: ENTERED
287 mgr.onLogEvent(*event);
288
289 // check listener update
290 EXPECT_EQ(0, listener1->updates.size());
291}
292
293TEST(StateTrackerTest, TestStateQuery) {
294 sp<TestStateListener> listener1 = new TestStateListener();
295 sp<TestStateListener> listener2 = new TestStateListener();
296 sp<TestStateListener> listener3 = new TestStateListener();
297 StateManager mgr;
298 mgr.registerListener(android::util::SCREEN_STATE_CHANGED, listener1);
299 mgr.registerListener(android::util::UID_PROCESS_STATE_CHANGED, listener2);
300 mgr.registerListener(android::util::OVERLAY_STATE_CHANGED, listener3);
301
302 std::shared_ptr<LogEvent> event1 = buildUidProcessEvent(
303 1000,
304 android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
305 std::shared_ptr<LogEvent> event2 = buildUidProcessEvent(
306 1001,
307 android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE); // state value: 1003
308 std::shared_ptr<LogEvent> event3 = buildUidProcessEvent(
309 1002,
310 android::app::ProcessStateEnum::PROCESS_STATE_PERSISTENT); // state value: 1000
311 std::shared_ptr<LogEvent> event4 = buildUidProcessEvent(
312 1001,
313 android::app::ProcessStateEnum::PROCESS_STATE_TOP); // state value: 1002
314 std::shared_ptr<LogEvent> event5 =
315 buildScreenEvent(android::view::DisplayStateEnum::DISPLAY_STATE_ON); // state value:
316 std::shared_ptr<LogEvent> event6 = buildOverlayEvent(1000, "package1", 1);
317 std::shared_ptr<LogEvent> event7 = buildOverlayEvent(1000, "package2", 2);
318
319 mgr.onLogEvent(*event1);
320 mgr.onLogEvent(*event2);
321 mgr.onLogEvent(*event3);
322 mgr.onLogEvent(*event5);
323 mgr.onLogEvent(*event5);
324 mgr.onLogEvent(*event6);
325 mgr.onLogEvent(*event7);
326
327 // Query for UidProcessState of uid 1001
328 HashableDimensionKey queryKey1;
329 getUidProcessKey(1001, &queryKey1);
330 EXPECT_EQ(1003, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
331
332 // Query for UidProcessState of uid 1004 - not in state map
333 HashableDimensionKey queryKey2;
334 getUidProcessKey(1004, &queryKey2);
335 EXPECT_EQ(-1,
336 mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey2)); // default state
337
338 // Query for UidProcessState of uid 1001 - after change in state
339 mgr.onLogEvent(*event4);
340 EXPECT_EQ(1002, mgr.getState(android::util::UID_PROCESS_STATE_CHANGED, queryKey1));
341
342 // Query for ScreenState
343 EXPECT_EQ(2, mgr.getState(android::util::SCREEN_STATE_CHANGED, DEFAULT_DIMENSION_KEY));
344
345 // Query for OverlayState of uid 1000, package name "package2"
346 HashableDimensionKey queryKey3;
347 getOverlayKey(1000, "package2", &queryKey3);
348 EXPECT_EQ(2, mgr.getState(android::util::OVERLAY_STATE_CHANGED, queryKey3));
349}
350
351} // namespace statsd
352} // namespace os
353} // namespace android
354#else
355GTEST_LOG_(INFO) << "This test does nothing.\n";
356#endif