blob: d32f1f77b88f8b8a3e8ac4b50df4bff5cef2a6f1 [file] [log] [blame]
Linus Tufvesson9d501752019-02-12 11:33:22 +00001/*
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
17package com.android.server.am;
18
19import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_1;
20import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_ACTION_2;
21import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_STATSD_SAMPLE_RATE;
22import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_1;
23import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_2;
24import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_3;
25import static android.provider.DeviceConfig.ActivityManager.KEY_COMPACT_THROTTLE_4;
26import static android.provider.DeviceConfig.ActivityManager.KEY_USE_COMPACTION;
27
28import static com.android.server.am.ActivityManagerService.Injector;
29import static com.android.server.am.AppCompactor.compactActionIntToString;
30
31import static com.google.common.truth.Truth.assertThat;
32
33import android.os.Handler;
34import android.os.HandlerThread;
35import android.provider.DeviceConfig;
36
37import com.android.server.appop.AppOpsService;
38import com.android.server.testables.TestableDeviceConfig;
39
40import org.junit.After;
41import org.junit.Before;
42import org.junit.Rule;
43import org.junit.Test;
44import org.junit.runner.RunWith;
45import org.mockito.Mock;
46import org.mockito.junit.MockitoJUnitRunner;
47
48import java.io.File;
49import java.util.concurrent.CountDownLatch;
50import java.util.concurrent.TimeUnit;
51
52/**
53 * Tests for {@link AppCompactor}.
54 *
55 * Build/Install/Run:
56 * atest FrameworksServicesTests:AppCompactorTest
57 */
58@RunWith(MockitoJUnitRunner.class)
59public final class AppCompactorTest {
60
61 @Mock
62 private AppOpsService mAppOpsService;
63 private AppCompactor mCompactorUnderTest;
64 private HandlerThread mHandlerThread;
65 private Handler mHandler;
66 private CountDownLatch mCountDown;
67
68 @Rule
69 public TestableDeviceConfig mDeviceConfig = new TestableDeviceConfig();
70
71 @Before
72 public void setUp() {
73 mHandlerThread = new HandlerThread("");
74 mHandlerThread.start();
75 mHandler = new Handler(mHandlerThread.getLooper());
76 ActivityManagerService ams = new ActivityManagerService(new TestInjector());
77 mCompactorUnderTest = new AppCompactor(ams,
78 new AppCompactor.PropertyChangedCallbackForTest() {
79 @Override
80 public void onPropertyChanged() {
81 if (mCountDown != null) {
82 mCountDown.countDown();
83 }
84 }
85 });
86 }
87
88 @After
89 public void tearDown() {
90 mHandlerThread.quit();
91 mCountDown = null;
92 }
93
94 @Test
95 public void init_setsDefaults() {
96 mCompactorUnderTest.init();
97 assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
98 AppCompactor.DEFAULT_USE_COMPACTION);
99 assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
100 compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
101 assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
102 compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
103 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
104 AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
105 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
106 AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
107 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
108 AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
109 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
110 AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
111 assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
112 AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
113 }
114
115 @Test
116 public void init_withDeviceConfigSetsParameters() {
117 // When the DeviceConfig already has a flag value stored (note this test will need to
118 // change if the default value changes from false).
119 assertThat(AppCompactor.DEFAULT_USE_COMPACTION).isFalse();
120 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
121 KEY_USE_COMPACTION, "true", false);
122 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
123 KEY_COMPACT_ACTION_1,
124 Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1), false);
125 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
126 KEY_COMPACT_ACTION_2,
127 Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1), false);
128 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
129 KEY_COMPACT_THROTTLE_1,
130 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
131 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
132 KEY_COMPACT_THROTTLE_2,
133 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1), false);
134 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
135 KEY_COMPACT_THROTTLE_3,
136 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1), false);
137 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
138 KEY_COMPACT_THROTTLE_4,
139 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
140 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
141 KEY_COMPACT_STATSD_SAMPLE_RATE,
142 Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
143
144 // Then calling init will read and set that flag.
145 mCompactorUnderTest.init();
146 assertThat(mCompactorUnderTest.useCompaction()).isTrue();
147 assertThat(mCompactorUnderTest.mCompactionThread.isAlive()).isTrue();
148
149 assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
150 compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1));
151 assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
152 compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1));
153 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
154 AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1);
155 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
156 AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1);
157 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
158 AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
159 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
160 AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
161 assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
162 AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
163 }
164
165 @Test
166 public void useCompaction_listensToDeviceConfigChanges() throws InterruptedException {
167 assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
168 AppCompactor.DEFAULT_USE_COMPACTION);
169 // When we call init and change some the flag value...
170 mCompactorUnderTest.init();
171 mCountDown = new CountDownLatch(1);
172 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
173 KEY_USE_COMPACTION, "true", false);
174 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
175
176 // Then that new flag value is updated in the implementation.
177 assertThat(mCompactorUnderTest.useCompaction()).isTrue();
178 assertThat(mCompactorUnderTest.mCompactionThread.isAlive()).isTrue();
179
180 // And again, setting the flag the other way.
181 mCountDown = new CountDownLatch(1);
182 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
183 KEY_USE_COMPACTION, "false", false);
184 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
185 assertThat(mCompactorUnderTest.useCompaction()).isFalse();
186 }
187
188 @Test
189 public void useCompaction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
190 assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
191 AppCompactor.DEFAULT_USE_COMPACTION);
192 mCompactorUnderTest.init();
193
194 // When we push an invalid flag value...
195 mCountDown = new CountDownLatch(1);
196 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
197 KEY_USE_COMPACTION, "foobar", false);
198 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
199
200 // Then we set the default.
201 assertThat(mCompactorUnderTest.useCompaction()).isEqualTo(
202 AppCompactor.DEFAULT_USE_COMPACTION);
203 }
204
205 @Test
206 public void compactAction_listensToDeviceConfigChanges() throws InterruptedException {
207 mCompactorUnderTest.init();
208
209 // When we override new values for the compaction action with reasonable values...
210
211 // There are four possible values for compactAction[Some|Full].
212 for (int i = 1; i < 5; i++) {
213 mCountDown = new CountDownLatch(2);
214 int expectedSome = (AppCompactor.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
215 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
216 KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false);
217 int expectedFull = (AppCompactor.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
218 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
219 KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false);
220 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
221
222 // Then the updates are reflected in the flags.
223 assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
224 compactActionIntToString(expectedSome));
225 assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
226 compactActionIntToString(expectedFull));
227 }
228 }
229
230 @Test
231 public void compactAction_listensToDeviceConfigChangesBadValues() throws InterruptedException {
232 mCompactorUnderTest.init();
233
234 // When we override new values for the compaction action with bad values ...
235 mCountDown = new CountDownLatch(2);
236 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
237 KEY_COMPACT_ACTION_1, "foo", false);
238 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
239 KEY_COMPACT_ACTION_2, "foo", false);
240 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
241
242 // Then the default values are reflected in the flag
243 assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
244 compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
245 assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
246 compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
247
248 mCountDown = new CountDownLatch(2);
249 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
250 KEY_COMPACT_ACTION_1, "", false);
251 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
252 KEY_COMPACT_ACTION_2, "", false);
253 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
254
255 assertThat(mCompactorUnderTest.mCompactActionSome).isEqualTo(
256 compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_1));
257 assertThat(mCompactorUnderTest.mCompactActionFull).isEqualTo(
258 compactActionIntToString(AppCompactor.DEFAULT_COMPACT_ACTION_2));
259 }
260
261 @Test
262 public void compactThrottle_listensToDeviceConfigChanges() throws InterruptedException {
263 mCompactorUnderTest.init();
264
265 // When we override new reasonable throttle values after init...
266 mCountDown = new CountDownLatch(4);
267 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
268 KEY_COMPACT_THROTTLE_1,
269 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
270 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
271 KEY_COMPACT_THROTTLE_2,
272 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1), false);
273 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
274 KEY_COMPACT_THROTTLE_3,
275 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1), false);
276 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
277 KEY_COMPACT_THROTTLE_4,
278 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
279 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
280
281 // Then those flags values are reflected in the compactor.
282 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
283 AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1);
284 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
285 AppCompactor.DEFAULT_COMPACT_THROTTLE_2 + 1);
286 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
287 AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
288 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
289 AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
290 }
291
292 @Test
293 public void compactThrottle_listensToDeviceConfigChangesBadValues()
294 throws InterruptedException {
295 mCompactorUnderTest.init();
296
297 // When one of the throttles is overridden with a bad value...
298 mCountDown = new CountDownLatch(1);
299 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
300 KEY_COMPACT_THROTTLE_1, "foo", false);
301 // Then all the throttles have the defaults set.
302 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
303 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
304 AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
305 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
306 AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
307 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
308 AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
309 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
310 AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
311
312 // Repeat for each of the throttle keys.
313 mCountDown = new CountDownLatch(1);
314 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
315 KEY_COMPACT_THROTTLE_2, "foo", false);
316 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
317 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
318 AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
319 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
320 AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
321 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
322 AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
323 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
324 AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
325
326 mCountDown = new CountDownLatch(1);
327 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
328 KEY_COMPACT_THROTTLE_3, "foo", false);
329 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
330 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
331 AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
332 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
333 AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
334 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
335 AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
336 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
337 AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
338
339 mCountDown = new CountDownLatch(1);
340 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
341 KEY_COMPACT_THROTTLE_4, "foo", false);
342 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
343 assertThat(mCompactorUnderTest.mCompactThrottleSomeSome).isEqualTo(
344 AppCompactor.DEFAULT_COMPACT_THROTTLE_1);
345 assertThat(mCompactorUnderTest.mCompactThrottleSomeFull).isEqualTo(
346 AppCompactor.DEFAULT_COMPACT_THROTTLE_2);
347 assertThat(mCompactorUnderTest.mCompactThrottleFullSome).isEqualTo(
348 AppCompactor.DEFAULT_COMPACT_THROTTLE_3);
349 assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
350 AppCompactor.DEFAULT_COMPACT_THROTTLE_4);
351 }
352
353 @Test
354 public void statsdSampleRate_listensToDeviceConfigChanges() throws InterruptedException {
355 mCompactorUnderTest.init();
356
357 // When we override mStatsdSampleRate with a reasonable values ...
358 mCountDown = new CountDownLatch(1);
359 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
360 KEY_COMPACT_STATSD_SAMPLE_RATE,
361 Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
362 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
363
364 // Then that override is reflected in the compactor.
365 assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
366 AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
367 }
368
369 @Test
370 public void statsdSanokeRate_listensToDeviceConfigChangesBadValues()
371 throws InterruptedException {
372 mCompactorUnderTest.init();
373
374 // When we override mStatsdSampleRate with a reasonable values ...
375 mCountDown = new CountDownLatch(1);
376 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
377 KEY_COMPACT_STATSD_SAMPLE_RATE, "foo", false);
378 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
379
380 // Then that override is reflected in the compactor.
381 assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
382 AppCompactor.DEFAULT_STATSD_SAMPLE_RATE);
383 }
384
385 @Test
386 public void statsdSanokeRate_listensToDeviceConfigChangesOutOfRangeValues()
387 throws InterruptedException {
388 mCompactorUnderTest.init();
389
390 // When we override mStatsdSampleRate with an value outside of [0..1]...
391 mCountDown = new CountDownLatch(1);
392 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
393 KEY_COMPACT_STATSD_SAMPLE_RATE,
394 Float.toString(-1.0f), false);
395 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
396
397 // Then the values is capped in the range.
398 assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(0.0f);
399
400 mCountDown = new CountDownLatch(1);
401 DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
402 KEY_COMPACT_STATSD_SAMPLE_RATE,
403 Float.toString(1.01f), false);
404 assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
405
406 // Then the values is capped in the range.
407 assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(1.0f);
408 }
409
410 private class TestInjector extends Injector {
411 @Override
412 public AppOpsService getAppOpsService(File file, Handler handler) {
413 return mAppOpsService;
414 }
415
416 @Override
417 public Handler getUiHandler(ActivityManagerService service) {
418 return mHandler;
419 }
420 }
421}