DexManagerTests.java revision 5a9094c1b6e5797327674d4f12fa1ac4ade7275c
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.content.pm.ApplicationInfo; 21import android.content.pm.PackageInfo; 22import android.support.test.filters.SmallTest; 23import android.support.test.runner.AndroidJUnit4; 24 25import dalvik.system.VMRuntime; 26 27import java.util.ArrayList; 28import java.util.Arrays; 29import java.util.HashMap; 30import java.util.List; 31import java.util.Map; 32 33import org.junit.Before; 34import org.junit.Test; 35import org.junit.runner.RunWith; 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 DexManagerTests { 50 private DexManager mDexManager; 51 52 private TestData mFooUser0; 53 private TestData mBarUser0; 54 private TestData mBarUser1; 55 private TestData mInvalidIsa; 56 private TestData mDoesNotExist; 57 58 private int mUser0; 59 private int mUser1; 60 @Before 61 public void setup() { 62 63 mUser0 = 0; 64 mUser1 = 1; 65 66 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 67 String foo = "foo"; 68 String bar = "bar"; 69 70 mFooUser0 = new TestData(foo, isa, mUser0); 71 mBarUser0 = new TestData(bar, isa, mUser0); 72 mBarUser1 = new TestData(bar, isa, mUser1); 73 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); 74 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); 75 76 77 mDexManager = new DexManager(); 78 79 // Foo and Bar are available to user0. 80 // Only Bar is available to user1; 81 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>(); 82 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo)); 83 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo)); 84 mDexManager.load(existingPackages); 85 } 86 87 @Test 88 public void testNotifyPrimaryUse() { 89 // The main dex file and splits are re-loaded by the app. 90 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 91 92 // Package is not used by others, so we should get nothing back. 93 assertNull(getPackageUseInfo(mFooUser0)); 94 } 95 96 @Test 97 public void testNotifyPrimaryForeignUse() { 98 // Foo loads Bar main apks. 99 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 100 101 // Bar is used by others now and should be in our records 102 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 103 assertNotNull(pui); 104 assertTrue(pui.isUsedByOtherApps()); 105 assertTrue(pui.getDexUseInfoMap().isEmpty()); 106 } 107 108 @Test 109 public void testNotifySecondary() { 110 // Foo loads its own secondary files. 111 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 112 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 113 114 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 115 assertNotNull(pui); 116 assertFalse(pui.isUsedByOtherApps()); 117 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 118 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 119 } 120 121 @Test 122 public void testNotifySecondaryForeign() { 123 // Foo loads bar secondary files. 124 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 125 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 126 127 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 128 assertNotNull(pui); 129 assertFalse(pui.isUsedByOtherApps()); 130 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size()); 131 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 132 } 133 134 @Test 135 public void testNotifySequence() { 136 // Foo loads its own secondary files. 137 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 138 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 139 // Foo loads Bar own secondary files. 140 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 141 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 142 // Foo loads Bar primary files. 143 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 144 // Bar loads its own secondary files. 145 notifyDexLoad(mBarUser0, barSecondaries, mUser0); 146 // Bar loads some own secondary files which foo didn't load. 147 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse(); 148 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0); 149 150 // Check bar usage. Should be used by other app (for primary and barSecondaries). 151 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 152 assertNotNull(pui); 153 assertTrue(pui.isUsedByOtherApps()); 154 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(), 155 pui.getDexUseInfoMap().size()); 156 157 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 158 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse, 159 /*isUsedByOtherApps*/false, mUser0); 160 161 // Check foo usage. Should not be used by other app. 162 pui = getPackageUseInfo(mFooUser0); 163 assertNotNull(pui); 164 assertFalse(pui.isUsedByOtherApps()); 165 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 166 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 167 } 168 169 @Test 170 public void testPackageUseInfoNotFound() { 171 // Assert we don't get back data we did not previously record. 172 assertNull(getPackageUseInfo(mFooUser0)); 173 } 174 175 @Test 176 public void testInvalidIsa() { 177 // Notifying with an invalid ISA should be ignored. 178 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0); 179 assertNull(getPackageUseInfo(mInvalidIsa)); 180 } 181 182 @Test 183 public void testNotExistingPackate() { 184 // Notifying about the load of a package which was previously not 185 // register in DexManager#load should be ignored. 186 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0); 187 assertNull(getPackageUseInfo(mDoesNotExist)); 188 } 189 190 @Test 191 public void testCrossUserAttempt() { 192 // Bar from User1 tries to load secondary dex files from User0 Bar. 193 // Request should be ignored. 194 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1); 195 assertNull(getPackageUseInfo(mBarUser1)); 196 } 197 198 @Test 199 public void testPackageNotInstalledForUser() { 200 // User1 tries to load Foo which is installed for User0 but not for User1. 201 // Note that the PackageManagerService already filters this out but we 202 // still check that nothing goes unexpected in DexManager. 203 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1); 204 assertNull(getPackageUseInfo(mBarUser1)); 205 } 206 207 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 208 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { 209 for (String dex : secondaries) { 210 DexUseInfo dui = pui.getDexUseInfoMap().get(dex); 211 assertNotNull(dui); 212 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps()); 213 assertEquals(ownerUserId, dui.getOwnerUserId()); 214 assertEquals(1, dui.getLoaderIsas().size()); 215 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); 216 } 217 } 218 219 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { 220 mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths, 221 testData.mLoaderIsa, loaderUserId); 222 } 223 224 private PackageUseInfo getPackageUseInfo(TestData testData) { 225 return mDexManager.getPackageUseInfo(testData.mPackageInfo.packageName); 226 } 227 228 private static PackageInfo getMockPackageInfo(String packageName, int userId) { 229 PackageInfo pi = new PackageInfo(); 230 pi.packageName = packageName; 231 pi.applicationInfo = getMockApplicationInfo(packageName, userId); 232 return pi; 233 } 234 235 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) { 236 ApplicationInfo ai = new ApplicationInfo(); 237 String codeDir = "/data/app/" + packageName; 238 ai.setBaseCodePath(codeDir + "/base.dex"); 239 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"}); 240 ai.dataDir = "/data/user/" + userId + "/" + packageName; 241 ai.packageName = packageName; 242 return ai; 243 } 244 245 private static class TestData { 246 private final PackageInfo mPackageInfo; 247 private final String mLoaderIsa; 248 249 private TestData(String packageName, String loaderIsa, int userId) { 250 mPackageInfo = getMockPackageInfo(packageName, userId); 251 mLoaderIsa = loaderIsa; 252 } 253 254 private String getPackageName() { 255 return mPackageInfo.packageName; 256 } 257 258 List<String> getSecondaryDexPaths() { 259 List<String> paths = new ArrayList<>(); 260 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex"); 261 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex"); 262 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex"); 263 return paths; 264 } 265 266 List<String> getSecondaryDexPathsForOwnUse() { 267 List<String> paths = new ArrayList<>(); 268 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex"); 269 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex"); 270 return paths; 271 } 272 273 List<String> getBaseAndSplitDexPaths() { 274 List<String> paths = new ArrayList<>(); 275 paths.add(mPackageInfo.applicationInfo.sourceDir); 276 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) { 277 paths.add(split); 278 } 279 return paths; 280 } 281 } 282} 283