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.content.pm.ApplicationInfo; 20 import android.content.pm.IPackageManager; 21 import android.content.pm.PackageInfo; 22 import android.os.Build; 23 import android.os.UserHandle; 24 import android.support.test.filters.SmallTest; 25 import android.support.test.runner.AndroidJUnit4; 26 27 import com.android.server.pm.Installer; 28 29 import dalvik.system.DelegateLastClassLoader; 30 import dalvik.system.PathClassLoader; 31 import dalvik.system.VMRuntime; 32 33 import java.io.File; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collections; 37 import java.util.HashMap; 38 import java.util.List; 39 import java.util.Map; 40 41 import org.junit.Before; 42 import org.junit.Rule; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.mockito.Mock; 46 import org.mockito.junit.MockitoJUnit; 47 import org.mockito.junit.MockitoRule; 48 import org.mockito.quality.Strictness; 49 50 import static org.junit.Assert.assertEquals; 51 import static org.junit.Assert.assertFalse; 52 import static org.junit.Assert.assertNotNull; 53 import static org.junit.Assert.assertNull; 54 import static org.junit.Assert.assertTrue; 55 import static org.junit.Assert.fail; 56 import static org.mockito.ArgumentMatchers.any; 57 import static org.mockito.ArgumentMatchers.anyInt; 58 import static org.mockito.ArgumentMatchers.anyString; 59 import static org.mockito.Mockito.times; 60 import static org.mockito.Mockito.verify; 61 import static org.mockito.Mockito.when; 62 63 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; 64 import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; 65 66 @RunWith(AndroidJUnit4.class) 67 @SmallTest 68 public class DexManagerTests { 69 private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); 70 private static final String DELEGATE_LAST_CLASS_LOADER_NAME = 71 DelegateLastClassLoader.class.getName(); 72 73 @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS); 74 @Mock Installer mInstaller; 75 @Mock IPackageManager mPM; 76 private final Object mInstallLock = new Object(); 77 @Mock DexManager.Listener mListener; 78 79 private DexManager mDexManager; 80 81 private TestData mFooUser0; 82 private TestData mBarUser0; 83 private TestData mBarUser1; 84 private TestData mInvalidIsa; 85 private TestData mDoesNotExist; 86 87 private TestData mBarUser0UnsupportedClassLoader; 88 private TestData mBarUser0DelegateLastClassLoader; 89 90 private int mUser0; 91 private int mUser1; 92 93 @Before 94 public void setup() { 95 mUser0 = 0; 96 mUser1 = 1; 97 98 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 99 String foo = "foo"; 100 String bar = "bar"; 101 102 mFooUser0 = new TestData(foo, isa, mUser0, PATH_CLASS_LOADER_NAME); 103 mBarUser0 = new TestData(bar, isa, mUser0, PATH_CLASS_LOADER_NAME); 104 mBarUser1 = new TestData(bar, isa, mUser1, PATH_CLASS_LOADER_NAME); 105 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); 106 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); 107 108 mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0, 109 "unsupported.class_loader"); 110 mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0, 111 DELEGATE_LAST_CLASS_LOADER_NAME); 112 113 mDexManager = new DexManager( 114 /*Context*/ null, mPM, /*PackageDexOptimizer*/ null, mInstaller, mInstallLock, 115 mListener); 116 117 // Foo and Bar are available to user0. 118 // Only Bar is available to user1; 119 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>(); 120 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo)); 121 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo)); 122 mDexManager.load(existingPackages); 123 } 124 125 @Test 126 public void testNotifyPrimaryUse() { 127 // The main dex file and splits are re-loaded by the app. 128 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 129 130 // Package is not used by others, so we should get nothing back. 131 assertNoUseInfo(mFooUser0); 132 } 133 134 @Test 135 public void testNotifyPrimaryForeignUse() { 136 // Foo loads Bar main apks. 137 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 138 139 // Bar is used by others now and should be in our records 140 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 141 assertIsUsedByOtherApps(mBarUser0, pui, true); 142 assertTrue(pui.getDexUseInfoMap().isEmpty()); 143 } 144 145 @Test 146 public void testNotifySecondary() { 147 // Foo loads its own secondary files. 148 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 149 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 150 151 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 152 assertIsUsedByOtherApps(mFooUser0, pui, false); 153 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 154 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 155 } 156 157 @Test 158 public void testNotifySecondaryForeign() { 159 // Foo loads bar secondary files. 160 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 161 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 162 163 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 164 assertIsUsedByOtherApps(mBarUser0, pui, false); 165 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size()); 166 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 167 } 168 169 @Test 170 public void testNotifySequence() { 171 // Foo loads its own secondary files. 172 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 173 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 174 // Foo loads Bar own secondary files. 175 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 176 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 177 // Foo loads Bar primary files. 178 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 179 // Bar loads its own secondary files. 180 notifyDexLoad(mBarUser0, barSecondaries, mUser0); 181 // Bar loads some own secondary files which foo didn't load. 182 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse(); 183 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0); 184 185 // Check bar usage. Should be used by other app (for primary and barSecondaries). 186 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 187 assertIsUsedByOtherApps(mBarUser0, pui, true); 188 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(), 189 pui.getDexUseInfoMap().size()); 190 191 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 192 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse, 193 /*isUsedByOtherApps*/false, mUser0); 194 195 // Check foo usage. Should not be used by other app. 196 pui = getPackageUseInfo(mFooUser0); 197 assertIsUsedByOtherApps(mFooUser0, pui, false); 198 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 199 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 200 } 201 202 @Test 203 public void testPackageUseInfoNotFound() { 204 // Assert we don't get back data we did not previously record. 205 assertNoUseInfo(mFooUser0); 206 } 207 208 @Test 209 public void testInvalidIsa() { 210 // Notifying with an invalid ISA should be ignored. 211 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0); 212 assertNoUseInfo(mInvalidIsa); 213 } 214 215 @Test 216 public void testNotExistingPackage() { 217 // Notifying about the load of a package which was previously not 218 // register in DexManager#load should be ignored. 219 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0); 220 assertNoUseInfo(mDoesNotExist); 221 } 222 223 @Test 224 public void testCrossUserAttempt() { 225 // Bar from User1 tries to load secondary dex files from User0 Bar. 226 // Request should be ignored. 227 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1); 228 assertNoUseInfo(mBarUser1); 229 } 230 231 @Test 232 public void testPackageNotInstalledForUser() { 233 // User1 tries to load Foo which is installed for User0 but not for User1. 234 // Note that the PackageManagerService already filters this out but we 235 // still check that nothing goes unexpected in DexManager. 236 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1); 237 assertNoUseInfo(mBarUser1); 238 } 239 240 @Test 241 public void testNotifyPackageInstallUsedByOther() { 242 TestData newPackage = new TestData("newPackage", 243 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 244 245 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 246 // Before we notify about the installation of the newPackage if mFoo 247 // is trying to load something from it we should not find it. 248 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 249 assertNoUseInfo(newPackage); 250 251 // Notify about newPackage install and let mFoo load its dexes. 252 mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0); 253 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 254 255 // We should get back the right info. 256 PackageUseInfo pui = getPackageUseInfo(newPackage); 257 assertIsUsedByOtherApps(newPackage, pui, false); 258 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 259 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0); 260 } 261 262 @Test 263 public void testNotifyPackageInstallSelfUse() { 264 TestData newPackage = new TestData("newPackage", 265 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 266 267 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 268 // Packages should be able to find their own dex files even if the notification about 269 // their installation is delayed. 270 notifyDexLoad(newPackage, newSecondaries, mUser0); 271 272 PackageUseInfo pui = getPackageUseInfo(newPackage); 273 assertIsUsedByOtherApps(newPackage, pui, false); 274 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 275 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0); 276 } 277 278 @Test 279 public void testNotifyPackageUpdated() { 280 // Foo loads Bar main apks. 281 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 282 283 // Bar is used by others now and should be in our records. 284 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 285 assertIsUsedByOtherApps(mBarUser0, pui, true); 286 assertTrue(pui.getDexUseInfoMap().isEmpty()); 287 288 // Notify that bar is updated. 289 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 290 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 291 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 292 293 // The usedByOtherApps flag should be clear now. 294 pui = getPackageUseInfo(mBarUser0); 295 assertIsUsedByOtherApps(mBarUser0, pui, false); 296 } 297 298 @Test 299 public void testNotifyPackageUpdatedCodeLocations() { 300 // Simulate a split update. 301 String newSplit = mBarUser0.replaceLastSplit(); 302 List<String> newSplits = new ArrayList<>(); 303 newSplits.add(newSplit); 304 305 // We shouldn't find yet the new split as we didn't notify the package update. 306 notifyDexLoad(mFooUser0, newSplits, mUser0); 307 assertNoUseInfo(mBarUser0); 308 309 // Notify that bar is updated. splitSourceDirs will contain the updated path. 310 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 311 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 312 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 313 314 // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers. 315 notifyDexLoad(mFooUser0, newSplits, mUser0); 316 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 317 assertNotNull(pui); 318 assertIsUsedByOtherApps(newSplits, pui, true); 319 } 320 321 @Test 322 public void testNotifyPackageDataDestroyForOne() { 323 // Bar loads its own secondary files. 324 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 325 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 326 327 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0); 328 329 // Bar should not be around since it was removed for all users. 330 PackageUseInfo pui = getPackageUseInfo(mBarUser1); 331 assertNotNull(pui); 332 assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(), 333 /*isUsedByOtherApps*/false, mUser1); 334 } 335 336 @Test 337 public void testNotifyPackageDataDestroyForeignUse() { 338 // Foo loads its own secondary files. 339 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 340 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 341 342 // Bar loads Foo main apks. 343 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 344 345 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 346 347 // Foo should still be around since it's used by other apps but with no 348 // secondary dex info. 349 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 350 assertIsUsedByOtherApps(mFooUser0, pui, true); 351 assertTrue(pui.getDexUseInfoMap().isEmpty()); 352 } 353 354 @Test 355 public void testNotifyPackageDataDestroyComplete() { 356 // Foo loads its own secondary files. 357 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 358 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 359 360 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 361 362 // Foo should not be around since all its secondary dex info were deleted 363 // and it is not used by other apps. 364 assertNoUseInfo(mFooUser0); 365 } 366 367 @Test 368 public void testNotifyPackageDataDestroyForAll() { 369 // Foo loads its own secondary files. 370 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 371 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 372 373 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL); 374 375 // Bar should not be around since it was removed for all users. 376 assertNoUseInfo(mBarUser0); 377 } 378 379 @Test 380 public void testNotifyFrameworkLoad() { 381 String frameworkDex = "/system/framework/com.android.location.provider.jar"; 382 // Load a dex file from framework. 383 notifyDexLoad(mFooUser0, Arrays.asList(frameworkDex), mUser0); 384 // The dex file should not be recognized as a package. 385 assertFalse(mDexManager.hasInfoOnPackage(frameworkDex)); 386 } 387 388 @Test 389 public void testNotifySecondaryFromProtected() { 390 // Foo loads its own secondary files. 391 List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs(); 392 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 393 394 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 395 assertIsUsedByOtherApps(mFooUser0, pui, false); 396 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 397 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 398 } 399 400 @Test 401 public void testNotifyUnsupportedClassLoader() { 402 List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); 403 notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); 404 405 PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); 406 assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false); 407 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 408 // We expect that all the contexts are unsupported. 409 String[] expectedContexts = 410 Collections.nCopies(secondaries.size(), 411 PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]); 412 assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, 413 /*isUsedByOtherApps*/false, mUser0, expectedContexts); 414 } 415 416 @Test 417 public void testNotifyVariableClassLoader() { 418 // Record bar secondaries with the default PathClassLoader. 419 List<String> secondaries = mBarUser0.getSecondaryDexPaths(); 420 421 notifyDexLoad(mBarUser0, secondaries, mUser0); 422 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 423 assertIsUsedByOtherApps(mBarUser0, pui, false); 424 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 425 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); 426 427 // Record bar secondaries again with a different class loader. This will change the context. 428 notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0); 429 430 pui = getPackageUseInfo(mBarUser0); 431 assertIsUsedByOtherApps(mBarUser0, pui, false); 432 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 433 // We expect that all the contexts to be changed to variable now. 434 String[] expectedContexts = 435 Collections.nCopies(secondaries.size(), 436 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT).toArray(new String[0]); 437 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0, 438 expectedContexts); 439 } 440 441 @Test 442 public void testNotifyUnsupportedClassLoaderDoesNotChange() { 443 List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); 444 notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); 445 446 PackageUseInfo pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); 447 assertIsUsedByOtherApps(mBarUser0UnsupportedClassLoader, pui, false); 448 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 449 // We expect that all the contexts are unsupported. 450 String[] expectedContexts = 451 Collections.nCopies(secondaries.size(), 452 PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT).toArray(new String[0]); 453 assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, 454 /*isUsedByOtherApps*/false, mUser0, expectedContexts); 455 456 // Record bar secondaries again with a different class loader. This will change the context. 457 // However, because the context was already marked as unsupported we should not chage it. 458 notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0); 459 pui = getPackageUseInfo(mBarUser0UnsupportedClassLoader); 460 assertSecondaryUse(mBarUser0UnsupportedClassLoader, pui, secondaries, 461 /*isUsedByOtherApps*/false, mUser0, expectedContexts); 462 463 } 464 465 @Test 466 public void testReconcileSecondaryDexFiles_invokesListener() throws Exception { 467 List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs(); 468 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 469 470 when(mPM.getPackageInfo(mFooUser0.getPackageName(), 0, 0)) 471 .thenReturn(mFooUser0.mPackageInfo); 472 473 mDexManager.reconcileSecondaryDexFiles(mFooUser0.getPackageName()); 474 475 verify(mListener, times(fooSecondaries.size())) 476 .onReconcileSecondaryDexFile(any(ApplicationInfo.class), 477 any(DexUseInfo.class), anyString(), anyInt()); 478 } 479 480 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 481 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, 482 String[] expectedContexts) { 483 assertNotNull(expectedContexts); 484 assertEquals(expectedContexts.length, secondaries.size()); 485 int index = 0; 486 for (String dex : secondaries) { 487 DexUseInfo dui = pui.getDexUseInfoMap().get(dex); 488 assertNotNull(dui); 489 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps()); 490 assertEquals(ownerUserId, dui.getOwnerUserId()); 491 assertEquals(1, dui.getLoaderIsas().size()); 492 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); 493 assertEquals(expectedContexts[index++], dui.getClassLoaderContext()); 494 } 495 } 496 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 497 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { 498 String[] expectedContexts = DexoptUtils.processContextForDexLoad( 499 Arrays.asList(testData.mClassLoader), 500 Arrays.asList(String.join(File.pathSeparator, secondaries))); 501 assertSecondaryUse(testData, pui, secondaries, isUsedByOtherApps, ownerUserId, 502 expectedContexts); 503 } 504 505 private void assertIsUsedByOtherApps(TestData testData, PackageUseInfo pui, 506 boolean isUsedByOtherApps) { 507 assertIsUsedByOtherApps(testData.getBaseAndSplitDexPaths(), pui, isUsedByOtherApps); 508 } 509 510 private void assertIsUsedByOtherApps(List<String> codePaths, PackageUseInfo pui, 511 boolean isUsedByOtherApps) { 512 for (String codePath : codePaths) { 513 assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath)); 514 } 515 } 516 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { 517 // By default, assume a single class loader in the chain. 518 // This makes writing tests much easier. 519 List<String> classLoaders = Arrays.asList(testData.mClassLoader); 520 List<String> classPaths = Arrays.asList(String.join(File.pathSeparator, dexPaths)); 521 notifyDexLoad(testData, classLoaders, classPaths, loaderUserId); 522 } 523 524 private void notifyDexLoad(TestData testData, List<String> classLoader, List<String> classPaths, 525 int loaderUserId) { 526 mDexManager.notifyDexLoad(testData.mPackageInfo.applicationInfo, classLoader, classPaths, 527 testData.mLoaderIsa, loaderUserId); 528 } 529 530 private PackageUseInfo getPackageUseInfo(TestData testData) { 531 assertTrue(mDexManager.hasInfoOnPackage(testData.getPackageName())); 532 return mDexManager.getPackageUseInfoOrDefault(testData.getPackageName()); 533 } 534 535 private void assertNoUseInfo(TestData testData) { 536 assertFalse(mDexManager.hasInfoOnPackage(testData.getPackageName())); 537 } 538 539 private static PackageInfo getMockPackageInfo(String packageName, int userId) { 540 PackageInfo pi = new PackageInfo(); 541 pi.packageName = packageName; 542 pi.applicationInfo = getMockApplicationInfo(packageName, userId); 543 return pi; 544 } 545 546 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) { 547 ApplicationInfo ai = new ApplicationInfo(); 548 String codeDir = "/data/app/" + packageName; 549 ai.setBaseCodePath(codeDir + "/base.dex"); 550 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"}); 551 ai.dataDir = "/data/user/" + userId + "/" + packageName; 552 ai.deviceProtectedDataDir = "/data/user_de/" + userId + "/" + packageName; 553 ai.credentialProtectedDataDir = "/data/user_ce/" + userId + "/" + packageName; 554 ai.packageName = packageName; 555 return ai; 556 } 557 558 private static class TestData { 559 private final PackageInfo mPackageInfo; 560 private final String mLoaderIsa; 561 private final String mClassLoader; 562 563 private TestData(String packageName, String loaderIsa, int userId, String classLoader) { 564 mPackageInfo = getMockPackageInfo(packageName, userId); 565 mLoaderIsa = loaderIsa; 566 mClassLoader = classLoader; 567 } 568 569 private TestData(String packageName, String loaderIsa, int userId) { 570 this(packageName, loaderIsa, userId, PATH_CLASS_LOADER_NAME); 571 } 572 573 private String getPackageName() { 574 return mPackageInfo.packageName; 575 } 576 577 List<String> getSecondaryDexPaths() { 578 List<String> paths = new ArrayList<>(); 579 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex"); 580 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex"); 581 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex"); 582 return paths; 583 } 584 585 List<String> getSecondaryDexPathsForOwnUse() { 586 List<String> paths = new ArrayList<>(); 587 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex"); 588 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex"); 589 return paths; 590 } 591 592 List<String> getSecondaryDexPathsFromProtectedDirs() { 593 List<String> paths = new ArrayList<>(); 594 paths.add(mPackageInfo.applicationInfo.deviceProtectedDataDir + "/secondary6.dex"); 595 paths.add(mPackageInfo.applicationInfo.credentialProtectedDataDir + "/secondary7.dex"); 596 return paths; 597 } 598 599 List<String> getBaseAndSplitDexPaths() { 600 List<String> paths = new ArrayList<>(); 601 paths.add(mPackageInfo.applicationInfo.sourceDir); 602 for (String split : mPackageInfo.applicationInfo.splitSourceDirs) { 603 paths.add(split); 604 } 605 return paths; 606 } 607 608 String replaceLastSplit() { 609 int length = mPackageInfo.applicationInfo.splitSourceDirs.length; 610 // Add an extra bogus dex extension to simulate a new split name. 611 mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex"; 612 return mPackageInfo.applicationInfo.splitSourceDirs[length - 1]; 613 } 614 } 615 } 616