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 static com.android.server.pm.dex.PackageDexUsage.DexUseInfo; 20 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; 21 import static com.android.server.pm.dex.PackageDynamicCodeLoading.DynamicCodeFile; 22 import static com.android.server.pm.dex.PackageDynamicCodeLoading.PackageDynamicCode; 23 24 import static org.junit.Assert.assertEquals; 25 import static org.junit.Assert.assertFalse; 26 import static org.junit.Assert.assertNotEquals; 27 import static org.junit.Assert.assertNotNull; 28 import static org.junit.Assert.assertNull; 29 import static org.junit.Assert.assertTrue; 30 31 import android.content.Context; 32 import android.content.pm.ApplicationInfo; 33 import android.content.pm.IPackageManager; 34 import android.content.pm.PackageInfo; 35 import android.content.pm.PackageManager; 36 import android.content.res.Resources; 37 import android.os.BatteryManager; 38 import android.os.Build; 39 import android.os.PowerManager; 40 import android.os.UserHandle; 41 42 import androidx.test.filters.SmallTest; 43 import androidx.test.runner.AndroidJUnit4; 44 45 import com.android.dx.mockito.inline.extended.ExtendedMockito; 46 import com.android.dx.mockito.inline.extended.StaticMockitoSession; 47 import com.android.server.pm.Installer; 48 import com.android.server.pm.PackageManagerService; 49 50 import dalvik.system.DelegateLastClassLoader; 51 import dalvik.system.PathClassLoader; 52 import dalvik.system.VMRuntime; 53 54 import org.junit.After; 55 import org.junit.Before; 56 import org.junit.Test; 57 import org.junit.runner.RunWith; 58 import org.mockito.Mock; 59 import org.mockito.quality.Strictness; 60 61 import java.io.File; 62 import java.util.ArrayList; 63 import java.util.Arrays; 64 import java.util.Collection; 65 import java.util.Collections; 66 import java.util.HashMap; 67 import java.util.List; 68 import java.util.Map; 69 70 @RunWith(AndroidJUnit4.class) 71 @SmallTest 72 public class DexManagerTests { 73 private static final String PATH_CLASS_LOADER_NAME = PathClassLoader.class.getName(); 74 private static final String DELEGATE_LAST_CLASS_LOADER_NAME = 75 DelegateLastClassLoader.class.getName(); 76 private static final String UNSUPPORTED_CLASS_LOADER_NAME = "unsupported.class_loader"; 77 78 private static final int TEST_BATTERY_LEVEL_CRITICAL = 10; 79 private static final int TEST_BATTERY_LEVEL_DEFAULT = 80; 80 81 public StaticMockitoSession mMockitoSession; 82 @Mock Installer mInstaller; 83 @Mock IPackageManager mPM; 84 @Mock BatteryManager mMockBatteryManager; 85 @Mock PowerManager mMockPowerManager; 86 87 private final Object mInstallLock = new Object(); 88 89 private DexManager mDexManager; 90 91 private TestData mFooUser0; 92 private TestData mBarUser0; 93 private TestData mBarUser1; 94 private TestData mInvalidIsa; 95 private TestData mDoesNotExist; 96 97 private TestData mBarUser0UnsupportedClassLoader; 98 private TestData mBarUser0DelegateLastClassLoader; 99 100 private TestData mSystemServerJar; 101 private TestData mSystemServerJarUpdatedContext; 102 private TestData mSystemServerJarInvalid; 103 104 private int mUser0; 105 private int mUser1; 106 107 @Before setup()108 public void setup() { 109 mUser0 = 0; 110 mUser1 = 1; 111 112 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 113 String foo = "foo"; 114 String bar = "bar"; 115 116 mFooUser0 = new TestData(foo, isa, mUser0, PATH_CLASS_LOADER_NAME); 117 mBarUser0 = new TestData(bar, isa, mUser0, PATH_CLASS_LOADER_NAME); 118 mBarUser1 = new TestData(bar, isa, mUser1, PATH_CLASS_LOADER_NAME); 119 mInvalidIsa = new TestData("INVALID", "INVALID_ISA", mUser0); 120 mDoesNotExist = new TestData("DOES.NOT.EXIST", isa, mUser1); 121 122 mBarUser0UnsupportedClassLoader = new TestData(bar, isa, mUser0, 123 UNSUPPORTED_CLASS_LOADER_NAME); 124 mBarUser0DelegateLastClassLoader = new TestData(bar, isa, mUser0, 125 DELEGATE_LAST_CLASS_LOADER_NAME); 126 127 mSystemServerJar = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME); 128 mSystemServerJarInvalid = new TestData("android", isa, mUser0, PATH_CLASS_LOADER_NAME); 129 mSystemServerJarUpdatedContext = new TestData("android", isa, mUser0, 130 DELEGATE_LAST_CLASS_LOADER_NAME); 131 132 // Initialize Static Mocking 133 134 mMockitoSession = ExtendedMockito.mockitoSession() 135 .initMocks(this) 136 .strictness(Strictness.LENIENT) 137 .startMocking(); 138 139 // Mock.... 140 141 mMockBatteryManager = ExtendedMockito.mock(BatteryManager.class); 142 mMockPowerManager = ExtendedMockito.mock(PowerManager.class); 143 144 setDefaultMockValues(); 145 146 Resources mockResources = ExtendedMockito.mock(Resources.class); 147 ExtendedMockito.when(mockResources 148 .getInteger(com.android.internal.R.integer.config_criticalBatteryWarningLevel)) 149 .thenReturn(15); 150 151 Context mockContext = ExtendedMockito.mock(Context.class); 152 ExtendedMockito.doReturn(mockResources) 153 .when(mockContext) 154 .getResources(); 155 ExtendedMockito.doReturn(mMockBatteryManager) 156 .when(mockContext) 157 .getSystemService(BatteryManager.class); 158 ExtendedMockito.doReturn(mMockPowerManager) 159 .when(mockContext) 160 .getSystemService(PowerManager.class); 161 162 mDexManager = new DexManager(mockContext, /*PackageDexOptimizer*/ null, 163 mInstaller, mInstallLock, mPM); 164 165 // Foo and Bar are available to user0. 166 // Only Bar is available to user1; 167 Map<Integer, List<PackageInfo>> existingPackages = new HashMap<>(); 168 existingPackages.put(mUser0, Arrays.asList(mFooUser0.mPackageInfo, mBarUser0.mPackageInfo)); 169 existingPackages.put(mUser1, Arrays.asList(mBarUser1.mPackageInfo)); 170 mDexManager.load(existingPackages); 171 } 172 173 @After teardown()174 public void teardown() throws Exception { 175 mMockitoSession.finishMocking(); 176 } 177 setDefaultMockValues()178 private void setDefaultMockValues() { 179 ExtendedMockito.doReturn(BatteryManager.BATTERY_STATUS_DISCHARGING) 180 .when(mMockBatteryManager) 181 .getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS); 182 183 ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_DEFAULT) 184 .when(mMockBatteryManager) 185 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); 186 187 ExtendedMockito.doReturn(PowerManager.THERMAL_STATUS_NONE) 188 .when(mMockPowerManager) 189 .getCurrentThermalStatus(); 190 } 191 192 @Test testNotifyPrimaryUse()193 public void testNotifyPrimaryUse() { 194 // The main dex file and splits are re-loaded by the app. 195 notifyDexLoad(mFooUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 196 197 // Package is not used by others, so we should get nothing back. 198 assertNoUseInfo(mFooUser0); 199 200 // A package loading its own code is not stored as DCL. 201 assertNoDclInfo(mFooUser0); 202 } 203 204 @Test testNotifyPrimaryForeignUse()205 public void testNotifyPrimaryForeignUse() { 206 // Foo loads Bar main apks. 207 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 208 209 // Bar is used by others now and should be in our records 210 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 211 assertIsUsedByOtherApps(mBarUser0, pui, true); 212 assertTrue(pui.getDexUseInfoMap().isEmpty()); 213 214 // A package loading another package's APK is not DCL (it's not app data). 215 assertNoDclInfo(mBarUser0); 216 } 217 218 @Test testNotifySecondary()219 public void testNotifySecondary() { 220 // Foo loads its own secondary files. 221 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 222 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 223 224 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 225 assertIsUsedByOtherApps(mFooUser0, pui, false); 226 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 227 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 228 229 assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); 230 } 231 232 @Test testNotifyPrimaryAndSecondary()233 public void testNotifyPrimaryAndSecondary() { 234 List<String> dexFiles = mFooUser0.getBaseAndSplitDexPaths(); 235 List<String> secondaries = mFooUser0.getSecondaryDexPaths(); 236 int baseAndSplitCount = dexFiles.size(); 237 dexFiles.addAll(secondaries); 238 239 notifyDexLoad(mFooUser0, dexFiles, mUser0); 240 241 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 242 assertIsUsedByOtherApps(mFooUser0, pui, false); 243 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 244 245 String[] allExpectedContexts = DexoptUtils.processContextForDexLoad( 246 Arrays.asList(mFooUser0.mClassLoader), 247 Arrays.asList(String.join(File.pathSeparator, dexFiles))); 248 String[] secondaryExpectedContexts = Arrays.copyOfRange(allExpectedContexts, 249 baseAndSplitCount, dexFiles.size()); 250 251 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0, 252 secondaryExpectedContexts); 253 254 assertHasDclInfo(mFooUser0, mFooUser0, secondaries); 255 } 256 257 @Test testNotifySecondaryForeign()258 public void testNotifySecondaryForeign() { 259 // Foo loads bar secondary files. 260 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 261 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 262 263 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 264 assertIsUsedByOtherApps(mBarUser0, pui, false); 265 assertEquals(barSecondaries.size(), pui.getDexUseInfoMap().size()); 266 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 267 268 assertHasDclInfo(mBarUser0, mFooUser0, barSecondaries); 269 } 270 271 @Test testNotifySequence()272 public void testNotifySequence() { 273 // Foo loads its own secondary files. 274 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 275 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 276 // Foo loads Bar own secondary files. 277 List<String> barSecondaries = mBarUser0.getSecondaryDexPaths(); 278 notifyDexLoad(mFooUser0, barSecondaries, mUser0); 279 // Foo loads Bar primary files. 280 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 281 // Bar loads its own secondary files. 282 notifyDexLoad(mBarUser0, barSecondaries, mUser0); 283 // Bar loads some own secondary files which foo didn't load. 284 List<String> barSecondariesForOwnUse = mBarUser0.getSecondaryDexPathsForOwnUse(); 285 notifyDexLoad(mBarUser0, barSecondariesForOwnUse, mUser0); 286 287 // Check bar usage. Should be used by other app (for primary and barSecondaries). 288 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 289 assertIsUsedByOtherApps(mBarUser0, pui, true); 290 assertEquals(barSecondaries.size() + barSecondariesForOwnUse.size(), 291 pui.getDexUseInfoMap().size()); 292 293 assertSecondaryUse(mFooUser0, pui, barSecondaries, /*isUsedByOtherApps*/true, mUser0); 294 assertSecondaryUse(mFooUser0, pui, barSecondariesForOwnUse, 295 /*isUsedByOtherApps*/false, mUser0); 296 297 // Check foo usage. Should not be used by other app. 298 pui = getPackageUseInfo(mFooUser0); 299 assertIsUsedByOtherApps(mFooUser0, pui, false); 300 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 301 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 302 } 303 304 @Test testNoNotify()305 public void testNoNotify() { 306 // Assert we don't get back data we did not previously record. 307 assertNoUseInfo(mFooUser0); 308 assertNoDclInfo(mFooUser0); 309 } 310 311 @Test testInvalidIsa()312 public void testInvalidIsa() { 313 // Notifying with an invalid ISA should be ignored. 314 notifyDexLoad(mInvalidIsa, mInvalidIsa.getSecondaryDexPaths(), mUser0); 315 assertNoUseInfo(mInvalidIsa); 316 assertNoDclInfo(mInvalidIsa); 317 } 318 319 @Test testNotExistingPackage()320 public void testNotExistingPackage() { 321 // Notifying about the load of a package which was previously not 322 // register in DexManager#load should be ignored. 323 notifyDexLoad(mDoesNotExist, mDoesNotExist.getBaseAndSplitDexPaths(), mUser0); 324 assertNoUseInfo(mDoesNotExist); 325 assertNoDclInfo(mDoesNotExist); 326 } 327 328 @Test testCrossUserAttempt()329 public void testCrossUserAttempt() { 330 // Bar from User1 tries to load secondary dex files from User0 Bar. 331 // Request should be ignored. 332 notifyDexLoad(mBarUser1, mBarUser0.getSecondaryDexPaths(), mUser1); 333 assertNoUseInfo(mBarUser1); 334 335 assertNoDclInfo(mBarUser1); 336 } 337 338 @Test testPackageNotInstalledForUser()339 public void testPackageNotInstalledForUser() { 340 // User1 tries to load Foo which is installed for User0 but not for User1. 341 // Note that the PackageManagerService already filters this out but we 342 // still check that nothing goes unexpected in DexManager. 343 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser1); 344 assertNoUseInfo(mBarUser1); 345 assertNoUseInfo(mFooUser0); 346 347 assertNoDclInfo(mBarUser1); 348 assertNoDclInfo(mFooUser0); 349 } 350 351 @Test testNotifyPackageInstallUsedByOther()352 public void testNotifyPackageInstallUsedByOther() { 353 TestData newPackage = new TestData("newPackage", 354 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 355 356 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 357 // Before we notify about the installation of the newPackage if mFoo 358 // is trying to load something from it we should not find it. 359 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 360 assertNoUseInfo(newPackage); 361 assertNoDclInfo(newPackage); 362 363 // Notify about newPackage install and let mFoo load its dexes. 364 mDexManager.notifyPackageInstalled(newPackage.mPackageInfo, mUser0); 365 notifyDexLoad(mFooUser0, newSecondaries, mUser0); 366 367 // We should get back the right info. 368 PackageUseInfo pui = getPackageUseInfo(newPackage); 369 assertIsUsedByOtherApps(newPackage, pui, false); 370 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 371 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/true, mUser0); 372 assertHasDclInfo(newPackage, mFooUser0, newSecondaries); 373 } 374 375 @Test testNotifyPackageInstallSelfUse()376 public void testNotifyPackageInstallSelfUse() { 377 TestData newPackage = new TestData("newPackage", 378 VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]), mUser0); 379 380 List<String> newSecondaries = newPackage.getSecondaryDexPaths(); 381 // Packages should be able to find their own dex files even if the notification about 382 // their installation is delayed. 383 notifyDexLoad(newPackage, newSecondaries, mUser0); 384 385 PackageUseInfo pui = getPackageUseInfo(newPackage); 386 assertIsUsedByOtherApps(newPackage, pui, false); 387 assertEquals(newSecondaries.size(), pui.getDexUseInfoMap().size()); 388 assertSecondaryUse(newPackage, pui, newSecondaries, /*isUsedByOtherApps*/false, mUser0); 389 assertHasDclInfo(newPackage, newPackage, newSecondaries); 390 } 391 392 @Test testNotifyPackageUpdated()393 public void testNotifyPackageUpdated() { 394 // Foo loads Bar main apks. 395 notifyDexLoad(mFooUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0); 396 397 // Bar is used by others now and should be in our records. 398 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 399 assertIsUsedByOtherApps(mBarUser0, pui, true); 400 assertTrue(pui.getDexUseInfoMap().isEmpty()); 401 402 // Notify that bar is updated. 403 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 404 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 405 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 406 407 // The usedByOtherApps flag should be clear now. 408 pui = getPackageUseInfo(mBarUser0); 409 assertIsUsedByOtherApps(mBarUser0, pui, false); 410 } 411 412 @Test testNotifyUsedByIsolatedProcess()413 public void testNotifyUsedByIsolatedProcess() { 414 // Bar loads its own apk but as isolatedProcess. 415 notifyDexLoad(mBarUser0, mBarUser0.getBaseAndSplitDexPaths(), mUser0, 416 /*isolatedProcess=*/ true); 417 418 // Bar is used by an isolated process and should be marked as usedByOtherApps 419 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 420 assertIsUsedByOtherApps(mBarUser0, pui, true); 421 } 422 423 @Test testNotifyPackageUpdatedCodeLocations()424 public void testNotifyPackageUpdatedCodeLocations() { 425 // Simulate a split update. 426 String newSplit = mBarUser0.replaceLastSplit(); 427 List<String> newSplits = new ArrayList<>(); 428 newSplits.add(newSplit); 429 430 // We shouldn't find yet the new split as we didn't notify the package update. 431 notifyDexLoad(mFooUser0, newSplits, mUser0); 432 assertNoUseInfo(mBarUser0); 433 assertNoDclInfo(mBarUser0); 434 435 // Notify that bar is updated. splitSourceDirs will contain the updated path. 436 mDexManager.notifyPackageUpdated(mBarUser0.getPackageName(), 437 mBarUser0.mPackageInfo.applicationInfo.sourceDir, 438 mBarUser0.mPackageInfo.applicationInfo.splitSourceDirs); 439 440 // Now, when the split is loaded we will find it and we should mark Bar as usedByOthers. 441 notifyDexLoad(mFooUser0, newSplits, mUser0); 442 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 443 assertIsUsedByOtherApps(newSplits, pui, true); 444 445 // Primary and split APKs are not recorded as DCL. 446 assertNoDclInfo(mBarUser0); 447 } 448 449 @Test testNotifyPackageDataDestroyForOne()450 public void testNotifyPackageDataDestroyForOne() { 451 // Bar loads its own secondary files. 452 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 453 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 454 455 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), mUser0); 456 457 // Data for user 1 should still be present 458 PackageUseInfo pui = getPackageUseInfo(mBarUser1); 459 assertSecondaryUse(mBarUser1, pui, mBarUser1.getSecondaryDexPaths(), 460 /*isUsedByOtherApps*/false, mUser1); 461 assertHasDclInfo(mBarUser1, mBarUser1, mBarUser1.getSecondaryDexPaths()); 462 463 // But not user 0 464 assertNoUseInfo(mBarUser0, mUser0); 465 assertNoDclInfo(mBarUser0, mUser0); 466 } 467 468 @Test testNotifyPackageDataDestroyForeignUse()469 public void testNotifyPackageDataDestroyForeignUse() { 470 // Foo loads its own secondary files. 471 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 472 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 473 474 // Bar loads Foo main apks. 475 notifyDexLoad(mBarUser0, mFooUser0.getBaseAndSplitDexPaths(), mUser0); 476 477 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 478 479 // Foo should still be around since it's used by other apps but with no 480 // secondary dex info. 481 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 482 assertIsUsedByOtherApps(mFooUser0, pui, true); 483 assertTrue(pui.getDexUseInfoMap().isEmpty()); 484 485 assertNoDclInfo(mFooUser0); 486 } 487 488 @Test testNotifyPackageDataDestroyComplete()489 public void testNotifyPackageDataDestroyComplete() { 490 // Foo loads its own secondary files. 491 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 492 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 493 494 mDexManager.notifyPackageDataDestroyed(mFooUser0.getPackageName(), mUser0); 495 496 // Foo should not be around since all its secondary dex info were deleted 497 // and it is not used by other apps. 498 assertNoUseInfo(mFooUser0); 499 assertNoDclInfo(mFooUser0); 500 } 501 502 @Test testNotifyPackageDataDestroyForAll()503 public void testNotifyPackageDataDestroyForAll() { 504 // Foo loads its own secondary files. 505 notifyDexLoad(mBarUser0, mBarUser0.getSecondaryDexPaths(), mUser0); 506 notifyDexLoad(mBarUser1, mBarUser1.getSecondaryDexPaths(), mUser1); 507 508 mDexManager.notifyPackageDataDestroyed(mBarUser0.getPackageName(), UserHandle.USER_ALL); 509 510 // Bar should not be around since it was removed for all users. 511 assertNoUseInfo(mBarUser0); 512 assertNoDclInfo(mBarUser0); 513 } 514 515 @Test testNotifyFrameworkLoad()516 public void testNotifyFrameworkLoad() { 517 String frameworkDex = "/system/framework/com.android.location.provider.jar"; 518 // Load a dex file from framework. 519 notifyDexLoad(mFooUser0, Arrays.asList(frameworkDex), mUser0); 520 // The dex file should not be recognized as owned by the package. 521 assertFalse(mDexManager.hasInfoOnPackage(mFooUser0.getPackageName())); 522 523 assertNull(getPackageDynamicCodeInfo(mFooUser0)); 524 } 525 526 @Test testNotifySecondaryFromProtected()527 public void testNotifySecondaryFromProtected() { 528 // Foo loads its own secondary files. 529 List<String> fooSecondaries = mFooUser0.getSecondaryDexPathsFromProtectedDirs(); 530 notifyDexLoad(mFooUser0, fooSecondaries, mUser0); 531 532 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 533 assertIsUsedByOtherApps(mFooUser0, pui, false); 534 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 535 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0); 536 537 assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); 538 } 539 540 @Test testNotifyUnsupportedClassLoader()541 public void testNotifyUnsupportedClassLoader() { 542 List<String> secondaries = mBarUser0UnsupportedClassLoader.getSecondaryDexPaths(); 543 notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); 544 545 // We don't record the dex usage 546 assertNoUseInfo(mBarUser0UnsupportedClassLoader); 547 548 // But we do record this as an intance of dynamic code loading 549 assertHasDclInfo( 550 mBarUser0UnsupportedClassLoader, mBarUser0UnsupportedClassLoader, secondaries); 551 } 552 553 @Test testNotifySupportedAndUnsupportedClassLoader()554 public void testNotifySupportedAndUnsupportedClassLoader() { 555 String classPath = String.join(File.pathSeparator, mBarUser0.getSecondaryDexPaths()); 556 List<String> classLoaders = 557 Arrays.asList(PATH_CLASS_LOADER_NAME, UNSUPPORTED_CLASS_LOADER_NAME); 558 List<String> classPaths = Arrays.asList(classPath, classPath); 559 notifyDexLoad(mBarUser0, classLoaders, classPaths, mUser0, /*isolatedProcess=*/ false); 560 561 assertNoUseInfo(mBarUser0); 562 563 assertHasDclInfo(mBarUser0, mBarUser0, mBarUser0.getSecondaryDexPaths()); 564 } 565 566 @Test testNotifyNullClassPath()567 public void testNotifyNullClassPath() { 568 notifyDexLoad(mBarUser0, null, mUser0); 569 570 assertNoUseInfo(mBarUser0); 571 assertNoDclInfo(mBarUser0); 572 } 573 574 @Test testNotifyVariableClassLoader()575 public void testNotifyVariableClassLoader() { 576 // Record bar secondaries with the default PathClassLoader. 577 List<String> secondaries = mBarUser0.getSecondaryDexPaths(); 578 579 notifyDexLoad(mBarUser0, secondaries, mUser0); 580 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 581 assertIsUsedByOtherApps(mBarUser0, pui, false); 582 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 583 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); 584 585 // Record bar secondaries again with a different class loader. This will change the context. 586 notifyDexLoad(mBarUser0DelegateLastClassLoader, secondaries, mUser0); 587 588 pui = getPackageUseInfo(mBarUser0); 589 assertIsUsedByOtherApps(mBarUser0, pui, false); 590 assertEquals(secondaries.size(), pui.getDexUseInfoMap().size()); 591 // We expect that all the contexts to be changed to variable now. 592 String[] expectedContexts = 593 Collections.nCopies(secondaries.size(), 594 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT).toArray(new String[0]); 595 assertSecondaryUse(mFooUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0, 596 expectedContexts); 597 } 598 599 @Test testSystemServerOverwritesContext()600 public void testSystemServerOverwritesContext() { 601 // Record bar secondaries with the default PathClassLoader. 602 List<String> secondaries = mSystemServerJar.getSecondaryDexPaths(); 603 604 notifyDexLoad(mSystemServerJar, secondaries, mUser0); 605 PackageUseInfo pui = getPackageUseInfo(mSystemServerJar); 606 assertSecondaryUse(mSystemServerJar, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); 607 608 // Record bar secondaries again with a different class loader. This will change the context. 609 notifyDexLoad(mSystemServerJarUpdatedContext, secondaries, mUser0); 610 611 pui = getPackageUseInfo(mSystemServerJar); 612 // We expect that all the contexts to be updated according to the last notify. 613 assertSecondaryUse(mSystemServerJarUpdatedContext, pui, secondaries, 614 /*isUsedByOtherApps*/false, mUser0); 615 } 616 617 @Test testNotifyUnsupportedClassLoaderDoesNotChangeExisting()618 public void testNotifyUnsupportedClassLoaderDoesNotChangeExisting() { 619 List<String> secondaries = mBarUser0.getSecondaryDexPaths(); 620 621 notifyDexLoad(mBarUser0, secondaries, mUser0); 622 PackageUseInfo pui = getPackageUseInfo(mBarUser0); 623 assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); 624 assertHasDclInfo(mBarUser0, mBarUser0, secondaries); 625 626 // Record bar secondaries again with an unsupported class loader. This should not change the 627 // context. 628 notifyDexLoad(mBarUser0UnsupportedClassLoader, secondaries, mUser0); 629 pui = getPackageUseInfo(mBarUser0); 630 assertSecondaryUse(mBarUser0, pui, secondaries, /*isUsedByOtherApps*/false, mUser0); 631 assertHasDclInfo(mBarUser0, mBarUser0, secondaries); 632 } 633 634 @Test testPrimaryAndSecondaryDexLoad()635 public void testPrimaryAndSecondaryDexLoad() { 636 // Foo loads both primary and secondary dexes 637 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 638 List<String> fooDexes = new ArrayList<>(mFooUser0.getBaseAndSplitDexPaths()); 639 int primaryCount = fooDexes.size(); 640 fooDexes.addAll(fooSecondaries); 641 642 notifyDexLoad(mFooUser0, fooDexes, mUser0); 643 644 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 645 assertIsUsedByOtherApps(mFooUser0, pui, false); 646 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 647 648 // Below we want to verify that the secondary dex files within fooDexes have been correctly 649 // reported and their class loader contexts were correctly recorded. 650 // 651 // In order to achieve this we first use DexoptUtils.processContextForDexLoad to compute the 652 // class loader contexts for all the dex files. 653 String[] allClassLoaderContexts = DexoptUtils.processContextForDexLoad( 654 Arrays.asList(mFooUser0.mClassLoader), 655 Arrays.asList(String.join(File.pathSeparator, fooDexes))); 656 // Next we filter out the class loader contexts corresponding to non-secondary dex files. 657 String[] secondaryClassLoaderContexts = Arrays.copyOfRange(allClassLoaderContexts, 658 primaryCount, allClassLoaderContexts.length); 659 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0, 660 secondaryClassLoaderContexts); 661 662 assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); 663 } 664 665 @Test testNotifySecondary_withSharedLibrary()666 public void testNotifySecondary_withSharedLibrary() { 667 // Foo loads its own secondary files. 668 List<String> fooSecondaries = mFooUser0.getSecondaryDexPaths(); 669 670 String contextSuffix = "{PCL[/system/framework/org.apache.http.legacy.jar]}"; 671 String[] expectedContexts = DexoptUtils.processContextForDexLoad( 672 Arrays.asList(mFooUser0.mClassLoader), 673 Arrays.asList(String.join(File.pathSeparator, fooSecondaries))); 674 for (int i = 0; i < expectedContexts.length; i++) { 675 expectedContexts[i] += contextSuffix; 676 } 677 678 notifyDexLoad(mFooUser0, fooSecondaries, expectedContexts, mUser0, 679 /*isolatedProcess=*/ false); 680 681 PackageUseInfo pui = getPackageUseInfo(mFooUser0); 682 assertIsUsedByOtherApps(mFooUser0, pui, false); 683 assertEquals(fooSecondaries.size(), pui.getDexUseInfoMap().size()); 684 assertSecondaryUse(mFooUser0, pui, fooSecondaries, /*isUsedByOtherApps*/false, mUser0, 685 expectedContexts); 686 687 assertHasDclInfo(mFooUser0, mFooUser0, fooSecondaries); 688 } 689 690 691 @Test testNotifySystemServerUse()692 public void testNotifySystemServerUse() { 693 List<String> dexFiles = new ArrayList<String>(); 694 dexFiles.add("/system/framework/foo"); 695 notifyDexLoad(mSystemServerJar, dexFiles, mUser0); 696 PackageUseInfo pui = getPackageUseInfo(mSystemServerJar); 697 assertIsUsedByOtherApps(mSystemServerJar, pui, false); 698 } 699 700 @Test testNotifySystemServerInvalidUse()701 public void testNotifySystemServerInvalidUse() { 702 List<String> dexFiles = new ArrayList<String>(); 703 dexFiles.add("/data/foo"); 704 notifyDexLoad(mSystemServerJarInvalid, dexFiles, mUser0); 705 assertNoUseInfo(mSystemServerJarInvalid); 706 assertNoDclInfo(mSystemServerJarInvalid); 707 } 708 709 @Test testInstallScenarioToReasonDefault()710 public void testInstallScenarioToReasonDefault() { 711 assertEquals( 712 PackageManagerService.REASON_INSTALL, 713 mDexManager.getCompilationReasonForInstallScenario( 714 PackageManager.INSTALL_SCENARIO_DEFAULT)); 715 716 assertEquals( 717 PackageManagerService.REASON_INSTALL_FAST, 718 mDexManager.getCompilationReasonForInstallScenario( 719 PackageManager.INSTALL_SCENARIO_FAST)); 720 721 assertEquals( 722 PackageManagerService.REASON_INSTALL_BULK, 723 mDexManager.getCompilationReasonForInstallScenario( 724 PackageManager.INSTALL_SCENARIO_BULK)); 725 726 assertEquals( 727 PackageManagerService.REASON_INSTALL_BULK_SECONDARY, 728 mDexManager.getCompilationReasonForInstallScenario( 729 PackageManager.INSTALL_SCENARIO_BULK_SECONDARY)); 730 } 731 732 @Test testInstallScenarioToReasonThermal()733 public void testInstallScenarioToReasonThermal() { 734 ExtendedMockito.doReturn(PowerManager.THERMAL_STATUS_SEVERE) 735 .when(mMockPowerManager) 736 .getCurrentThermalStatus(); 737 738 assertEquals( 739 PackageManagerService.REASON_INSTALL, 740 mDexManager.getCompilationReasonForInstallScenario( 741 PackageManager.INSTALL_SCENARIO_DEFAULT)); 742 743 assertEquals( 744 PackageManagerService.REASON_INSTALL_FAST, 745 mDexManager.getCompilationReasonForInstallScenario( 746 PackageManager.INSTALL_SCENARIO_FAST)); 747 748 assertEquals( 749 PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED, 750 mDexManager.getCompilationReasonForInstallScenario( 751 PackageManager.INSTALL_SCENARIO_BULK)); 752 753 assertEquals( 754 PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED, 755 mDexManager.getCompilationReasonForInstallScenario( 756 PackageManager.INSTALL_SCENARIO_BULK_SECONDARY)); 757 } 758 759 @Test testInstallScenarioToReasonBatteryDischarging()760 public void testInstallScenarioToReasonBatteryDischarging() { 761 ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_CRITICAL) 762 .when(mMockBatteryManager) 763 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); 764 765 assertEquals( 766 PackageManagerService.REASON_INSTALL, 767 mDexManager.getCompilationReasonForInstallScenario( 768 PackageManager.INSTALL_SCENARIO_DEFAULT)); 769 770 assertEquals( 771 PackageManagerService.REASON_INSTALL_FAST, 772 mDexManager.getCompilationReasonForInstallScenario( 773 PackageManager.INSTALL_SCENARIO_FAST)); 774 775 assertEquals( 776 PackageManagerService.REASON_INSTALL_BULK_DOWNGRADED, 777 mDexManager.getCompilationReasonForInstallScenario( 778 PackageManager.INSTALL_SCENARIO_BULK)); 779 780 assertEquals( 781 PackageManagerService.REASON_INSTALL_BULK_SECONDARY_DOWNGRADED, 782 mDexManager.getCompilationReasonForInstallScenario( 783 PackageManager.INSTALL_SCENARIO_BULK_SECONDARY)); 784 } 785 786 @Test testInstallScenarioToReasonBatteryCharging()787 public void testInstallScenarioToReasonBatteryCharging() { 788 ExtendedMockito.doReturn(TEST_BATTERY_LEVEL_CRITICAL) 789 .when(mMockBatteryManager) 790 .getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY); 791 792 ExtendedMockito.doReturn(BatteryManager.BATTERY_STATUS_CHARGING) 793 .when(mMockBatteryManager) 794 .getIntProperty(BatteryManager.BATTERY_PROPERTY_STATUS); 795 796 assertEquals( 797 PackageManagerService.REASON_INSTALL, 798 mDexManager.getCompilationReasonForInstallScenario( 799 PackageManager.INSTALL_SCENARIO_DEFAULT)); 800 801 assertEquals( 802 PackageManagerService.REASON_INSTALL_FAST, 803 mDexManager.getCompilationReasonForInstallScenario( 804 PackageManager.INSTALL_SCENARIO_FAST)); 805 806 assertEquals( 807 PackageManagerService.REASON_INSTALL_BULK, 808 mDexManager.getCompilationReasonForInstallScenario( 809 PackageManager.INSTALL_SCENARIO_BULK)); 810 811 assertEquals( 812 PackageManagerService.REASON_INSTALL_BULK_SECONDARY, 813 mDexManager.getCompilationReasonForInstallScenario( 814 PackageManager.INSTALL_SCENARIO_BULK_SECONDARY)); 815 } 816 assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, String[] expectedContexts)817 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 818 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId, 819 String[] expectedContexts) { 820 assertNotNull(expectedContexts); 821 assertEquals(expectedContexts.length, secondaries.size()); 822 int index = 0; 823 for (String dex : secondaries) { 824 DexUseInfo dui = pui.getDexUseInfoMap().get(dex); 825 assertNotNull(dui); 826 assertEquals(isUsedByOtherApps, dui.isUsedByOtherApps()); 827 assertEquals(ownerUserId, dui.getOwnerUserId()); 828 assertEquals(1, dui.getLoaderIsas().size()); 829 assertTrue(dui.getLoaderIsas().contains(testData.mLoaderIsa)); 830 assertEquals(expectedContexts[index++], dui.getClassLoaderContext()); 831 } 832 } assertSecondaryUse(TestData testData, PackageUseInfo pui, List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId)833 private void assertSecondaryUse(TestData testData, PackageUseInfo pui, 834 List<String> secondaries, boolean isUsedByOtherApps, int ownerUserId) { 835 String[] expectedContexts = DexoptUtils.processContextForDexLoad( 836 Arrays.asList(testData.mClassLoader), 837 Arrays.asList(String.join(File.pathSeparator, secondaries))); 838 assertSecondaryUse(testData, pui, secondaries, isUsedByOtherApps, ownerUserId, 839 expectedContexts); 840 } 841 assertIsUsedByOtherApps(TestData testData, PackageUseInfo pui, boolean isUsedByOtherApps)842 private void assertIsUsedByOtherApps(TestData testData, PackageUseInfo pui, 843 boolean isUsedByOtherApps) { 844 assertIsUsedByOtherApps(testData.getBaseAndSplitDexPaths(), pui, isUsedByOtherApps); 845 } 846 assertIsUsedByOtherApps(List<String> codePaths, PackageUseInfo pui, boolean isUsedByOtherApps)847 private void assertIsUsedByOtherApps(List<String> codePaths, PackageUseInfo pui, 848 boolean isUsedByOtherApps) { 849 for (String codePath : codePaths) { 850 assertEquals(codePath, isUsedByOtherApps, pui.isUsedByOtherApps(codePath)); 851 } 852 } 853 notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId)854 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId) { 855 notifyDexLoad(testData, dexPaths, loaderUserId, /*isolatedProcess=*/ false); 856 } 857 notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId, boolean isolatedProcess)858 private void notifyDexLoad(TestData testData, List<String> dexPaths, int loaderUserId, 859 boolean isolatedProcess) { 860 // By default, assume a single class loader in the chain. 861 // This makes writing tests much easier. 862 List<String> classLoaders = Arrays.asList(testData.mClassLoader); 863 List<String> classPaths = dexPaths != null 864 ? Arrays.<String>asList(String.join(File.pathSeparator, dexPaths)) : null; 865 notifyDexLoad(testData, classLoaders, classPaths, loaderUserId, isolatedProcess); 866 } 867 notifyDexLoad(TestData testData, List<String> classLoaders, List<String> classPaths, int loaderUserId, boolean isolatedProcess)868 private void notifyDexLoad(TestData testData, List<String> classLoaders, 869 List<String> classPaths, int loaderUserId, boolean isolatedProcess) { 870 String[] classLoaderContexts = computeClassLoaderContexts(classLoaders, classPaths); 871 // We call the internal function so any exceptions thrown cause test failures. 872 List<String> dexPaths = classPaths != null 873 ? Arrays.asList(classPaths.get(0).split(File.pathSeparator)) : Arrays.asList(); 874 notifyDexLoad(testData, dexPaths, classLoaderContexts, loaderUserId, isolatedProcess); 875 } 876 notifyDexLoad(TestData testData, List<String> dexPaths, String[] classLoaderContexts, int loaderUserId, boolean isolatedProcess)877 private void notifyDexLoad(TestData testData, List<String> dexPaths, 878 String[] classLoaderContexts, int loaderUserId, boolean isolatedProcess) { 879 assertTrue(dexPaths.size() == classLoaderContexts.length); 880 HashMap<String, String> dexPathMapping = new HashMap<>(dexPaths.size()); 881 for (int i = 0; i < dexPaths.size(); i++) { 882 dexPathMapping.put(dexPaths.get(i), classLoaderContexts != null 883 ? classLoaderContexts[i] : PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT); 884 } 885 mDexManager.notifyDexLoadInternal(testData.mPackageInfo.applicationInfo, dexPathMapping, 886 testData.mLoaderIsa, loaderUserId, isolatedProcess); 887 } 888 computeClassLoaderContexts(List<String> classLoaders, List<String> classPaths)889 private String[] computeClassLoaderContexts(List<String> classLoaders, 890 List<String> classPaths) { 891 if (classPaths == null) { 892 return new String[0]; 893 } 894 String[] results = DexoptUtils.processContextForDexLoad(classLoaders, classPaths); 895 if (results == null) { 896 results = new String[classPaths.get(0).split(File.pathSeparator).length]; 897 Arrays.fill(results, PackageDexUsage.UNSUPPORTED_CLASS_LOADER_CONTEXT); 898 } 899 return results; 900 } 901 getPackageUseInfo(TestData testData)902 private PackageUseInfo getPackageUseInfo(TestData testData) { 903 assertTrue(mDexManager.hasInfoOnPackage(testData.getPackageName())); 904 PackageUseInfo pui = mDexManager.getPackageUseInfoOrDefault(testData.getPackageName()); 905 assertNotNull(pui); 906 return pui; 907 } 908 getPackageDynamicCodeInfo(TestData testData)909 private PackageDynamicCode getPackageDynamicCodeInfo(TestData testData) { 910 return mDexManager.getDynamicCodeLogger() 911 .getPackageDynamicCodeInfo(testData.getPackageName()); 912 } 913 assertNoUseInfo(TestData testData)914 private void assertNoUseInfo(TestData testData) { 915 assertFalse(mDexManager.hasInfoOnPackage(testData.getPackageName())); 916 } 917 assertNoUseInfo(TestData testData, int userId)918 private void assertNoUseInfo(TestData testData, int userId) { 919 if (!mDexManager.hasInfoOnPackage(testData.getPackageName())) { 920 return; 921 } 922 PackageUseInfo pui = getPackageUseInfo(testData); 923 for (DexUseInfo dexUseInfo : pui.getDexUseInfoMap().values()) { 924 assertNotEquals(userId, dexUseInfo.getOwnerUserId()); 925 } 926 } 927 assertNoDclInfo(TestData testData)928 private void assertNoDclInfo(TestData testData) { 929 assertNull(getPackageDynamicCodeInfo(testData)); 930 } 931 assertNoDclInfo(TestData testData, int userId)932 private void assertNoDclInfo(TestData testData, int userId) { 933 PackageDynamicCode info = getPackageDynamicCodeInfo(testData); 934 if (info == null) { 935 return; 936 } 937 938 for (DynamicCodeFile fileInfo : info.mFileUsageMap.values()) { 939 assertNotEquals(userId, fileInfo.mUserId); 940 } 941 } 942 assertHasDclInfo(TestData owner, TestData loader, List<String> paths)943 private void assertHasDclInfo(TestData owner, TestData loader, List<String> paths) { 944 PackageDynamicCode info = getPackageDynamicCodeInfo(owner); 945 assertNotNull("No DCL data for owner " + owner.getPackageName(), info); 946 for (String path : paths) { 947 DynamicCodeFile fileInfo = info.mFileUsageMap.get(path); 948 assertNotNull("No DCL data for path " + path, fileInfo); 949 assertEquals(PackageDynamicCodeLoading.FILE_TYPE_DEX, fileInfo.mFileType); 950 assertEquals(owner.mUserId, fileInfo.mUserId); 951 assertTrue("No DCL data for loader " + loader.getPackageName(), 952 fileInfo.mLoadingPackages.contains(loader.getPackageName())); 953 } 954 } 955 getMockPackageInfo(String packageName, int userId)956 private static PackageInfo getMockPackageInfo(String packageName, int userId) { 957 PackageInfo pi = new PackageInfo(); 958 pi.packageName = packageName; 959 pi.applicationInfo = getMockApplicationInfo(packageName, userId); 960 return pi; 961 } 962 getMockApplicationInfo(String packageName, int userId)963 private static ApplicationInfo getMockApplicationInfo(String packageName, int userId) { 964 ApplicationInfo ai = new ApplicationInfo(); 965 String codeDir = "/data/app/" + packageName; 966 ai.setBaseCodePath(codeDir + "/base.dex"); 967 ai.setSplitCodePaths(new String[] {codeDir + "/split-1.dex", codeDir + "/split-2.dex"}); 968 ai.dataDir = "/data/user/" + userId + "/" + packageName; 969 ai.deviceProtectedDataDir = "/data/user_de/" + userId + "/" + packageName; 970 ai.credentialProtectedDataDir = "/data/user_ce/" + userId + "/" + packageName; 971 ai.packageName = packageName; 972 return ai; 973 } 974 975 private static class TestData { 976 private final PackageInfo mPackageInfo; 977 private final String mLoaderIsa; 978 private final String mClassLoader; 979 private final int mUserId; 980 TestData(String packageName, String loaderIsa, int userId, String classLoader)981 private TestData(String packageName, String loaderIsa, int userId, String classLoader) { 982 mPackageInfo = getMockPackageInfo(packageName, userId); 983 mLoaderIsa = loaderIsa; 984 mClassLoader = classLoader; 985 mUserId = userId; 986 } 987 TestData(String packageName, String loaderIsa, int userId)988 private TestData(String packageName, String loaderIsa, int userId) { 989 this(packageName, loaderIsa, userId, PATH_CLASS_LOADER_NAME); 990 } 991 getPackageName()992 private String getPackageName() { 993 return mPackageInfo.packageName; 994 } 995 getSecondaryDexPaths()996 List<String> getSecondaryDexPaths() { 997 List<String> paths = new ArrayList<>(); 998 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary1.dex"); 999 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary2.dex"); 1000 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary3.dex"); 1001 return paths; 1002 } 1003 getSecondaryDexPathsForOwnUse()1004 List<String> getSecondaryDexPathsForOwnUse() { 1005 List<String> paths = new ArrayList<>(); 1006 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary4.dex"); 1007 paths.add(mPackageInfo.applicationInfo.dataDir + "/secondary5.dex"); 1008 return paths; 1009 } 1010 getSecondaryDexPathsFromProtectedDirs()1011 List<String> getSecondaryDexPathsFromProtectedDirs() { 1012 List<String> paths = new ArrayList<>(); 1013 paths.add(mPackageInfo.applicationInfo.deviceProtectedDataDir + "/secondary6.dex"); 1014 paths.add(mPackageInfo.applicationInfo.credentialProtectedDataDir + "/secondary7.dex"); 1015 return paths; 1016 } 1017 getBaseAndSplitDexPaths()1018 List<String> getBaseAndSplitDexPaths() { 1019 List<String> paths = new ArrayList<>(); 1020 paths.add(mPackageInfo.applicationInfo.sourceDir); 1021 Collections.addAll(paths, mPackageInfo.applicationInfo.splitSourceDirs); 1022 return paths; 1023 } 1024 replaceLastSplit()1025 String replaceLastSplit() { 1026 int length = mPackageInfo.applicationInfo.splitSourceDirs.length; 1027 // Add an extra bogus dex extension to simulate a new split name. 1028 mPackageInfo.applicationInfo.splitSourceDirs[length - 1] += ".dex"; 1029 return mPackageInfo.applicationInfo.splitSourceDirs[length - 1]; 1030 } 1031 } 1032 shouldPackageRunOob(boolean isDefaultEnabled, String whitelist, Collection<String> packageNamesInSameProcess)1033 private boolean shouldPackageRunOob(boolean isDefaultEnabled, String whitelist, 1034 Collection<String> packageNamesInSameProcess) { 1035 return DexManager.isPackageSelectedToRunOobInternal( 1036 isDefaultEnabled, whitelist, packageNamesInSameProcess); 1037 } 1038 1039 @Test testOobPackageSelectionDefault()1040 public void testOobPackageSelectionDefault() { 1041 // Feature is off by default, not overriden 1042 assertFalse(shouldPackageRunOob(false, "ALL", null)); 1043 } 1044 1045 @Test testOobPackageSelectionWhitelist()1046 public void testOobPackageSelectionWhitelist() { 1047 // Various allowlist of apps to run in OOB mode. 1048 final String kWhitelistApp0 = "com.priv.app0"; 1049 final String kWhitelistApp1 = "com.priv.app1"; 1050 final String kWhitelistApp2 = "com.priv.app2"; 1051 final String kWhitelistApp1AndApp2 = "com.priv.app1,com.priv.app2"; 1052 1053 // Packages that shares the targeting process. 1054 final Collection<String> runningPackages = Arrays.asList("com.priv.app1", "com.priv.app2"); 1055 1056 // Feature is off, allowlist does not matter 1057 assertFalse(shouldPackageRunOob(false, kWhitelistApp0, runningPackages)); 1058 assertFalse(shouldPackageRunOob(false, kWhitelistApp1, runningPackages)); 1059 assertFalse(shouldPackageRunOob(false, "", runningPackages)); 1060 assertFalse(shouldPackageRunOob(false, "ALL", runningPackages)); 1061 1062 // Feature is on, app not in allowlist 1063 assertFalse(shouldPackageRunOob(true, kWhitelistApp0, runningPackages)); 1064 assertFalse(shouldPackageRunOob(true, "", runningPackages)); 1065 1066 // Feature is on, app in allowlist 1067 assertTrue(shouldPackageRunOob(true, kWhitelistApp1, runningPackages)); 1068 assertTrue(shouldPackageRunOob(true, kWhitelistApp2, runningPackages)); 1069 assertTrue(shouldPackageRunOob(true, kWhitelistApp1AndApp2, runningPackages)); 1070 assertTrue(shouldPackageRunOob(true, "ALL", runningPackages)); 1071 } 1072 } 1073