AppTimeLimitControllerTests.java revision c870309921dab30893f26409625058f0eddf5a18
1/*
2 * Copyright (C) 2018 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
17package com.android.server.usage;
18
19import static org.junit.Assert.assertEquals;
20import static org.junit.Assert.assertFalse;
21import static org.junit.Assert.assertTrue;
22import static org.junit.Assert.fail;
23
24import android.app.PendingIntent;
25import android.os.HandlerThread;
26import android.os.Looper;
27import android.support.test.filters.MediumTest;
28import android.support.test.runner.AndroidJUnit4;
29
30import org.junit.After;
31import org.junit.Before;
32import org.junit.Test;
33import org.junit.runner.RunWith;
34
35import java.util.concurrent.CountDownLatch;
36import java.util.concurrent.TimeUnit;
37
38@RunWith(AndroidJUnit4.class)
39@MediumTest
40public class AppTimeLimitControllerTests {
41
42    private static final String PKG_SOC1 = "package.soc1";
43    private static final String PKG_SOC2 = "package.soc2";
44    private static final String PKG_GAME1 = "package.game1";
45    private static final String PKG_GAME2 = "package.game2";
46    private static final String PKG_PROD = "package.prod";
47
48    private static final int UID = 10100;
49    private static final int USER_ID = 10;
50    private static final int OBS_ID1 = 1;
51    private static final int OBS_ID2 = 2;
52    private static final int OBS_ID3 = 3;
53    private static final int OBS_ID4 = 4;
54    private static final int OBS_ID5 = 5;
55    private static final int OBS_ID6 = 6;
56    private static final int OBS_ID7 = 7;
57    private static final int OBS_ID8 = 8;
58    private static final int OBS_ID9 = 9;
59    private static final int OBS_ID10 = 10;
60    private static final int OBS_ID11 = 11;
61
62    private static final long TIME_30_MIN = 30 * 60_000L;
63    private static final long TIME_10_MIN = 10 * 60_000L;
64
65    private static final long MAX_OBSERVER_PER_UID = 10;
66    private static final long MIN_TIME_LIMIT = 4_000L;
67
68    private static final String[] GROUP1 = {
69            PKG_SOC1, PKG_GAME1, PKG_PROD
70    };
71
72    private static final String[] GROUP_SOC = {
73            PKG_SOC1, PKG_SOC2
74    };
75
76    private static final String[] GROUP_GAME = {
77            PKG_GAME1, PKG_GAME2
78    };
79
80    private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
81
82    private AppTimeLimitController mController;
83
84    private HandlerThread mThread;
85
86    private long mUptimeMillis;
87
88    AppTimeLimitController.OnLimitReachedListener mListener
89            = new AppTimeLimitController.OnLimitReachedListener() {
90
91        @Override
92        public void onLimitReached(int observerId, int userId, long timeLimit, long timeElapsed,
93                PendingIntent callbackIntent) {
94            mCountDownLatch.countDown();
95        }
96    };
97
98    class MyAppTimeLimitController extends AppTimeLimitController {
99        MyAppTimeLimitController(AppTimeLimitController.OnLimitReachedListener listener,
100                Looper looper) {
101            super(listener, looper);
102        }
103
104        @Override
105        protected long getUptimeMillis() {
106            return mUptimeMillis;
107        }
108
109        @Override
110        protected long getObserverPerUidLimit() {
111            return MAX_OBSERVER_PER_UID;
112        }
113
114        @Override
115        protected long getMinTimeLimit() {
116            return MIN_TIME_LIMIT;
117        }
118    }
119
120    @Before
121    public void setUp() {
122        mThread = new HandlerThread("Test");
123        mThread.start();
124        mController = new MyAppTimeLimitController(mListener, mThread.getLooper());
125    }
126
127    @After
128    public void tearDown() {
129        mThread.quit();
130    }
131
132    /** Verify observer is added */
133    @Test
134    public void testAddObserver() {
135        addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
136        assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
137        addObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN);
138        assertTrue("Observer wasn't added", hasObserver(OBS_ID2));
139        assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
140    }
141
142    /** Verify observer is removed */
143    @Test
144    public void testRemoveObserver() {
145        addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
146        assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
147        mController.removeObserver(UID, OBS_ID1, USER_ID);
148        assertFalse("Observer wasn't removed", hasObserver(OBS_ID1));
149    }
150
151    /** Re-adding an observer should result in only one copy */
152    @Test
153    public void testObserverReAdd() {
154        addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
155        assertTrue("Observer wasn't added", hasObserver(OBS_ID1));
156        addObserver(OBS_ID1, GROUP1, TIME_10_MIN);
157        assertTrue("Observer wasn't added",
158                mController.getObserverGroup(OBS_ID1, USER_ID).timeLimit == TIME_10_MIN);
159        mController.removeObserver(UID, OBS_ID1, USER_ID);
160        assertFalse("Observer wasn't removed", hasObserver(OBS_ID1));
161    }
162
163    /** Verify that usage across different apps within a group are added up */
164    @Test
165    public void testAccumulation() throws Exception {
166        setTime(0L);
167        addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
168        moveToForeground(PKG_SOC1);
169        // Add 10 mins
170        setTime(TIME_10_MIN);
171        moveToBackground(PKG_SOC1);
172
173        long timeRemaining = mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining;
174        assertEquals(TIME_10_MIN * 2, timeRemaining);
175
176        moveToForeground(PKG_SOC1);
177        setTime(TIME_10_MIN * 2);
178        moveToBackground(PKG_SOC1);
179
180        timeRemaining = mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining;
181        assertEquals(TIME_10_MIN, timeRemaining);
182
183        setTime(TIME_30_MIN);
184
185        assertFalse(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS));
186
187        // Add a different package in the group
188        moveToForeground(PKG_GAME1);
189        setTime(TIME_30_MIN + TIME_10_MIN);
190        moveToBackground(PKG_GAME1);
191
192        assertEquals(0, mController.getObserverGroup(OBS_ID1, USER_ID).timeRemaining);
193        assertTrue(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS));
194    }
195
196    /** Verify that time limit does not get triggered due to a different app */
197    @Test
198    public void testTimeoutOtherApp() throws Exception {
199        setTime(0L);
200        addObserver(OBS_ID1, GROUP1, 4_000L);
201        moveToForeground(PKG_SOC2);
202        assertFalse(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS));
203        setTime(6_000L);
204        moveToBackground(PKG_SOC2);
205        assertFalse(mCountDownLatch.await(100L, TimeUnit.MILLISECONDS));
206    }
207
208    /** Verify the timeout message is delivered at the right time */
209    @Test
210    public void testTimeout() throws Exception {
211        setTime(0L);
212        addObserver(OBS_ID1, GROUP1, 4_000L);
213        moveToForeground(PKG_SOC1);
214        setTime(6_000L);
215        assertTrue(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS));
216        moveToBackground(PKG_SOC1);
217        // Verify that the observer was removed
218        assertFalse(hasObserver(OBS_ID1));
219    }
220
221    /** If an app was already running, make sure it is partially counted towards the time limit */
222    @Test
223    public void testAlreadyRunning() throws Exception {
224        setTime(TIME_10_MIN);
225        moveToForeground(PKG_GAME1);
226        setTime(TIME_30_MIN);
227        addObserver(OBS_ID2, GROUP_GAME, TIME_30_MIN);
228        setTime(TIME_30_MIN + TIME_10_MIN);
229        moveToBackground(PKG_GAME1);
230        assertFalse(mCountDownLatch.await(1000L, TimeUnit.MILLISECONDS));
231
232        moveToForeground(PKG_GAME2);
233        setTime(TIME_30_MIN + TIME_30_MIN);
234        moveToBackground(PKG_GAME2);
235        assertTrue(mCountDownLatch.await(1000L, TimeUnit.MILLISECONDS));
236        // Verify that the observer was removed
237        assertFalse(hasObserver(OBS_ID2));
238    }
239
240    /** If watched app is already running, verify the timeout callback happens at the right time */
241    @Test
242    public void testAlreadyRunningTimeout() throws Exception {
243        setTime(0);
244        moveToForeground(PKG_SOC1);
245        setTime(TIME_10_MIN);
246        // 10 second time limit
247        addObserver(OBS_ID1, GROUP_SOC, 10_000L);
248        setTime(TIME_10_MIN + 5_000L);
249        // Shouldn't call back in 6 seconds
250        assertFalse(mCountDownLatch.await(6_000L, TimeUnit.MILLISECONDS));
251        setTime(TIME_10_MIN + 10_000L);
252        // Should call back by 11 seconds (6 earlier + 5 now)
253        assertTrue(mCountDownLatch.await(5_000L, TimeUnit.MILLISECONDS));
254        // Verify that the observer was removed
255        assertFalse(hasObserver(OBS_ID1));
256    }
257
258    /** Verify that App Time Limit Controller will limit the number of observerIds */
259    @Test
260    public void testMaxObserverLimit() throws Exception {
261        boolean receivedException = false;
262        int ANOTHER_UID = UID + 1;
263        addObserver(OBS_ID1, GROUP1, TIME_30_MIN);
264        addObserver(OBS_ID2, GROUP1, TIME_30_MIN);
265        addObserver(OBS_ID3, GROUP1, TIME_30_MIN);
266        addObserver(OBS_ID4, GROUP1, TIME_30_MIN);
267        addObserver(OBS_ID5, GROUP1, TIME_30_MIN);
268        addObserver(OBS_ID6, GROUP1, TIME_30_MIN);
269        addObserver(OBS_ID7, GROUP1, TIME_30_MIN);
270        addObserver(OBS_ID8, GROUP1, TIME_30_MIN);
271        addObserver(OBS_ID9, GROUP1, TIME_30_MIN);
272        addObserver(OBS_ID10, GROUP1, TIME_30_MIN);
273        // Readding an observer should not cause an IllegalStateException
274        addObserver(OBS_ID5, GROUP1, TIME_30_MIN);
275        // Adding an observer for a different uid shouldn't cause an IllegalStateException
276        mController.addObserver(ANOTHER_UID, OBS_ID11, GROUP1, TIME_30_MIN, null, USER_ID);
277        try {
278            addObserver(OBS_ID11, GROUP1, TIME_30_MIN);
279        } catch (IllegalStateException ise) {
280            receivedException = true;
281        }
282        assertTrue("Should have caused an IllegalStateException", receivedException);
283    }
284
285    /** Verify that addObserver minimum time limit is one minute */
286    @Test
287    public void testMinimumTimeLimit() throws Exception {
288        boolean receivedException = false;
289        // adding an observer with a one minute time limit should not cause an exception
290        addObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT);
291        try {
292            addObserver(OBS_ID1, GROUP1, MIN_TIME_LIMIT - 1);
293        } catch (IllegalArgumentException iae) {
294            receivedException = true;
295        }
296        assertTrue("Should have caused an IllegalArgumentException", receivedException);
297    }
298
299    private void moveToForeground(String packageName) {
300        mController.moveToForeground(packageName, "class", USER_ID);
301    }
302
303    private void moveToBackground(String packageName) {
304        mController.moveToBackground(packageName, "class", USER_ID);
305    }
306
307    private void addObserver(int observerId, String[] packages, long timeLimit) {
308        mController.addObserver(UID, observerId, packages, timeLimit, null, USER_ID);
309    }
310
311    /** Is there still an observer by that id */
312    private boolean hasObserver(int observerId) {
313        return mController.getObserverGroup(observerId, USER_ID) != null;
314    }
315
316    private void setTime(long time) {
317        mUptimeMillis = time;
318    }
319}
320