DexManagerTests.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.content.pm.ApplicationInfo; 20import android.content.pm.PackageInfo; 21import android.os.Build; 22import android.os.UserHandle; 23import android.support.test.filters.SmallTest; 24import android.support.test.runner.AndroidJUnit4; 25 26import dalvik.system.VMRuntime; 27 28import java.util.ArrayList; 29import java.util.Arrays; 30import java.util.HashMap; 31import java.util.List; 32import java.util.Map; 33 34import org.junit.Before; 35import org.junit.Test; 36import org.junit.runner.RunWith; 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 DexManagerTests { 51 private DexManager mDexManager; 52 53 private TestData mFooUser0; 54 private TestData mBarUser0; 55 private TestData mBarUser1; 56 private TestData mInvalidIsa; 57 private TestData mDoesNotExist; 58 59 private int mUser0; 60 private int mUser1; 61 62 @Before 63 public void setup() { 64 65 mUser0 = 0; 66 mUser1 = 1; 67 68 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 69 String foo = "foo"; 70 String bar = "bar"; 71 72 mFooUser0 = new TestData(foo, isa, mUser0); 73 mBarUser0 = new TestData(bar, isa, mUser0); 74 mBarUser1 = new TestData(bar, isa, mUser1); 75 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); 76 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); 77 78 mDexManager = new DexManager(null, null, null, null); 79 80 // Foo and Bar are available to user0. 81 // Only Bar is available to user1; 82 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>(); 83 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo)); 84 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo)); 85 mDexManager.load(existingPackages); 86 } 87 88 @Test 89 public void testNotifyPrimaryUse() { 90 // The main dex file and splits are re-loaded by the app. 91 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 92 93 // Package is not used by others, so we should get nothing back. 94 assertNull(getPackageUseInfo(mFooUser0)); 95 } 96 97 @Test 98 public void testNotifyPrimaryForeignUse() { 99 // Foo loads Bar main apks. 100 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 101 102 // Bar is used by others now and should be in our records 103 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 104 assertNotNull(pui); 105 assertTrue(pui.isUsedByOtherApps()); 106 assertTrue(pui.getDexUseInfoMap().isEmpty()); 107 } 108 109 @Test 110 public void testNotifySecondary() { 111 // Foo loads its own secondary files. 112 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 113 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 114 115 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 116 assertNotNull(pui); 117 assertFalse(pui.isUsedByOtherApps()); 118 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 119 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 120 } 121 122 @Test 123 public void testNotifySecondaryForeign() { 124 // Foo loads bar secondary files. 125 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 126 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 127 128 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 129 assertNotNull(pui); 130 assertFalse(pui.isUsedByOtherApps()); 131 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size()); 132 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 133 } 134 135 @Test 136 public void testNotifySequence() { 137 // Foo loads its own secondary files. 138 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 139 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 140 // Foo loads Bar own secondary files. 141 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 142 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 143 // Foo loads Bar primary files. 144 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 145 // Bar loads its own secondary files. 146 notifyDexLoad(mBarUser0, barSecondaries, mUser0); 147 // Bar loads some own secondary files which foo didn't load. 148 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse(); 149 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0); 150 151 // Check bar usage. Should be used by other app (for primary and barSecondaries). 152 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 153 assertNotNull(pui); 154 assertTrue(pui.isUsedByOtherApps()); 155 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(), 156 pui.getDexUseInfoMap().size()); 157 158 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 159 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse, 160 /*isUsedByOtherApps*/false, mUser0); 161 162 // Check foo usage. Should not be used by other app. 163 pui = getPackageUseInfo(mFooUser0); 164 assertNotNull(pui); 165 assertFalse(pui.isUsedByOtherApps()); 166 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 167 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 168 } 169 170 @Test 171 public void testPackageUseInfoNotFound() { 172 // Assert we don't get back data we did not previously record. 173 assertNull(getPackageUseInfo(mFooUser0)); 174 } 175 176 @Test 177 public void testInvalidIsa() { 178 // Notifying with an invalid ISA should be ignored. 179 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0); 180 assertNull(getPackageUseInfo(mInvalidIsa)); 181 } 182 183 @Test 184 public void testNotExistingPackate() { 185 // Notifying about the load of a package which was previously not 186 // register in DexManager#load should be ignored. 187 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0); 188 assertNull(getPackageUseInfo(mDoesNotExist)); 189 } 190 191 @Test 192 public void testCrossUserAttempt() { 193 // Bar from User1 tries to load secondary dex files from User0 Bar. 194 // Request should be ignored. 195 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1); 196 assertNull(getPackageUseInfo(mBarUser1)); 197 } 198 199 @Test 200 public void testPackageNotInstalledForUser() { 201 // User1 tries to load Foo which is installed for User0 but not for User1. 202 // Note that the PackageManagerService already filters this out but we 203 // still check that nothing goes unexpected in DexManager. 204 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1); 205 assertNull(getPackageUseInfo(mBarUser1)); 206 } 207 208 @Test 209 public void testNotifyPackageInstallUsedByOther() { 210 TestData newPackage = new TestData("newPackage", 211 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 212 213 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 214 // Before we notify about the installation of the newPackage if mFoo 215 // is trying to load something from it we should not find it. 216 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 217 assertNull(getPackageUseInfo(newPackage)); 218 219 // Notify about newPackage install and let mFoo load its dexes. 220 mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0); 221 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 222 223 // We should get back the right info. 224 PackageUseInfo pui = getPackageUseInfo(newPackage); 225 assertNotNull(pui); 226 assertFalse(pui.isUsedByOtherApps()); 227 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 228 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0); 229 } 230 231 @Test 232 public void testNotifyPackageInstallSelfUse() { 233 TestData newPackage = new TestData("newPackage", 234 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 235 236 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 237 // Packages should be able to find their own dex files even if the notification about 238 // their installation is delayed. 239 notifyDexLoad(newPackage, newSecondaries, mUser0); 240 241 PackageUseInfo pui = getPackageUseInfo(newPackage); 242 assertNotNull(pui); 243 assertFalse(pui.isUsedByOtherApps()); 244 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 245 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0); 246 } 247 248 @Test 249 public void testNotifyPackageUpdated() { 250 // Foo loads Bar main apks. 251 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 252 253 // Bar is used by others now and should be in our records. 254 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 255 assertNotNull(pui); 256 assertTrue(pui.isUsedByOtherApps()); 257 assertTrue(pui.getDexUseInfoMap().isEmpty()); 258 259 // Notify that bar is updated. 260 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 261 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 262 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 263 264 // The usedByOtherApps flag should be clear now. 265 pui = getPackageUseInfo(mBarUser0); 266 assertNotNull(pui); 267 assertFalse(pui.isUsedByOtherApps()); 268 } 269 270 @Test 271 public void testNotifyPackageUpdatedCodeLocations() { 272 // Simulate a split update. 273 String newSplit = mBarUser0.replaceLastSplit(); 274 List<String> newSplits = new ArrayList<>(); 275 newSplits.add(newSplit); 276 277 // We shouldn't find yet the new split as we didn't notify the package update. 278 notifyDexLoad(mFooUser0, newSplits, mUser0); 279 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 280 assertNull(pui); 281 282 // Notify that bar is updated. splitSourceDirs will contain the updated path. 283 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 284 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 285 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 286 287 // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers. 288 notifyDexLoad(mFooUser0, newSplits, mUser0); 289 pui = getPackageUseInfo(mBarUser0); 290 assertNotNull(pui); 291 assertTrue(pui.isUsedByOtherApps()); 292 } 293 294 @Test 295 public void testNotifyPackageDataDestroyForOne() { 296 // Bar loads its own secondary files. 297 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 298 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 299 300 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0); 301 302 // Bar should not be around since it was removed for all users. 303 PackageUseInfo pui = getPackageUseInfo(mBarUser1); 304 assertNotNull(pui); 305 assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(), 306 /*isUsedByOtherApps*/false, mUser1); 307 } 308 309 @Test 310 public void testNotifyPackageDataDestroyForeignUse() { 311 // Foo loads its own secondary files. 312 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 313 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 314 315 // Bar loads Foo main apks. 316 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 317 318 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 319 320 // Foo should still be around since it's used by other apps but with no 321 // secondary dex info. 322 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 323 assertNotNull(pui); 324 assertTrue(pui.isUsedByOtherApps()); 325 assertTrue(pui.getDexUseInfoMap().isEmpty()); 326 } 327 328 @Test 329 public void testNotifyPackageDataDestroyComplete() { 330 // Foo loads its own secondary files. 331 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 332 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 333 334 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 335 336 // Foo should not be around since all its secondary dex info were deleted 337 // and it is not used by other apps. 338 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 339 assertNull(pui); 340 } 341 342 @Test 343 public void testNotifyPackageDataDestroyForAll() { 344 // Foo loads its own secondary files. 345 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 346 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 347 348 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL); 349 350 // Bar should not be around since it was removed for all users. 351 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 352 assertNull(pui); 353 } 354 355 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 356 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { 357 for (String dex : secondaries) { 358 DexUseInfo dui = pui.getDexUseInfoMap().get(dex); 359 assertNotNull(dui); 360 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps()); 361 assertEquals(ownerUserId, dui.getOwnerUserId()); 362 assertEquals(1, dui.getLoaderIsas().size()); 363 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); 364 } 365 } 366 367 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { 368 mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, dexPaths, 369 testData.mLoaderIsa, loaderUserId); 370 } 371 372 private PackageUseInfo getPackageUseInfo(TestData testData) { 373 return mDexManager.getPackageUseInfo(testData.mPackageInfo.packageName); 374 } 375 376 private static PackageInfo getMockPackageInfo(String packageName, int userId) { 377 PackageInfo pi = new PackageInfo(); 378 pi.packageName = packageName; 379 pi.applicationInfo = getMockApplicationInfo(packageName, userId); 380 return pi; 381 } 382 383 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) { 384 ApplicationInfo ai = new ApplicationInfo(); 385 String codeDir = "/data/app/" + packageName; 386 ai.setBaseCodePath(codeDir + "/base.dex"); 387 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"}); 388 ai.dataDir = "/data/user/" + userId + "/" + packageName; 389 ai.packageName = packageName; 390 return ai; 391 } 392 393 private static class TestData { 394 private final PackageInfo mPackageInfo; 395 private final String mLoaderIsa; 396 397 private TestData(String packageName, String loaderIsa, int userId) { 398 mPackageInfo = getMockPackageInfo(packageName, userId); 399 mLoaderIsa = loaderIsa; 400 } 401 402 private String getPackageName() { 403 return mPackageInfo.packageName; 404 } 405 406 List<String> getSecondaryDexPaths() { 407 List<String> paths = new ArrayList<>(); 408 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex"); 409 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex"); 410 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex"); 411 return paths; 412 } 413 414 List<String> getSecondaryDexPathsForOwnUse() { 415 List<String> paths = new ArrayList<>(); 416 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex"); 417 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex"); 418 return paths; 419 } 420 421 List<String> getBaseAndSplitDexPaths() { 422 List<String> paths = new ArrayList<>(); 423 paths.add(mPackageInfo.applicationInfo.sourceDir); 424 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) { 425 paths.add(split); 426 } 427 return paths; 428 } 429 430 String replaceLastSplit() { 431 int length = mPackageInfo.applicationInfo.splitSourceDirs.length; 432 // Add an extra bogus dex extension to simulate a new split name. 433 mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex"; 434 return mPackageInfo.applicationInfo.splitSourceDirs[length - 1]; 435 } 436 } 437} 438