Home | History | Annotate | Download | only in dex
      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 
     17 package com.android.server.pm.dex;
     18 
     19 import android.os.Build;
     20 import android.support.test.filters.SmallTest;
     21 import android.support.test.runner.AndroidJUnit4;
     22 import dalvik.system.VMRuntime;
     23 
     24 import java.util.Collections;
     25 import org.junit.Before;
     26 import org.junit.Test;
     27 import org.junit.runner.RunWith;
     28 
     29 import java.io.IOException;
     30 import java.io.StringReader;
     31 import java.io.StringWriter;
     32 import java.util.Arrays;
     33 import java.util.HashMap;
     34 import java.util.HashSet;
     35 import java.util.Map;
     36 import java.util.Set;
     37 
     38 import static org.junit.Assert.assertEquals;
     39 import static org.junit.Assert.assertFalse;
     40 import static org.junit.Assert.assertNotNull;
     41 import static org.junit.Assert.assertNull;
     42 import static org.junit.Assert.assertTrue;
     43 import static org.junit.Assert.fail;
     44 
     45 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
     46 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
     47 
     48 @RunWith(AndroidJUnit4.class)
     49 @SmallTest
     50 public 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