PackageDexUsageTests.java revision 99dd37b3c5262910150ef955d16a33d32da264dd
1/*
2 * Copyright (C) 2016 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.pm.dex;
18
19import android.os.Build;
20import android.support.test.filters.SmallTest;
21import android.support.test.runner.AndroidJUnit4;
22import dalvik.system.VMRuntime;
23
24import org.junit.Before;
25import org.junit.Test;
26import org.junit.runner.RunWith;
27
28import java.io.IOException;
29import java.io.StringReader;
30import java.io.StringWriter;
31import java.util.Arrays;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.Map;
35import java.util.Set;
36
37import static org.junit.Assert.assertEquals;
38import static org.junit.Assert.assertFalse;
39import static org.junit.Assert.assertNotNull;
40import static org.junit.Assert.assertNull;
41import static org.junit.Assert.assertTrue;
42import static org.junit.Assert.fail;
43
44import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
45import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
46
47@RunWith(AndroidJUnit4.class)
48@SmallTest
49public class PackageDexUsageTests {
50    private PackageDexUsage mPackageDexUsage;
51
52    private TestData mFooBaseUser0;
53    private TestData mFooSplit1User0;
54    private TestData mFooSplit2UsedByOtherApps0;
55    private TestData mFooSecondary1User0;
56    private TestData mFooSecondary1User1;
57    private TestData mFooSecondary2UsedByOtherApps0;
58    private TestData mInvalidIsa;
59
60    private TestData mBarBaseUser0;
61    private TestData mBarSecondary1User0;
62    private TestData mBarSecondary2User1;
63
64    @Before
65    public void setup() {
66        mPackageDexUsage = new PackageDexUsage();
67
68        String fooPackageName = "com.google.foo";
69        String fooCodeDir = "/data/app/com.google.foo/";
70        String fooDataDir = "/data/user/0/com.google.foo/";
71
72        String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
73
74        mFooBaseUser0 = new TestData(fooPackageName,
75                fooCodeDir + "base.apk", 0, isa, false, true);
76
77        mFooSplit1User0 = new TestData(fooPackageName,
78                fooCodeDir + "split-1.apk", 0, isa, false, true);
79
80        mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName,
81                fooCodeDir + "split-2.apk", 0, isa, true, true);
82
83        mFooSecondary1User0 = new TestData(fooPackageName,
84                fooDataDir + "sec-1.dex", 0, isa, false, false);
85
86        mFooSecondary1User1 = new TestData(fooPackageName,
87                fooDataDir + "sec-1.dex", 1, isa, false, false);
88
89        mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName,
90                fooDataDir + "sec-2.dex", 0, isa, true, false);
91
92        mInvalidIsa = new TestData(fooPackageName,
93                fooCodeDir + "base.apk", 0, "INVALID_ISA", false, true);
94
95        String barPackageName = "com.google.bar";
96        String barCodeDir = "/data/app/com.google.bar/";
97        String barDataDir = "/data/user/0/com.google.bar/";
98        String barDataDir1 = "/data/user/1/com.google.bar/";
99
100        mBarBaseUser0 = new TestData(barPackageName,
101                barCodeDir + "base.apk", 0, isa, false, true);
102        mBarSecondary1User0 = new TestData(barPackageName,
103                barDataDir + "sec-1.dex", 0, isa, false, false);
104        mBarSecondary2User1 = new TestData(barPackageName,
105                barDataDir1 + "sec-2.dex", 1, isa, false, false);
106    }
107
108    @Test
109    public void testRecordPrimary() {
110        // Assert new information.
111        assertTrue(record(mFooBaseUser0));
112
113        assertPackageDexUsage(mFooBaseUser0);
114        writeAndReadBack();
115        assertPackageDexUsage(mFooBaseUser0);
116    }
117
118    @Test
119    public void testRecordSplit() {
120        // Assert new information.
121        assertTrue(record(mFooSplit1User0));
122
123        assertPackageDexUsage(mFooSplit1User0);
124        writeAndReadBack();
125        assertPackageDexUsage(mFooSplit1User0);
126    }
127
128    @Test
129    public void testRecordSplitPrimarySequence() {
130        // Assert new information.
131        assertTrue(record(mFooBaseUser0));
132        // Assert no new information.
133        assertFalse(record(mFooSplit1User0));
134
135        assertPackageDexUsage(mFooBaseUser0);
136        writeAndReadBack();
137        assertPackageDexUsage(mFooBaseUser0);
138
139        // Write Split2 which is used by other apps.
140        // Assert new information.
141        assertTrue(record(mFooSplit2UsedByOtherApps0));
142        assertPackageDexUsage(mFooSplit2UsedByOtherApps0);
143        writeAndReadBack();
144        assertPackageDexUsage(mFooSplit2UsedByOtherApps0);
145    }
146
147    @Test
148    public void testRecordSecondary() {
149        assertTrue(record(mFooSecondary1User0));
150
151        assertPackageDexUsage(null, mFooSecondary1User0);
152        writeAndReadBack();
153        assertPackageDexUsage(null, mFooSecondary1User0);
154
155        // Recording again does not add more data.
156        assertFalse(record(mFooSecondary1User0));
157        assertPackageDexUsage(null, mFooSecondary1User0);
158    }
159
160    @Test
161    public void testRecordBaseAndSecondarySequence() {
162        // Write split.
163        assertTrue(record(mFooSplit2UsedByOtherApps0));
164        // Write secondary.
165        assertTrue(record(mFooSecondary1User0));
166
167        // Check.
168        assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0);
169        writeAndReadBack();
170        assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0);
171
172        // Write another secondary.
173        assertTrue(record(mFooSecondary2UsedByOtherApps0));
174
175        // Check.
176        assertPackageDexUsage(
177                mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
178        writeAndReadBack();
179        assertPackageDexUsage(
180                mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
181    }
182
183    @Test
184    public void testMultiplePackages() {
185        assertTrue(record(mFooBaseUser0));
186        assertTrue(record(mFooSecondary1User0));
187        assertTrue(record(mFooSecondary2UsedByOtherApps0));
188        assertTrue(record(mBarBaseUser0));
189        assertTrue(record(mBarSecondary1User0));
190        assertTrue(record(mBarSecondary2User1));
191
192        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
193        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
194        writeAndReadBack();
195        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
196        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
197    }
198
199    @Test
200    public void testPackageNotFound() {
201        assertNull(mPackageDexUsage.getPackageUseInfo("missing.package"));
202    }
203
204    @Test
205    public void testAttemptToChangeOwner() {
206        assertTrue(record(mFooSecondary1User0));
207        try {
208            record(mFooSecondary1User1);
209            fail("Expected exception");
210        } catch (IllegalArgumentException e) {
211            // expected
212        }
213    }
214
215    @Test
216    public void testInvalidIsa() {
217        try {
218            record(mInvalidIsa);
219            fail("Expected exception");
220        } catch (IllegalArgumentException e) {
221            // expected
222        }
223    }
224
225    @Test
226    public void testReadWriteEmtpy() {
227        // Expect no exceptions when writing/reading without data.
228        writeAndReadBack();
229    }
230
231    @Test
232    public void testSyncData() {
233        // Write some records.
234        assertTrue(record(mFooBaseUser0));
235        assertTrue(record(mFooSecondary1User0));
236        assertTrue(record(mFooSecondary2UsedByOtherApps0));
237        assertTrue(record(mBarBaseUser0));
238        assertTrue(record(mBarSecondary1User0));
239        assertTrue(record(mBarSecondary2User1));
240
241        // Verify all is good.
242        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
243        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
244        writeAndReadBack();
245        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
246        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
247
248        // Simulate that only user 1 is available.
249        Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
250        packageToUsersMap.put(mBarSecondary2User1.mPackageName,
251                new HashSet<>(Arrays.asList(mBarSecondary2User1.mOwnerUserId)));
252        mPackageDexUsage.syncData(packageToUsersMap);
253
254        // Assert that only user 1 files are there.
255        assertPackageDexUsage(mBarBaseUser0, mBarSecondary2User1);
256        assertNull(mPackageDexUsage.getPackageUseInfo(mFooBaseUser0.mPackageName));
257    }
258
259    @Test
260    public void testRemovePackage() {
261        // Record Bar secondaries for two different users.
262        assertTrue(record(mBarSecondary1User0));
263        assertTrue(record(mBarSecondary2User1));
264
265        // Remove the package.
266        assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
267        // Assert that we can't find the package anymore.
268        assertNull(mPackageDexUsage.getPackageUseInfo(mBarSecondary1User0.mPackageName));
269    }
270
271    @Test
272    public void testRemoveNonexistentPackage() {
273        // Record Bar secondaries for two different users.
274        assertTrue(record(mBarSecondary1User0));
275
276        // Remove the package.
277        assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
278        // Remove the package again. It should return false because the package no longer
279        // has a record in the use info.
280        assertFalse(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
281    }
282
283    @Test
284    public void testRemoveUserPackage() {
285        // Record Bar secondaries for two different users.
286        assertTrue(record(mBarSecondary1User0));
287        assertTrue(record(mBarSecondary2User1));
288
289        // Remove user 0 files.
290        assertTrue(mPackageDexUsage.removeUserPackage(mBarSecondary1User0.mPackageName,
291                mBarSecondary1User0.mOwnerUserId));
292        // Assert that only user 1 files are there.
293        assertPackageDexUsage(null, mBarSecondary2User1);
294    }
295
296    @Test
297    public void testRemoveDexFile() {
298        // Record Bar secondaries for two different users.
299        assertTrue(record(mBarSecondary1User0));
300        assertTrue(record(mBarSecondary2User1));
301
302        // Remove mBarSecondary1User0 file.
303        assertTrue(mPackageDexUsage.removeDexFile(mBarSecondary1User0.mPackageName,
304                mBarSecondary1User0.mDexFile, mBarSecondary1User0.mOwnerUserId));
305        // Assert that only user 1 files are there.
306        assertPackageDexUsage(null, mBarSecondary2User1);
307    }
308
309    @Test
310    public void testClearUsedByOtherApps() {
311        // Write a package which is used by other apps.
312        assertTrue(record(mFooSplit2UsedByOtherApps0));
313        assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
314
315        // Check that the package is no longer used by other apps.
316        TestData noLongerUsedByOtherApps = new TestData(
317            mFooSplit2UsedByOtherApps0.mPackageName,
318            mFooSplit2UsedByOtherApps0.mDexFile,
319            mFooSplit2UsedByOtherApps0.mOwnerUserId,
320            mFooSplit2UsedByOtherApps0.mLoaderIsa,
321            /*mIsUsedByOtherApps*/false,
322            mFooSplit2UsedByOtherApps0.mPrimaryOrSplit);
323        assertPackageDexUsage(noLongerUsedByOtherApps);
324    }
325
326    @Test
327    public void testClearUsedByOtherAppsNonexistent() {
328        // Write a package which is used by other apps.
329        assertTrue(record(mFooSplit2UsedByOtherApps0));
330        assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
331        // Clearing again should return false as there should be no update on the use info.
332        assertFalse(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
333    }
334
335    private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
336        String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName;
337        boolean primaryUsedByOtherApps = primary == null ? false : primary.mUsedByOtherApps;
338        PackageUseInfo pInfo = mPackageDexUsage.getPackageUseInfo(packageName);
339
340        // Check package use info
341        assertNotNull(pInfo);
342        assertEquals(primaryUsedByOtherApps, pInfo.isUsedByOtherApps());
343        Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap();
344        assertEquals(secondaries.length, dexUseInfoMap.size());
345
346        // Check dex use info
347        for (TestData testData : secondaries) {
348            DexUseInfo dInfo = dexUseInfoMap.get(testData.mDexFile);
349            assertNotNull(dInfo);
350            assertEquals(testData.mUsedByOtherApps, dInfo.isUsedByOtherApps());
351            assertEquals(testData.mOwnerUserId, dInfo.getOwnerUserId());
352            assertEquals(1, dInfo.getLoaderIsas().size());
353            assertTrue(dInfo.getLoaderIsas().contains(testData.mLoaderIsa));
354        }
355    }
356
357    private boolean record(TestData testData) {
358        return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile,
359                testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps,
360                testData.mPrimaryOrSplit);
361    }
362
363    private void writeAndReadBack() {
364        try {
365            StringWriter writer = new StringWriter();
366            mPackageDexUsage.write(writer);
367
368            mPackageDexUsage = new PackageDexUsage();
369            mPackageDexUsage.read(new StringReader(writer.toString()));
370        } catch (IOException e) {
371            fail("Unexpected IOException: " + e.getMessage());
372        }
373    }
374
375    private static class TestData {
376        private final String mPackageName;
377        private final String mDexFile;
378        private final int mOwnerUserId;
379        private final String mLoaderIsa;
380        private final boolean mUsedByOtherApps;
381        private final boolean mPrimaryOrSplit;
382
383        private TestData(String packageName, String dexFile, int ownerUserId,
384                 String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit) {
385            mPackageName = packageName;
386            mDexFile = dexFile;
387            mOwnerUserId = ownerUserId;
388            mLoaderIsa = loaderIsa;
389            mUsedByOtherApps = isUsedByOtherApps;
390            mPrimaryOrSplit = primaryOrSplit;
391        }
392
393    }
394}
395