1/*
2 * Copyright (C) 2017 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.wm;
18
19import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
20import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
21import static org.junit.Assert.assertEquals;
22import static org.junit.Assert.assertFalse;
23import static org.junit.Assert.assertNotNull;
24import static org.junit.Assert.assertNull;
25import static org.junit.Assert.assertTrue;
26import static org.junit.Assert.fail;
27
28import android.app.ActivityManager.TaskSnapshot;
29import android.content.res.Configuration;
30import android.graphics.Rect;
31import android.os.SystemClock;
32import android.platform.test.annotations.Presubmit;
33import android.support.test.filters.MediumTest;
34import android.support.test.runner.AndroidJUnit4;
35import android.util.ArraySet;
36
37import android.view.View;
38import com.android.server.wm.TaskSnapshotPersister.RemoveObsoleteFilesQueueItem;
39
40import org.junit.Test;
41import org.junit.runner.RunWith;
42
43import java.io.File;
44
45/**
46 * Test class for {@link TaskSnapshotPersister} and {@link TaskSnapshotLoader}
47 *
48 * atest FrameworksServicesTests:TaskSnapshotPersisterLoaderTest
49 */
50@MediumTest
51@Presubmit
52@RunWith(AndroidJUnit4.class)
53public class TaskSnapshotPersisterLoaderTest extends TaskSnapshotPersisterTestBase {
54
55    private static final Rect TEST_INSETS = new Rect(10, 20, 30, 40);
56
57    @Test
58    public void testPersistAndLoadSnapshot() {
59        mPersister.persistSnapshot(1 , mTestUserId, createSnapshot());
60        mPersister.waitForQueueEmpty();
61        final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
62                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
63                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")};
64        assertTrueForFiles(files, File::exists, " must exist");
65        final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, false /* reduced */);
66        assertNotNull(snapshot);
67        assertEquals(TEST_INSETS, snapshot.getContentInsets());
68        assertNotNull(snapshot.getSnapshot());
69        assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
70    }
71
72    private void assertTrueForFiles(File[] files, Predicate<File> predicate, String message) {
73        for (File file : files) {
74            assertTrue(file.getName() + message, predicate.apply(file));
75        }
76    }
77
78    @Test
79    public void testTaskRemovedFromRecents() {
80        mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
81        mPersister.onTaskRemovedFromRecents(1, mTestUserId);
82        mPersister.waitForQueueEmpty();
83        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.proto").exists());
84        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1.jpg").exists());
85        assertFalse(new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg").exists());
86    }
87
88    /**
89     * Tests that persisting a couple of snapshots is being throttled.
90     */
91    @Test
92    public void testThrottling() {
93        long ms = SystemClock.elapsedRealtime();
94        mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
95        mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
96        mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
97        mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
98        mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
99        mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
100        mPersister.waitForQueueEmpty();
101        assertTrue(SystemClock.elapsedRealtime() - ms > 500);
102    }
103
104    /**
105     * Tests that too many store write queue items are being purged.
106     */
107    @Test
108    public void testPurging() {
109        mPersister.persistSnapshot(100, mTestUserId, createSnapshot());
110        mPersister.waitForQueueEmpty();
111        mPersister.setPaused(true);
112        mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
113        mPersister.removeObsoleteFiles(new ArraySet<>(), new int[] { mTestUserId });
114        mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
115        mPersister.persistSnapshot(3, mTestUserId, createSnapshot());
116        mPersister.persistSnapshot(4, mTestUserId, createSnapshot());
117        mPersister.setPaused(false);
118        mPersister.waitForQueueEmpty();
119
120        // Make sure 1,2 were purged but removeObsoleteFiles wasn't.
121        final File[] existsFiles = new File[] {
122                new File(sFilesDir.getPath() + "/snapshots/3.proto"),
123                new File(sFilesDir.getPath() + "/snapshots/4.proto")};
124        final File[] nonExistsFiles = new File[] {
125                new File(sFilesDir.getPath() + "/snapshots/100.proto"),
126                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
127                new File(sFilesDir.getPath() + "/snapshots/1.proto")};
128        assertTrueForFiles(existsFiles, File::exists, " must exist");
129        assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
130    }
131
132    @Test
133    public void testGetTaskId() {
134        RemoveObsoleteFilesQueueItem removeObsoleteFilesQueueItem =
135                mPersister.new RemoveObsoleteFilesQueueItem(new ArraySet<>(), new int[] {});
136        assertEquals(-1, removeObsoleteFilesQueueItem.getTaskId("blablablulp"));
137        assertEquals(-1, removeObsoleteFilesQueueItem.getTaskId("nothing.err"));
138        assertEquals(-1, removeObsoleteFilesQueueItem.getTaskId("/invalid/"));
139        assertEquals(12, removeObsoleteFilesQueueItem.getTaskId("12.jpg"));
140        assertEquals(12, removeObsoleteFilesQueueItem.getTaskId("12.proto"));
141        assertEquals(1, removeObsoleteFilesQueueItem.getTaskId("1.jpg"));
142        assertEquals(1, removeObsoleteFilesQueueItem.getTaskId("1_reduced.jpg"));
143    }
144
145    @Test
146    public void testLowResolutionPersistAndLoadSnapshot() {
147        TaskSnapshot a = createSnapshot(0.5f /* reducedResolution */);
148        assertTrue(a.isReducedResolution());
149        mPersister.persistSnapshot(1 , mTestUserId, a);
150        mPersister.waitForQueueEmpty();
151        final File[] files = new File[] { new File(sFilesDir.getPath() + "/snapshots/1.proto"),
152                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg")};
153        final File[] nonExistsFiles = new File[] {
154                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
155        };
156        assertTrueForFiles(files, File::exists, " must exist");
157        assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
158        final TaskSnapshot snapshot = mLoader.loadTask(1, mTestUserId, true /* reduced */);
159        assertNotNull(snapshot);
160        assertEquals(TEST_INSETS, snapshot.getContentInsets());
161        assertNotNull(snapshot.getSnapshot());
162        assertEquals(Configuration.ORIENTATION_PORTRAIT, snapshot.getOrientation());
163
164        final TaskSnapshot snapshotNotExist = mLoader.loadTask(1, mTestUserId, false /* reduced */);
165        assertNull(snapshotNotExist);
166    }
167
168    @Test
169    public void testIsRealSnapshotPersistAndLoadSnapshot() {
170        TaskSnapshot a = new TaskSnapshotBuilder()
171                .setIsRealSnapshot(true)
172                .build();
173        TaskSnapshot b = new TaskSnapshotBuilder()
174                .setIsRealSnapshot(false)
175                .build();
176        assertTrue(a.isRealSnapshot());
177        assertFalse(b.isRealSnapshot());
178        mPersister.persistSnapshot(1, mTestUserId, a);
179        mPersister.persistSnapshot(2, mTestUserId, b);
180        mPersister.waitForQueueEmpty();
181        final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
182        final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
183        assertNotNull(snapshotA);
184        assertNotNull(snapshotB);
185        assertTrue(snapshotA.isRealSnapshot());
186        assertFalse(snapshotB.isRealSnapshot());
187    }
188
189    @Test
190    public void testWindowingModePersistAndLoadSnapshot() {
191        TaskSnapshot a = new TaskSnapshotBuilder()
192                .setWindowingMode(WINDOWING_MODE_FULLSCREEN)
193                .build();
194        TaskSnapshot b = new TaskSnapshotBuilder()
195                .setWindowingMode(WINDOWING_MODE_PINNED)
196                .build();
197        assertTrue(a.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
198        assertTrue(b.getWindowingMode() == WINDOWING_MODE_PINNED);
199        mPersister.persistSnapshot(1, mTestUserId, a);
200        mPersister.persistSnapshot(2, mTestUserId, b);
201        mPersister.waitForQueueEmpty();
202        final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
203        final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
204        assertNotNull(snapshotA);
205        assertNotNull(snapshotB);
206        assertTrue(snapshotA.getWindowingMode() == WINDOWING_MODE_FULLSCREEN);
207        assertTrue(snapshotB.getWindowingMode() == WINDOWING_MODE_PINNED);
208    }
209
210    @Test
211    public void testIsTranslucentPersistAndLoadSnapshot() {
212        TaskSnapshot a = new TaskSnapshotBuilder()
213                .setIsTranslucent(true)
214                .build();
215        TaskSnapshot b = new TaskSnapshotBuilder()
216                .setIsTranslucent(false)
217                .build();
218        assertTrue(a.isTranslucent());
219        assertFalse(b.isTranslucent());
220        mPersister.persistSnapshot(1, mTestUserId, a);
221        mPersister.persistSnapshot(2, mTestUserId, b);
222        mPersister.waitForQueueEmpty();
223        final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
224        final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
225        assertNotNull(snapshotA);
226        assertNotNull(snapshotB);
227        assertTrue(snapshotA.isTranslucent());
228        assertFalse(snapshotB.isTranslucent());
229    }
230
231    @Test
232    public void testSystemUiVisibilityPersistAndLoadSnapshot() {
233        final int lightBarFlags = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
234                | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR;
235        TaskSnapshot a = new TaskSnapshotBuilder()
236                .setSystemUiVisibility(0)
237                .build();
238        TaskSnapshot b = new TaskSnapshotBuilder()
239                .setSystemUiVisibility(lightBarFlags)
240                .build();
241        assertTrue(a.getSystemUiVisibility() == 0);
242        assertTrue(b.getSystemUiVisibility() == lightBarFlags);
243        mPersister.persistSnapshot(1, mTestUserId, a);
244        mPersister.persistSnapshot(2, mTestUserId, b);
245        mPersister.waitForQueueEmpty();
246        final TaskSnapshot snapshotA = mLoader.loadTask(1, mTestUserId, false /* reduced */);
247        final TaskSnapshot snapshotB = mLoader.loadTask(2, mTestUserId, false /* reduced */);
248        assertNotNull(snapshotA);
249        assertNotNull(snapshotB);
250        assertTrue(snapshotA.getSystemUiVisibility() == 0);
251        assertTrue(snapshotB.getSystemUiVisibility() == lightBarFlags);
252    }
253
254    @Test
255    public void testRemoveObsoleteFiles() {
256        mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
257        mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
258        final ArraySet<Integer> taskIds = new ArraySet<>();
259        taskIds.add(1);
260        mPersister.removeObsoleteFiles(taskIds, new int[] { mTestUserId });
261        mPersister.waitForQueueEmpty();
262        final File[] existsFiles = new File[] {
263                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
264                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
265                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg") };
266        final File[] nonExistsFiles = new File[] {
267                new File(sFilesDir.getPath() + "/snapshots/2.proto"),
268                new File(sFilesDir.getPath() + "/snapshots/2.jpg"),
269                new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
270        assertTrueForFiles(existsFiles, File::exists, " must exist");
271        assertTrueForFiles(nonExistsFiles, file -> !file.exists(), " must not exist");
272    }
273
274    @Test
275    public void testRemoveObsoleteFiles_addedOneInTheMeantime() {
276        mPersister.persistSnapshot(1, mTestUserId, createSnapshot());
277        final ArraySet<Integer> taskIds = new ArraySet<>();
278        taskIds.add(1);
279        mPersister.removeObsoleteFiles(taskIds, new int[] { mTestUserId });
280        mPersister.persistSnapshot(2, mTestUserId, createSnapshot());
281        mPersister.waitForQueueEmpty();
282        final File[] existsFiles = new File[] {
283                new File(sFilesDir.getPath() + "/snapshots/1.proto"),
284                new File(sFilesDir.getPath() + "/snapshots/1.jpg"),
285                new File(sFilesDir.getPath() + "/snapshots/1_reduced.jpg"),
286                new File(sFilesDir.getPath() + "/snapshots/2.proto"),
287                new File(sFilesDir.getPath() + "/snapshots/2.jpg"),
288                new File(sFilesDir.getPath() + "/snapshots/2_reduced.jpg")};
289        assertTrueForFiles(existsFiles, File::exists, " must exist");
290    }
291
292    /**
293     * Private predicate definition.
294     *
295     * This is needed because com.android.internal.util.Predicate is deprecated
296     * and can only be used with classes fron android.test.runner. This cannot
297     * use java.util.function.Predicate because that is not present on all API
298     * versions that this test must run on.
299     */
300    private interface Predicate<T> {
301        boolean apply(T t);
302    }
303}
304