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 java.util.Collections;
25import org.junit.Before;
26import org.junit.Test;
27import org.junit.runner.RunWith;
28
29import java.io.IOException;
30import java.io.StringReader;
31import java.io.StringWriter;
32import java.util.Arrays;
33import java.util.HashMap;
34import java.util.HashSet;
35import java.util.Map;
36import java.util.Set;
37
38import static org.junit.Assert.assertEquals;
39import static org.junit.Assert.assertFalse;
40import static org.junit.Assert.assertNotNull;
41import static org.junit.Assert.assertNull;
42import static org.junit.Assert.assertTrue;
43import static org.junit.Assert.fail;
44
45import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
46import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
47
48@RunWith(AndroidJUnit4.class)
49@SmallTest
50public class PackageDexUsageTests {
51    private PackageDexUsage mPackageDexUsage;
52
53    private TestData mFooBaseUser0;
54    private TestData mFooSplit1User0;
55    private TestData mFooSplit2UsedByOtherApps0;
56    private TestData mFooSecondary1User0;
57    private TestData mFooSecondary1User1;
58    private TestData mFooSecondary2UsedByOtherApps0;
59    private TestData mInvalidIsa;
60
61    private TestData mBarBaseUser0;
62    private TestData mBarSecondary1User0;
63    private TestData mBarSecondary2User1;
64
65    @Before
66    public void setup() {
67        mPackageDexUsage = new PackageDexUsage();
68
69        String fooPackageName = "com.google.foo";
70        String fooCodeDir = "/data/app/com.google.foo/";
71        String fooDataDir = "/data/user/0/com.google.foo/";
72
73        String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
74
75        mFooBaseUser0 = new TestData(fooPackageName,
76                fooCodeDir + "base.apk", 0, isa, false, true, fooPackageName);
77
78        mFooSplit1User0 = new TestData(fooPackageName,
79                fooCodeDir + "split-1.apk", 0, isa, false, true, fooPackageName);
80
81        mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName,
82                fooCodeDir + "split-2.apk", 0, isa, true, true, "used.by.other.com");
83
84        mFooSecondary1User0 = new TestData(fooPackageName,
85                fooDataDir + "sec-1.dex", 0, isa, false, false, fooPackageName);
86
87        mFooSecondary1User1 = new TestData(fooPackageName,
88                fooDataDir + "sec-1.dex", 1, isa, false, false, fooPackageName);
89
90        mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName,
91                fooDataDir + "sec-2.dex", 0, isa, true, false, "used.by.other.com");
92
93        mInvalidIsa = new TestData(fooPackageName,
94                fooCodeDir + "base.apk", 0, "INVALID_ISA", false, true, "INALID_USER");
95
96        String barPackageName = "com.google.bar";
97        String barCodeDir = "/data/app/com.google.bar/";
98        String barDataDir = "/data/user/0/com.google.bar/";
99        String barDataDir1 = "/data/user/1/com.google.bar/";
100
101        mBarBaseUser0 = new TestData(barPackageName,
102                barCodeDir + "base.apk", 0, isa, false, true, barPackageName);
103        mBarSecondary1User0 = new TestData(barPackageName,
104                barDataDir + "sec-1.dex", 0, isa, false, false, barPackageName);
105        mBarSecondary2User1 = new TestData(barPackageName,
106                barDataDir1 + "sec-2.dex", 1, isa, false, false, barPackageName);
107    }
108
109    @Test
110    public void testRecordPrimary() {
111        // Assert new information.
112        assertTrue(record(mFooBaseUser0));
113
114        assertPackageDexUsage(mFooBaseUser0);
115        writeAndReadBack();
116        assertPackageDexUsage(mFooBaseUser0);
117    }
118
119    @Test
120    public void testRecordSplit() {
121        // Assert new information.
122        assertTrue(record(mFooSplit1User0));
123
124        assertPackageDexUsage(mFooSplit1User0);
125        writeAndReadBack();
126        assertPackageDexUsage(mFooSplit1User0);
127    }
128
129    @Test
130    public void testRecordSplitPrimarySequence() {
131        // Assert new information.
132        assertTrue(record(mFooBaseUser0));
133        // Assert no new information.
134        assertFalse(record(mFooSplit1User0));
135
136        assertPackageDexUsage(mFooBaseUser0);
137        writeAndReadBack();
138        assertPackageDexUsage(mFooBaseUser0);
139
140        // Write Split2 which is used by other apps.
141        // Assert new information.
142        assertTrue(record(mFooSplit2UsedByOtherApps0));
143        assertPackageDexUsage(mFooSplit2UsedByOtherApps0);
144        writeAndReadBack();
145        assertPackageDexUsage(mFooSplit2UsedByOtherApps0);
146    }
147
148    @Test
149    public void testRecordSecondary() {
150        assertTrue(record(mFooSecondary1User0));
151
152        assertPackageDexUsage(null, mFooSecondary1User0);
153        writeAndReadBack();
154        assertPackageDexUsage(null, mFooSecondary1User0);
155
156        // Recording again does not add more data.
157        assertFalse(record(mFooSecondary1User0));
158        assertPackageDexUsage(null, mFooSecondary1User0);
159    }
160
161    @Test
162    public void testRecordBaseAndSecondarySequence() {
163        // Write split.
164        assertTrue(record(mFooSplit2UsedByOtherApps0));
165        // Write secondary.
166        assertTrue(record(mFooSecondary1User0));
167
168        // Check.
169        assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0);
170        writeAndReadBack();
171        assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0);
172
173        // Write another secondary.
174        assertTrue(record(mFooSecondary2UsedByOtherApps0));
175
176        // Check.
177        assertPackageDexUsage(
178                mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
179        writeAndReadBack();
180        assertPackageDexUsage(
181                mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
182    }
183
184    @Test
185    public void testMultiplePackages() {
186        assertTrue(record(mFooBaseUser0));
187        assertTrue(record(mFooSecondary1User0));
188        assertTrue(record(mFooSecondary2UsedByOtherApps0));
189        assertTrue(record(mBarBaseUser0));
190        assertTrue(record(mBarSecondary1User0));
191        assertTrue(record(mBarSecondary2User1));
192
193        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
194        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
195        writeAndReadBack();
196        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
197        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
198    }
199
200    @Test
201    public void testPackageNotFound() {
202        assertNull(mPackageDexUsage.getPackageUseInfo("missing.package"));
203    }
204
205    @Test
206    public void testAttemptToChangeOwner() {
207        assertTrue(record(mFooSecondary1User0));
208        try {
209            record(mFooSecondary1User1);
210            fail("Expected exception");
211        } catch (IllegalArgumentException e) {
212            // expected
213        }
214    }
215
216    @Test
217    public void testInvalidIsa() {
218        try {
219            record(mInvalidIsa);
220            fail("Expected exception");
221        } catch (IllegalArgumentException e) {
222            // expected
223        }
224    }
225
226    @Test
227    public void testReadWriteEmtpy() {
228        // Expect no exceptions when writing/reading without data.
229        writeAndReadBack();
230    }
231
232    @Test
233    public void testSyncData() {
234        // Write some records.
235        assertTrue(record(mFooBaseUser0));
236        assertTrue(record(mFooSecondary1User0));
237        assertTrue(record(mFooSecondary2UsedByOtherApps0));
238        assertTrue(record(mBarBaseUser0));
239        assertTrue(record(mBarSecondary1User0));
240        assertTrue(record(mBarSecondary2User1));
241
242        // Verify all is good.
243        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
244        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
245        writeAndReadBack();
246        assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0);
247        assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1);
248
249        // Simulate that only user 1 is available.
250        Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
251        packageToUsersMap.put(mBarSecondary2User1.mPackageName,
252                new HashSet<>(Arrays.asList(mBarSecondary2User1.mOwnerUserId)));
253        Map<String, Set<String>> packageToCodePaths = new HashMap<>();
254        packageToCodePaths.put(mBarBaseUser0.mPackageName,
255                new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile)));
256        mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths);
257
258        // Assert that only user 1 files are there.
259        assertPackageDexUsage(mBarBaseUser0, mBarSecondary2User1);
260        assertNull(mPackageDexUsage.getPackageUseInfo(mFooBaseUser0.mPackageName));
261    }
262
263    @Test
264    public void testRemovePackage() {
265        // Record Bar secondaries for two different users.
266        assertTrue(record(mBarSecondary1User0));
267        assertTrue(record(mBarSecondary2User1));
268
269        // Remove the package.
270        assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
271        // Assert that we can't find the package anymore.
272        assertNull(mPackageDexUsage.getPackageUseInfo(mBarSecondary1User0.mPackageName));
273    }
274
275    @Test
276    public void testRemoveNonexistentPackage() {
277        // Record Bar secondaries for two different users.
278        assertTrue(record(mBarSecondary1User0));
279
280        // Remove the package.
281        assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
282        // Remove the package again. It should return false because the package no longer
283        // has a record in the use info.
284        assertFalse(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName));
285    }
286
287    @Test
288    public void testRemoveUserPackage() {
289        // Record Bar secondaries for two different users.
290        assertTrue(record(mBarSecondary1User0));
291        assertTrue(record(mBarSecondary2User1));
292
293        // Remove user 0 files.
294        assertTrue(mPackageDexUsage.removeUserPackage(mBarSecondary1User0.mPackageName,
295                mBarSecondary1User0.mOwnerUserId));
296        // Assert that only user 1 files are there.
297        assertPackageDexUsage(null, mBarSecondary2User1);
298    }
299
300    @Test
301    public void testRemoveDexFile() {
302        // Record Bar secondaries for two different users.
303        assertTrue(record(mBarSecondary1User0));
304        assertTrue(record(mBarSecondary2User1));
305
306        // Remove mBarSecondary1User0 file.
307        assertTrue(mPackageDexUsage.removeDexFile(mBarSecondary1User0.mPackageName,
308                mBarSecondary1User0.mDexFile, mBarSecondary1User0.mOwnerUserId));
309        // Assert that only user 1 files are there.
310        assertPackageDexUsage(null, mBarSecondary2User1);
311    }
312
313    @Test
314    public void testClearUsedByOtherApps() {
315        // Write a package which is used by other apps.
316        assertTrue(record(mFooSplit2UsedByOtherApps0));
317        assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
318
319        // Check that the package is no longer used by other apps.
320        TestData noLongerUsedByOtherApps = new TestData(
321            mFooSplit2UsedByOtherApps0.mPackageName,
322            mFooSplit2UsedByOtherApps0.mDexFile,
323            mFooSplit2UsedByOtherApps0.mOwnerUserId,
324            mFooSplit2UsedByOtherApps0.mLoaderIsa,
325            /*mIsUsedByOtherApps*/false,
326            mFooSplit2UsedByOtherApps0.mPrimaryOrSplit,
327            mFooSplit2UsedByOtherApps0.mUsedBy);
328        assertPackageDexUsage(noLongerUsedByOtherApps);
329    }
330
331    @Test
332    public void testClearUsedByOtherAppsNonexistent() {
333        // Write a package which is used by other apps.
334        assertTrue(record(mFooSplit2UsedByOtherApps0));
335        assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
336        // Clearing again should return false as there should be no update on the use info.
337        assertFalse(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName));
338    }
339
340    @Test
341    public void testRecordDexFileUsers() {
342        PackageDexUsage packageDexUsageRecordUsers = new PackageDexUsage();
343        Set<String> users = new HashSet<>(Arrays.asList(
344                new String[] {"another.package.1"}));
345        Set<String> usersExtra = new HashSet<>(Arrays.asList(
346                new String[] {"another.package.2", "another.package.3"}));
347
348        assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, users));
349        assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, usersExtra));
350
351        assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, users));
352        assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, usersExtra));
353
354        packageDexUsageRecordUsers = writeAndReadBack(packageDexUsageRecordUsers);
355        // Verify that the users were recorded.
356        Set<String> userAll = new HashSet<>(users);
357        userAll.addAll(usersExtra);
358        assertPackageDexUsage(packageDexUsageRecordUsers, userAll, mFooSplit2UsedByOtherApps0,
359                mFooSecondary1User0);
360    }
361
362    @Test
363    public void testRecordDexFileUsersNotTheOwningPackage() {
364        PackageDexUsage packageDexUsageRecordUsers = new PackageDexUsage();
365        Set<String> users = new HashSet<>(Arrays.asList(
366                new String[] {mFooSplit2UsedByOtherApps0.mPackageName}));
367        Set<String> usersExtra = new HashSet<>(Arrays.asList(
368                new String[] {"another.package.2", "another.package.3"}));
369
370        assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, users));
371        assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, usersExtra));
372
373        assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, users));
374        assertTrue(record(packageDexUsageRecordUsers, mFooSecondary1User0, usersExtra));
375
376        packageDexUsageRecordUsers = writeAndReadBack(packageDexUsageRecordUsers);
377        // Verify that only the non owning packages were recorded.
378        assertPackageDexUsage(packageDexUsageRecordUsers, usersExtra, mFooSplit2UsedByOtherApps0,
379                mFooSecondary1User0);
380    }
381
382    @Test
383    public void testRecordClassLoaderContextVariableContext() {
384        // Record a secondary dex file.
385        assertTrue(record(mFooSecondary1User0));
386        // Now update its context.
387        TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext(
388                "PCL[new_context.dex]");
389        assertTrue(record(fooSecondary1User0NewContext));
390
391        // Not check that the context was switch to variable.
392        TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext(
393                PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT);
394
395        assertPackageDexUsage(null, expectedContext);
396        writeAndReadBack();
397        assertPackageDexUsage(null, expectedContext);
398    }
399
400    @Test
401    public void testRecordClassLoaderContextUnsupportedContext() {
402        // Record a secondary dex file.
403        assertTrue(record(mFooSecondary1User0));
404        // Now update its context.
405        TestData unsupportedContext = mFooSecondary1User0.updateClassLoaderContext(
406                PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT);
407        assertTrue(record(unsupportedContext));
408
409        assertPackageDexUsage(null, unsupportedContext);
410        writeAndReadBack();
411        assertPackageDexUsage(null, unsupportedContext);
412    }
413
414    @Test
415    public void testRecordClassLoaderContextTransitionFromUnknown() {
416        // Record a secondary dex file.
417        TestData unknownContext = mFooSecondary1User0.updateClassLoaderContext(
418                PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT);
419        assertTrue(record(unknownContext));
420
421        assertPackageDexUsage(null, unknownContext);
422        writeAndReadBack();
423        assertPackageDexUsage(null, unknownContext);
424
425        // Now update the secondary dex record with a class loader context. This simulates the
426        // version 2 to version 3 upgrade.
427
428        assertTrue(record(mFooSecondary1User0));
429
430        assertPackageDexUsage(null, mFooSecondary1User0);
431        writeAndReadBack();
432        assertPackageDexUsage(null, mFooSecondary1User0);
433    }
434
435    @Test
436    public void testDexUsageClassLoaderContext() {
437        final boolean isUsedByOtherApps = false;
438        final int userId = 0;
439        PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId,
440                "valid_context", "arm");
441        assertFalse(validContext.isUnknownClassLoaderContext());
442        assertFalse(validContext.isUnsupportedClassLoaderContext());
443        assertFalse(validContext.isVariableClassLoaderContext());
444
445        PackageDexUsage.DexUseInfo unsupportedContext = new DexUseInfo(isUsedByOtherApps, userId,
446                PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT, "arm");
447        assertFalse(unsupportedContext.isUnknownClassLoaderContext());
448        assertTrue(unsupportedContext.isUnsupportedClassLoaderContext());
449        assertFalse(unsupportedContext.isVariableClassLoaderContext());
450
451        PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId,
452                PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm");
453        assertFalse(variableContext.isUnknownClassLoaderContext());
454        assertFalse(variableContext.isUnsupportedClassLoaderContext());
455        assertTrue(variableContext.isVariableClassLoaderContext());
456
457        PackageDexUsage.DexUseInfo unknownContext = new DexUseInfo(isUsedByOtherApps, userId,
458                PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT, "arm");
459        assertTrue(unknownContext.isUnknownClassLoaderContext());
460        assertFalse(unknownContext.isUnsupportedClassLoaderContext());
461        assertFalse(unknownContext.isVariableClassLoaderContext());
462    }
463
464    @Test
465    public void testReadVersion1() {
466        String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);
467        // Equivalent to
468        //   record(mFooSplit2UsedByOtherApps0);
469        //   record(mFooSecondary1User0);
470        //   record(mFooSecondary2UsedByOtherApps0);
471        //   record(mBarBaseUser0);
472        //   record(mBarSecondary1User0);
473        String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__1\n"
474                + "com.google.foo,1\n"
475                + "#/data/user/0/com.google.foo/sec-1.dex\n"
476                + "0,0," + isa + "\n"
477                + "#/data/user/0/com.google.foo/sec-2.dex\n"
478                + "0,1," + isa + "\n"
479                + "com.google.bar,0\n"
480                + "#/data/user/0/com.google.bar/sec-1.dex\n"
481                + "0,0," + isa + "\n";
482
483        PackageDexUsage packageDexUsage = new PackageDexUsage();
484        try {
485            packageDexUsage.read(new StringReader(content));
486        } catch (IOException e) {
487            fail();
488        }
489
490        // After the read we must sync the data to fill the missing information on the code paths.
491        Map<String, Set<Integer>> packageToUsersMap = new HashMap<>();
492        Map<String, Set<String>> packageToCodePaths = new HashMap<>();
493
494        // Handle foo package.
495        packageToUsersMap.put(mFooSplit2UsedByOtherApps0.mPackageName,
496            new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId)));
497        packageToCodePaths.put(mFooSplit2UsedByOtherApps0.mPackageName,
498            new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mDexFile,
499                mFooSplit1User0.mDexFile, mFooBaseUser0.mDexFile)));
500        // Handle bar package.
501        packageToUsersMap.put(mBarBaseUser0.mPackageName,
502            new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId)));
503        packageToCodePaths.put(mBarBaseUser0.mPackageName,
504            new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile)));
505
506        // Sync the data.
507        packageDexUsage.syncData(packageToUsersMap, packageToCodePaths);
508
509        // Update the class loaders to unknown before asserting if needed. Before version 2 we
510        // didn't have any.
511        String unknown = PackageDexUsage.UNKNOWN_CLASS_LOADER_CONTEXT;
512        TestData fooBaseUser0 = mFooBaseUser0.updateClassLoaderContext(unknown);
513        TestData fooSplit1User0 = mFooSplit1User0.updateClassLoaderContext(unknown);
514        TestData fooSplit2UsedByOtherApps0 =
515            mFooSplit2UsedByOtherApps0.updateClassLoaderContext(unknown);
516        TestData fooSecondary1User0 = mFooSecondary1User0.updateClassLoaderContext(unknown);
517        TestData fooSecondary2UsedByOtherApps0 =
518            mFooSecondary2UsedByOtherApps0.updateClassLoaderContext(unknown);
519        TestData barBaseUser0 = mBarBaseUser0.updateClassLoaderContext(unknown);
520        TestData barSecondary1User0 = mBarSecondary1User0.updateClassLoaderContext(unknown);
521
522        // Assert foo code paths. Note that we ignore the users during upgrade.
523        final Set<String> ignoredUsers = null;
524        assertPackageDexUsage(packageDexUsage, ignoredUsers,
525            fooSplit2UsedByOtherApps0, fooSecondary1User0, fooSecondary2UsedByOtherApps0);
526        // Because fooSplit2UsedByOtherApps0 is used by others, all the other code paths must
527        // share the same data.
528        assertPackageDexUsage(packageDexUsage, ignoredUsers,
529            fooSplit1User0.updateUseByOthers(true),
530            fooSecondary1User0, fooSecondary2UsedByOtherApps0);
531        assertPackageDexUsage(packageDexUsage, ignoredUsers, fooBaseUser0.updateUseByOthers(true),
532            fooSecondary1User0, fooSecondary2UsedByOtherApps0);
533
534        // Assert bar code paths. Note that we ignore the users during upgrade.
535        assertPackageDexUsage(packageDexUsage, ignoredUsers, barBaseUser0, barSecondary1User0);
536    }
537
538    private void assertPackageDexUsage(TestData primary, TestData... secondaries) {
539        assertPackageDexUsage(mPackageDexUsage, null, primary, secondaries);
540    }
541
542    private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users,
543            TestData primary, TestData... secondaries) {
544        String packageName = primary == null ? secondaries[0].mPackageName : primary.mPackageName;
545        boolean primaryUsedByOtherApps = primary != null && primary.mUsedByOtherApps;
546        PackageUseInfo pInfo = packageDexUsage.getPackageUseInfo(packageName);
547
548        // Check package use info
549        assertNotNull(pInfo);
550        if (primary != null) {
551            assertEquals(primaryUsedByOtherApps, pInfo.isUsedByOtherApps(primary.mDexFile));
552            if (users != null) {
553                assertEquals(pInfo.getLoadingPackages(primary.mDexFile), users);
554            }
555        }
556
557        Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap();
558        assertEquals(secondaries.length, dexUseInfoMap.size());
559
560        // Check dex use info
561        for (TestData testData : secondaries) {
562            DexUseInfo dInfo = dexUseInfoMap.get(testData.mDexFile);
563            assertNotNull(dInfo);
564            assertEquals(testData.mUsedByOtherApps, dInfo.isUsedByOtherApps());
565            assertEquals(testData.mOwnerUserId, dInfo.getOwnerUserId());
566            assertEquals(1, dInfo.getLoaderIsas().size());
567            assertTrue(dInfo.getLoaderIsas().contains(testData.mLoaderIsa));
568            if (users != null) {
569                 assertEquals(dInfo.getLoadingPackages(), users);
570            }
571
572            assertEquals(testData.mClassLoaderContext, dInfo.getClassLoaderContext());
573        }
574    }
575
576    private boolean record(TestData testData) {
577        return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile,
578               testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps,
579               testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext);
580    }
581
582    private boolean record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users) {
583        boolean result = true;
584        for (String user : users) {
585            result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile,
586                    testData.mOwnerUserId, testData.mLoaderIsa, testData.mUsedByOtherApps,
587                    testData.mPrimaryOrSplit, user, testData.mClassLoaderContext);
588        }
589        return result;
590    }
591
592    private void writeAndReadBack() {
593        mPackageDexUsage = writeAndReadBack(mPackageDexUsage);
594    }
595
596    private PackageDexUsage writeAndReadBack(PackageDexUsage packageDexUsage) {
597        try {
598            StringWriter writer = new StringWriter();
599            packageDexUsage.write(writer);
600
601            PackageDexUsage newPackageDexUsage = new PackageDexUsage();
602            newPackageDexUsage.read(new StringReader(writer.toString()));
603            return newPackageDexUsage;
604        } catch (IOException e) {
605            fail("Unexpected IOException: " + e.getMessage());
606            return null;
607        }
608    }
609
610    private static class TestData {
611        private final String mPackageName;
612        private final String mDexFile;
613        private final int mOwnerUserId;
614        private final String mLoaderIsa;
615        private final boolean mUsedByOtherApps;
616        private final boolean mPrimaryOrSplit;
617        private final String mUsedBy;
618        private final String mClassLoaderContext;
619
620        private TestData(String packageName, String dexFile, int ownerUserId,
621                String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy) {
622            this(packageName, dexFile, ownerUserId, loaderIsa, isUsedByOtherApps, primaryOrSplit,
623                    usedBy, "DefaultClassLoaderContextFor_" + dexFile);
624        }
625        private TestData(String packageName, String dexFile, int ownerUserId,
626                String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, String usedBy,
627                String classLoaderContext) {
628            mPackageName = packageName;
629            mDexFile = dexFile;
630            mOwnerUserId = ownerUserId;
631            mLoaderIsa = loaderIsa;
632            mUsedByOtherApps = isUsedByOtherApps;
633            mPrimaryOrSplit = primaryOrSplit;
634            mUsedBy = usedBy;
635            mClassLoaderContext = classLoaderContext;
636        }
637
638        private TestData updateClassLoaderContext(String newContext) {
639            return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, mUsedByOtherApps,
640                    mPrimaryOrSplit, mUsedBy, newContext);
641        }
642
643        private TestData updateUseByOthers(boolean newUsedByOthers) {
644            return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, newUsedByOthers,
645                mPrimaryOrSplit, mUsedBy, mClassLoaderContext);
646        }
647    }
648}
649