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.MAX_SECONDARY_FILES_PER_OWNER; 21 import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo; 22 23 import static org.junit.Assert.assertEquals; 24 import static org.junit.Assert.assertFalse; 25 import static org.junit.Assert.assertNotNull; 26 import static org.junit.Assert.assertNull; 27 import static org.junit.Assert.assertTrue; 28 import static org.junit.Assert.fail; 29 30 import android.os.Build; 31 import android.platform.test.annotations.Presubmit; 32 33 import androidx.test.filters.SmallTest; 34 import androidx.test.runner.AndroidJUnit4; 35 36 import dalvik.system.VMRuntime; 37 38 import org.junit.Before; 39 import org.junit.Test; 40 import org.junit.runner.RunWith; 41 42 import java.io.IOException; 43 import java.io.StringReader; 44 import java.io.StringWriter; 45 import java.util.ArrayList; 46 import java.util.Arrays; 47 import java.util.HashMap; 48 import java.util.HashSet; 49 import java.util.List; 50 import java.util.Map; 51 import java.util.Set; 52 53 @Presubmit 54 @RunWith(AndroidJUnit4.class) 55 @SmallTest 56 public class PackageDexUsageTests { 57 private static final String ISA = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 58 59 private PackageDexUsage mPackageDexUsage; 60 61 private TestData mFooBaseUser0; 62 private TestData mFooSplit1User0; 63 private TestData mFooSplit2UsedByOtherApps0; 64 private TestData mFooSecondary1User0; 65 private TestData mFooSecondary1User1; 66 private TestData mFooSecondary2UsedByOtherApps0; 67 private TestData mInvalidIsa; 68 69 private TestData mBarBaseUser0; 70 private TestData mBarSecondary1User0; 71 private TestData mBarSecondary2User1; 72 73 @Before setup()74 public void setup() { 75 mPackageDexUsage = new PackageDexUsage(); 76 77 String fooPackageName = "com.google.foo"; 78 String fooCodeDir = "/data/app/com.google.foo/"; 79 String fooDataDir = "/data/user/0/com.google.foo/"; 80 81 mFooBaseUser0 = new TestData(fooPackageName, 82 fooCodeDir + "base.apk", 0, ISA, true, fooPackageName); 83 84 mFooSplit1User0 = new TestData(fooPackageName, 85 fooCodeDir + "split-1.apk", 0, ISA, true, fooPackageName); 86 87 mFooSplit2UsedByOtherApps0 = new TestData(fooPackageName, 88 fooCodeDir + "split-2.apk", 0, ISA, true, "used.by.other.com"); 89 90 mFooSecondary1User0 = new TestData(fooPackageName, 91 fooDataDir + "sec-1.dex", 0, ISA, false, fooPackageName); 92 93 mFooSecondary1User1 = new TestData(fooPackageName, 94 fooDataDir + "sec-1.dex", 1, ISA, false, fooPackageName); 95 96 mFooSecondary2UsedByOtherApps0 = new TestData(fooPackageName, 97 fooDataDir + "sec-2.dex", 0, ISA, false, "used.by.other.com"); 98 99 mInvalidIsa = new TestData(fooPackageName, 100 fooCodeDir + "base.apk", 0, "INVALID_ISA", true, "INALID_USER"); 101 102 String barPackageName = "com.google.bar"; 103 String barCodeDir = "/data/app/com.google.bar/"; 104 String barDataDir = "/data/user/0/com.google.bar/"; 105 String barDataDir1 = "/data/user/1/com.google.bar/"; 106 107 mBarBaseUser0 = new TestData(barPackageName, 108 barCodeDir + "base.apk", 0, ISA, true, barPackageName); 109 mBarSecondary1User0 = new TestData(barPackageName, 110 barDataDir + "sec-1.dex", 0, ISA, false, barPackageName); 111 mBarSecondary2User1 = new TestData(barPackageName, 112 barDataDir1 + "sec-2.dex", 1, ISA, false, barPackageName); 113 } 114 115 @Test testRecordPrimary()116 public void testRecordPrimary() { 117 // Assert new information. 118 assertTrue(record(mFooBaseUser0)); 119 120 assertPackageDexUsage(mFooBaseUser0); 121 writeAndReadBack(); 122 assertPackageDexUsage(mFooBaseUser0); 123 } 124 125 @Test testRecordSplit()126 public void testRecordSplit() { 127 // Assert new information. 128 assertTrue(record(mFooSplit1User0)); 129 130 assertPackageDexUsage(mFooSplit1User0); 131 writeAndReadBack(); 132 assertPackageDexUsage(mFooSplit1User0); 133 } 134 135 @Test testRecordSplitPrimarySequence()136 public void testRecordSplitPrimarySequence() { 137 // Assert new information. 138 assertTrue(record(mFooBaseUser0)); 139 assertTrue(record(mFooSplit1User0)); 140 // Assert no new information if we add again 141 assertFalse(record(mFooBaseUser0)); 142 assertFalse(record(mFooSplit1User0)); 143 144 assertPackageDexUsage(mFooBaseUser0); 145 writeAndReadBack(); 146 assertPackageDexUsage(mFooBaseUser0); 147 148 // Write Split2 which is used by other apps. 149 // Assert new information. 150 assertTrue(record(mFooSplit2UsedByOtherApps0)); 151 assertPackageDexUsage(mFooSplit2UsedByOtherApps0); 152 writeAndReadBack(); 153 assertPackageDexUsage(mFooSplit2UsedByOtherApps0); 154 } 155 156 @Test testRecordSecondary()157 public void testRecordSecondary() { 158 assertTrue(record(mFooSecondary1User0)); 159 160 assertPackageDexUsage(null, mFooSecondary1User0); 161 writeAndReadBack(); 162 assertPackageDexUsage(null, mFooSecondary1User0); 163 164 // Recording again does not add more data. 165 assertFalse(record(mFooSecondary1User0)); 166 assertPackageDexUsage(null, mFooSecondary1User0); 167 } 168 169 @Test testRecordBaseAndSecondarySequence()170 public void testRecordBaseAndSecondarySequence() { 171 // Write split. 172 assertTrue(record(mFooSplit2UsedByOtherApps0)); 173 // Write secondary. 174 assertTrue(record(mFooSecondary1User0)); 175 176 // Check. 177 assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0); 178 writeAndReadBack(); 179 assertPackageDexUsage(mFooSplit2UsedByOtherApps0, mFooSecondary1User0); 180 181 // Write another secondary. 182 assertTrue(record(mFooSecondary2UsedByOtherApps0)); 183 184 // Check. 185 assertPackageDexUsage( 186 mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); 187 writeAndReadBack(); 188 assertPackageDexUsage( 189 mFooSplit2UsedByOtherApps0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); 190 } 191 192 @Test testRecordTooManySecondaries()193 public void testRecordTooManySecondaries() { 194 int tooManyFiles = MAX_SECONDARY_FILES_PER_OWNER + 1; 195 List<TestData> expectedSecondaries = new ArrayList<>(); 196 for (int i = 1; i <= tooManyFiles; i++) { 197 String fooPackageName = "com.google.foo"; 198 TestData testData = new TestData(fooPackageName, 199 "/data/user/0/" + fooPackageName + "/sec-" + i + "1.dex", 0, ISA, false, 200 fooPackageName); 201 if (i < tooManyFiles) { 202 assertTrue("Adding " + testData.mDexFile, record(testData)); 203 expectedSecondaries.add(testData); 204 } else { 205 assertFalse("Adding " + testData.mDexFile, record(testData)); 206 } 207 assertPackageDexUsage( 208 mPackageDexUsage, 209 /* usdeBy=*/ (Set<String>) null, 210 /* primaryDex= */ null, 211 expectedSecondaries); 212 } 213 } 214 215 @Test testMultiplePackages()216 public void testMultiplePackages() { 217 assertTrue(record(mFooBaseUser0)); 218 assertTrue(record(mFooSecondary1User0)); 219 assertTrue(record(mFooSecondary2UsedByOtherApps0)); 220 assertTrue(record(mBarBaseUser0)); 221 assertTrue(record(mBarSecondary1User0)); 222 assertTrue(record(mBarSecondary2User1)); 223 224 assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); 225 assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1); 226 writeAndReadBack(); 227 assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); 228 assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1); 229 } 230 231 @Test testPackageNotFound()232 public void testPackageNotFound() { 233 assertNull(mPackageDexUsage.getPackageUseInfo("missing.package")); 234 } 235 236 @Test testAttemptToChangeOwner()237 public void testAttemptToChangeOwner() { 238 assertTrue(record(mFooSecondary1User0)); 239 try { 240 record(mFooSecondary1User1); 241 fail("Expected exception"); 242 } catch (IllegalArgumentException e) { 243 // expected 244 } 245 } 246 247 @Test testInvalidIsa()248 public void testInvalidIsa() { 249 try { 250 record(mInvalidIsa); 251 fail("Expected exception"); 252 } catch (IllegalArgumentException e) { 253 // expected 254 } 255 } 256 257 @Test testReadWriteEmtpy()258 public void testReadWriteEmtpy() { 259 // Expect no exceptions when writing/reading without data. 260 writeAndReadBack(); 261 } 262 263 @Test testSyncData()264 public void testSyncData() { 265 // Write some records. 266 assertTrue(record(mFooBaseUser0)); 267 assertTrue(record(mFooSecondary1User0)); 268 assertTrue(record(mFooSecondary2UsedByOtherApps0)); 269 assertTrue(record(mBarBaseUser0)); 270 assertTrue(record(mBarSecondary1User0)); 271 assertTrue(record(mBarSecondary2User1)); 272 273 // Verify all is good. 274 assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); 275 assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1); 276 writeAndReadBack(); 277 assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0, mFooSecondary2UsedByOtherApps0); 278 assertPackageDexUsage(mBarBaseUser0, mBarSecondary1User0, mBarSecondary2User1); 279 280 // Simulate that only user 1 is available. 281 Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); 282 packageToUsersMap.put(mBarSecondary2User1.mPackageName, 283 new HashSet<>(Arrays.asList(mBarSecondary2User1.mOwnerUserId))); 284 Map<String, Set<String>> packageToCodePaths = new HashMap<>(); 285 packageToCodePaths.put(mBarBaseUser0.mPackageName, 286 new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); 287 mPackageDexUsage.syncData(packageToUsersMap, packageToCodePaths, new ArrayList<String>()); 288 289 // Assert that only user 1 files are there. 290 assertPackageDexUsage(mBarBaseUser0, mBarSecondary2User1); 291 assertNull(mPackageDexUsage.getPackageUseInfo(mFooBaseUser0.mPackageName)); 292 } 293 294 @Test testSyncDataKeepPackages()295 public void testSyncDataKeepPackages() { 296 PackageDexUsage packageDexUsage = new PackageDexUsage(); 297 // Write the record we want to keep and which won't be keep by default. 298 Set<String> fooUsers = new HashSet<>(Arrays.asList( 299 new String[] {mFooBaseUser0.mPackageName})); 300 assertTrue(record(packageDexUsage, mFooBaseUser0, fooUsers)); 301 // Write a record that would be kept by default. 302 Set<String> barUsers = new HashSet<>(Arrays.asList( 303 new String[] {"another.package", mFooBaseUser0.mPackageName})); 304 assertTrue(record(packageDexUsage, mBarBaseUser0, barUsers)); 305 306 // Construct the user packages and their code paths (things that will be 307 // kept by default during sync). 308 Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); 309 packageToUsersMap.put(mBarBaseUser0.mPackageName, 310 new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId))); 311 Map<String, Set<String>> packageToCodePaths = new HashMap<>(); 312 packageToCodePaths.put(mBarBaseUser0.mPackageName, 313 new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); 314 315 // Sync data. 316 List<String> keepData = new ArrayList<String>(); 317 keepData.add(mFooBaseUser0.mPackageName); 318 packageDexUsage.syncData(packageToUsersMap, packageToCodePaths, keepData); 319 320 // Assert that both packages are kept 321 assertPackageDexUsage(packageDexUsage, fooUsers, mFooBaseUser0); 322 // "another.package" should not be in the loading packages after sync. 323 Set<String> expectedBarUsers = new HashSet<>(Arrays.asList( 324 new String[] {mFooBaseUser0.mPackageName})); 325 assertPackageDexUsage(packageDexUsage, expectedBarUsers, 326 mBarBaseUser0.updateUsedBy(mFooBaseUser0.mPackageName)); 327 } 328 329 @Test testRemovePackage()330 public void testRemovePackage() { 331 // Record Bar secondaries for two different users. 332 assertTrue(record(mBarSecondary1User0)); 333 assertTrue(record(mBarSecondary2User1)); 334 335 // Remove the package. 336 assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName)); 337 // Assert that we can't find the package anymore. 338 assertNull(mPackageDexUsage.getPackageUseInfo(mBarSecondary1User0.mPackageName)); 339 } 340 341 @Test testRemoveNonexistentPackage()342 public void testRemoveNonexistentPackage() { 343 // Record Bar secondaries for two different users. 344 assertTrue(record(mBarSecondary1User0)); 345 346 // Remove the package. 347 assertTrue(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName)); 348 // Remove the package again. It should return false because the package no longer 349 // has a record in the use info. 350 assertFalse(mPackageDexUsage.removePackage(mBarSecondary1User0.mPackageName)); 351 } 352 353 @Test testRemoveUserPackage()354 public void testRemoveUserPackage() { 355 // Record Bar secondaries for two different users. 356 assertTrue(record(mBarSecondary1User0)); 357 assertTrue(record(mBarSecondary2User1)); 358 359 // Remove user 0 files. 360 assertTrue(mPackageDexUsage.removeUserPackage(mBarSecondary1User0.mPackageName, 361 mBarSecondary1User0.mOwnerUserId)); 362 // Assert that only user 1 files are there. 363 assertPackageDexUsage(null, mBarSecondary2User1); 364 } 365 366 @Test testRemoveDexFile()367 public void testRemoveDexFile() { 368 // Record Bar secondaries for two different users. 369 assertTrue(record(mBarSecondary1User0)); 370 assertTrue(record(mBarSecondary2User1)); 371 372 // Remove mBarSecondary1User0 file. 373 assertTrue(mPackageDexUsage.removeDexFile(mBarSecondary1User0.mPackageName, 374 mBarSecondary1User0.mDexFile, mBarSecondary1User0.mOwnerUserId)); 375 // Assert that only user 1 files are there. 376 assertPackageDexUsage(null, mBarSecondary2User1); 377 } 378 379 @Test testClearUsedByOtherApps()380 public void testClearUsedByOtherApps() { 381 // Write a package which is used by other apps. 382 assertTrue(record(mFooSplit2UsedByOtherApps0)); 383 assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName)); 384 385 // Check that the package is no longer used by other apps. 386 TestData noLongerUsedByOtherApps = new TestData( 387 mFooSplit2UsedByOtherApps0.mPackageName, 388 mFooSplit2UsedByOtherApps0.mDexFile, 389 mFooSplit2UsedByOtherApps0.mOwnerUserId, 390 mFooSplit2UsedByOtherApps0.mLoaderIsa, 391 mFooSplit2UsedByOtherApps0.mPrimaryOrSplit, 392 /*usedBy=*/ null); 393 assertPackageDexUsage(noLongerUsedByOtherApps); 394 } 395 396 @Test testClearUsedByOtherAppsNonexistent()397 public void testClearUsedByOtherAppsNonexistent() { 398 // Write a package which is used by other apps. 399 assertTrue(record(mFooSplit2UsedByOtherApps0)); 400 assertTrue(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName)); 401 // Clearing again should return false as there should be no update on the use info. 402 assertFalse(mPackageDexUsage.clearUsedByOtherApps(mFooSplit2UsedByOtherApps0.mPackageName)); 403 } 404 405 @Test testRecordDexFileUsers()406 public void testRecordDexFileUsers() { 407 PackageDexUsage packageDexUsageRecordUsers = new PackageDexUsage(); 408 Set<String> users = new HashSet<>(Arrays.asList( 409 new String[] {"another.package.1"})); 410 Set<String> usersExtra = new HashSet<>(Arrays.asList( 411 new String[] {"another.package.2", "another.package.3"})); 412 413 assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, users)); 414 assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, usersExtra)); 415 416 assertTrue(record(packageDexUsageRecordUsers, mFooSecondary2UsedByOtherApps0, users)); 417 assertTrue(record(packageDexUsageRecordUsers, mFooSecondary2UsedByOtherApps0, usersExtra)); 418 419 packageDexUsageRecordUsers = writeAndReadBack(packageDexUsageRecordUsers); 420 // Verify that the users were recorded. 421 Set<String> userAll = new HashSet<>(users); 422 userAll.addAll(usersExtra); 423 assertPackageDexUsage(packageDexUsageRecordUsers, userAll, mFooSplit2UsedByOtherApps0, 424 mFooSecondary2UsedByOtherApps0); 425 } 426 427 @Test testRecordDexFileUsersAndTheOwningPackage()428 public void testRecordDexFileUsersAndTheOwningPackage() { 429 PackageDexUsage packageDexUsageRecordUsers = new PackageDexUsage(); 430 Set<String> users = new HashSet<>(Arrays.asList( 431 new String[] {mFooSplit2UsedByOtherApps0.mPackageName})); 432 Set<String> usersExtra = new HashSet<>(Arrays.asList( 433 new String[] {"another.package.2", "another.package.3"})); 434 435 assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, users)); 436 assertTrue(record(packageDexUsageRecordUsers, mFooSplit2UsedByOtherApps0, usersExtra)); 437 438 packageDexUsageRecordUsers = writeAndReadBack(packageDexUsageRecordUsers); 439 440 Set<String> expectedUsers = new HashSet<>(users); 441 expectedUsers.addAll(usersExtra); 442 // Verify that all loading packages were recorded. 443 assertPackageDexUsage( 444 packageDexUsageRecordUsers, expectedUsers, mFooSplit2UsedByOtherApps0); 445 } 446 447 @Test testRecordClassLoaderContextVariableContext()448 public void testRecordClassLoaderContextVariableContext() { 449 // Record a secondary dex file. 450 assertTrue(record(mFooSecondary1User0)); 451 // Now update its context. 452 TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext( 453 "PCL[new_context.dex]"); 454 assertTrue(record(fooSecondary1User0NewContext)); 455 456 // Now check that the context was switch to variable. 457 TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext( 458 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT); 459 460 assertPackageDexUsage(null, expectedContext); 461 writeAndReadBack(); 462 assertPackageDexUsage(null, expectedContext); 463 } 464 465 @Test testRecordClassLoaderContextOverwritten()466 public void testRecordClassLoaderContextOverwritten() { 467 // Record a secondary dex file. 468 assertTrue(record(mFooSecondary1User0)); 469 // Now update its context. 470 TestData fooSecondary1User0NewContext = mFooSecondary1User0.updateClassLoaderContext( 471 "PCL[new_context.dex]", true); 472 assertTrue(record(fooSecondary1User0NewContext)); 473 474 // Now check that the context was overwritten. 475 TestData expectedContext = mFooSecondary1User0.updateClassLoaderContext( 476 "PCL[new_context.dex]", true); 477 478 assertPackageDexUsage(null, expectedContext); 479 } 480 481 @Test testDexUsageClassLoaderContext()482 public void testDexUsageClassLoaderContext() { 483 final boolean isUsedByOtherApps = false; 484 final int userId = 0; 485 PackageDexUsage.DexUseInfo validContext = new DexUseInfo(isUsedByOtherApps, userId, 486 "valid_context", "arm"); 487 assertFalse(validContext.isUnsupportedClassLoaderContext()); 488 assertFalse(validContext.isVariableClassLoaderContext()); 489 490 PackageDexUsage.DexUseInfo variableContext = new DexUseInfo(isUsedByOtherApps, userId, 491 PackageDexUsage.VARIABLE_CLASS_LOADER_CONTEXT, "arm"); 492 assertFalse(variableContext.isUnsupportedClassLoaderContext()); 493 assertTrue(variableContext.isVariableClassLoaderContext()); 494 } 495 496 @Test testRead()497 public void testRead() { 498 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 499 // Equivalent to 500 // record(mFooSplit2UsedByOtherApps0); 501 // record(mFooSecondary1User0); 502 // record(mFooSecondary2UsedByOtherApps0); 503 // record(mBarBaseUser0); 504 // record(mBarSecondary1User0); 505 String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n" 506 + "com.google.foo\n" 507 + "+/data/app/com.google.foo/split-2.apk\n" 508 + "@used.by.other.com\n" 509 + "#/data/user/0/com.google.foo/sec-2.dex\n" 510 + "0,1," + ISA + "\n" 511 + "@used.by.other.com\n" 512 + "PCL[/data/user/0/com.google.foo/sec-2.dex]\n" 513 + "#/data/user/0/com.google.foo/sec-1.dex\n" 514 + "0,0," + ISA + "\n" 515 + "@\n" 516 + "PCL[/data/user/0/com.google.foo/sec-1.dex]\n" 517 + "com.google.bar\n" 518 + "+/data/app/com.google.bar/base.apk\n" 519 + "@com.google.bar\n" 520 + "#/data/user/0/com.google.bar/sec-1.dex\n" 521 + "0,0," + ISA + "\n" 522 + "@\n" 523 + "PCL[/data/user/0/com.google.bar/sec-1.dex]"; 524 525 PackageDexUsage packageDexUsage = new PackageDexUsage(); 526 try { 527 packageDexUsage.read(new StringReader(content)); 528 } catch (IOException e) { 529 fail(); 530 } 531 532 // After the read we must sync the data to fill the missing information on the code paths. 533 Map<String, Set<Integer>> packageToUsersMap = new HashMap<>(); 534 Map<String, Set<String>> packageToCodePaths = new HashMap<>(); 535 536 // Handle foo package. 537 packageToUsersMap.put( 538 mFooSplit2UsedByOtherApps0.mPackageName, 539 new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId))); 540 packageToCodePaths.put( 541 mFooSplit2UsedByOtherApps0.mPackageName, 542 new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mDexFile, 543 mFooSplit1User0.mDexFile, mFooBaseUser0.mDexFile))); 544 // Handle bar package. 545 packageToUsersMap.put( 546 mBarBaseUser0.mPackageName, 547 new HashSet<>(Arrays.asList(mBarBaseUser0.mOwnerUserId))); 548 packageToCodePaths.put( 549 mBarBaseUser0.mPackageName, 550 new HashSet<>(Arrays.asList(mBarBaseUser0.mDexFile))); 551 // Handle the loading package. 552 packageToUsersMap.put( 553 mFooSplit2UsedByOtherApps0.mUsedBy, 554 new HashSet<>(Arrays.asList(mFooSplit2UsedByOtherApps0.mOwnerUserId))); 555 556 // Sync the data. 557 packageDexUsage.syncData(packageToUsersMap, packageToCodePaths, new ArrayList<>()); 558 559 // Assert foo code paths. 560 assertPackageDexUsage( 561 packageDexUsage, 562 /*nonDefaultUsers=*/ null, 563 mFooSplit2UsedByOtherApps0, 564 mFooSecondary2UsedByOtherApps0, 565 mFooSecondary1User0); 566 567 // Assert bar code paths. 568 assertPackageDexUsage( 569 packageDexUsage, 570 /*nonDefaultUsers=*/ null, 571 mBarBaseUser0, 572 mBarSecondary1User0); 573 } 574 575 @Test testUnsupportedClassLoaderDiscardedOnRead()576 public void testUnsupportedClassLoaderDiscardedOnRead() throws Exception { 577 String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n" 578 + mBarSecondary1User0.mPackageName + "\n" 579 + "#" + mBarSecondary1User0.mDexFile + "\n" 580 + "0,0," + mBarSecondary1User0.mLoaderIsa + "\n" 581 + "@\n" 582 + "=UnsupportedClassLoaderContext=\n" 583 584 + mFooSecondary1User0.mPackageName + "\n" 585 + "#" + mFooSecondary1User0.mDexFile + "\n" 586 + "0,0," + mFooSecondary1User0.mLoaderIsa + "\n" 587 + "@\n" 588 + mFooSecondary1User0.mClassLoaderContext + "\n"; 589 590 mPackageDexUsage.read(new StringReader(content)); 591 592 assertPackageDexUsage(mFooBaseUser0, mFooSecondary1User0); 593 assertPackageDexUsage(mBarBaseUser0); 594 } 595 596 @Test testEnsureLoadingPackagesCanBeExtended()597 public void testEnsureLoadingPackagesCanBeExtended() { 598 String isa = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]); 599 String content = "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__2\n" 600 + "com.google.foo\n" 601 + "+/data/app/com.google.foo/split-2.apk\n" 602 + "@\n"; 603 PackageDexUsage packageDexUsage = new PackageDexUsage(); 604 try { 605 packageDexUsage.read(new StringReader(content)); 606 } catch (IOException e) { 607 fail(); 608 } 609 record(packageDexUsage, mFooSplit2UsedByOtherApps0, mFooSplit2UsedByOtherApps0.getUsedBy()); 610 } 611 assertPackageDexUsage(TestData primary, TestData... secondaries)612 private void assertPackageDexUsage(TestData primary, TestData... secondaries) { 613 assertPackageDexUsage(mPackageDexUsage, null, primary, secondaries); 614 } 615 assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, TestData... secondaries)616 private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, 617 TestData primary, TestData... secondaries) { 618 assertPackageDexUsage(packageDexUsage, users, primary, Arrays.asList(secondaries)); 619 } 620 assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, TestData primary, List<TestData> secondaries)621 private void assertPackageDexUsage(PackageDexUsage packageDexUsage, Set<String> users, 622 TestData primary, List<TestData> secondaries) { 623 String packageName = primary == null 624 ? secondaries.get(0).mPackageName 625 : primary.mPackageName; 626 boolean primaryUsedByOtherApps = primary != null && primary.isUsedByOtherApps(); 627 PackageUseInfo pInfo = packageDexUsage.getPackageUseInfo(packageName); 628 629 // Check package use info 630 assertNotNull(pInfo); 631 if (primary != null) { 632 if (users != null) { 633 assertEquals(pInfo.getLoadingPackages(primary.mDexFile), users); 634 } else if (pInfo.getLoadingPackages(primary.mDexFile) != null) { 635 assertEquals(pInfo.getLoadingPackages(primary.mDexFile), primary.getUsedBy()); 636 } 637 assertEquals(primaryUsedByOtherApps, pInfo.isUsedByOtherApps(primary.mDexFile)); 638 } 639 640 Map<String, DexUseInfo> dexUseInfoMap = pInfo.getDexUseInfoMap(); 641 assertEquals(secondaries.size(), dexUseInfoMap.size()); 642 643 // Check dex use info 644 for (TestData testData : secondaries) { 645 DexUseInfo dInfo = dexUseInfoMap.get(testData.mDexFile); 646 assertNotNull(dInfo); 647 if (users != null) { 648 assertEquals(testData.mDexFile, dInfo.getLoadingPackages(), users); 649 } else { 650 assertEquals(testData.mDexFile, dInfo.getLoadingPackages(), testData.getUsedBy()); 651 } 652 assertEquals(testData.isUsedByOtherApps(), dInfo.isUsedByOtherApps()); 653 assertEquals(testData.mOwnerUserId, dInfo.getOwnerUserId()); 654 assertEquals(1, dInfo.getLoaderIsas().size()); 655 assertTrue(dInfo.getLoaderIsas().contains(testData.mLoaderIsa)); 656 657 assertEquals(testData.mClassLoaderContext, dInfo.getClassLoaderContext()); 658 } 659 } 660 record(TestData testData)661 private boolean record(TestData testData) { 662 return mPackageDexUsage.record(testData.mPackageName, testData.mDexFile, 663 testData.mOwnerUserId, testData.mLoaderIsa, 664 testData.mPrimaryOrSplit, testData.mUsedBy, testData.mClassLoaderContext, 665 testData.mOverwriteCLC); 666 } 667 record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users)668 private boolean record(PackageDexUsage packageDexUsage, TestData testData, Set<String> users) { 669 boolean result = true; 670 for (String user : users) { 671 result = result && packageDexUsage.record(testData.mPackageName, testData.mDexFile, 672 testData.mOwnerUserId, testData.mLoaderIsa, 673 testData.mPrimaryOrSplit, user, testData.mClassLoaderContext, 674 testData.mOverwriteCLC); 675 } 676 return result; 677 } 678 writeAndReadBack()679 private void writeAndReadBack() { 680 mPackageDexUsage = writeAndReadBack(mPackageDexUsage); 681 } 682 writeAndReadBack(PackageDexUsage packageDexUsage)683 private PackageDexUsage writeAndReadBack(PackageDexUsage packageDexUsage) { 684 try { 685 StringWriter writer = new StringWriter(); 686 packageDexUsage.write(writer); 687 688 PackageDexUsage newPackageDexUsage = new PackageDexUsage(); 689 newPackageDexUsage.read(new StringReader(writer.toString())); 690 return newPackageDexUsage; 691 } catch (IOException e) { 692 fail("Unexpected IOException: " + e.getMessage()); 693 return null; 694 } 695 } 696 697 private static class TestData { 698 private final String mPackageName; 699 private final String mDexFile; 700 private final int mOwnerUserId; 701 private final String mLoaderIsa; 702 private final boolean mPrimaryOrSplit; 703 private final String mUsedBy; 704 private final String mClassLoaderContext; 705 private final boolean mOverwriteCLC; 706 TestData(String packageName, String dexFile, int ownerUserId, String loaderIsa, boolean primaryOrSplit, String usedBy)707 private TestData(String packageName, String dexFile, int ownerUserId, 708 String loaderIsa, boolean primaryOrSplit, String usedBy) { 709 this(packageName, dexFile, ownerUserId, loaderIsa, primaryOrSplit, 710 usedBy, "PCL[" + dexFile + "]", false); 711 } TestData(String packageName, String dexFile, int ownerUserId, String loaderIsa, boolean primaryOrSplit, String usedBy, String classLoaderContext, boolean overwriteCLC)712 private TestData(String packageName, String dexFile, int ownerUserId, 713 String loaderIsa, boolean primaryOrSplit, String usedBy, 714 String classLoaderContext, boolean overwriteCLC) { 715 mPackageName = packageName; 716 mDexFile = dexFile; 717 mOwnerUserId = ownerUserId; 718 mLoaderIsa = loaderIsa; 719 mPrimaryOrSplit = primaryOrSplit; 720 mUsedBy = usedBy; 721 mClassLoaderContext = classLoaderContext; 722 mOverwriteCLC = overwriteCLC; 723 } 724 updateClassLoaderContext(String newContext)725 private TestData updateClassLoaderContext(String newContext) { 726 return updateClassLoaderContext(newContext, mOverwriteCLC); 727 } 728 updateClassLoaderContext(String newContext, boolean overwriteCLC)729 private TestData updateClassLoaderContext(String newContext, boolean overwriteCLC) { 730 return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, 731 mPrimaryOrSplit, mUsedBy, newContext, overwriteCLC); 732 } 733 updateUsedBy(String newUsedBy)734 private TestData updateUsedBy(String newUsedBy) { 735 return new TestData(mPackageName, mDexFile, mOwnerUserId, mLoaderIsa, 736 mPrimaryOrSplit, newUsedBy, mClassLoaderContext, mOverwriteCLC); 737 } 738 isUsedByOtherApps()739 private boolean isUsedByOtherApps() { 740 return mUsedBy != null && !mPackageName.equals(mUsedBy); 741 } 742 getUsedBy()743 private Set<String> getUsedBy() { 744 Set<String> users = new HashSet<>(); 745 if ((mUsedBy != null) && (mPrimaryOrSplit || isUsedByOtherApps())) { 746 // We do not store the loading package for secondary dex files 747 // which are not used by others. 748 users.add(mUsedBy); 749 } 750 return users; 751 } 752 } 753 } 754