1 /* 2 * Copyright (C) 2019 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.systemconfig; 18 19 import static com.google.common.truth.Truth.assertThat; 20 21 import static org.junit.Assert.assertEquals; 22 import static org.testng.Assert.expectThrows; 23 24 import android.os.Build; 25 import android.platform.test.annotations.Presubmit; 26 import android.util.ArrayMap; 27 import android.util.ArraySet; 28 import android.util.Log; 29 import android.util.Xml; 30 31 import androidx.test.filters.SmallTest; 32 import androidx.test.runner.AndroidJUnit4; 33 34 import com.android.server.SystemConfig; 35 36 import org.junit.Before; 37 import org.junit.Rule; 38 import org.junit.Test; 39 import org.junit.rules.TemporaryFolder; 40 import org.junit.runner.RunWith; 41 import org.xmlpull.v1.XmlPullParser; 42 import org.xmlpull.v1.XmlPullParserException; 43 44 import java.io.BufferedWriter; 45 import java.io.File; 46 import java.io.FileReader; 47 import java.io.FileWriter; 48 import java.io.IOException; 49 import java.util.Arrays; 50 import java.util.Map; 51 import java.util.Scanner; 52 import java.util.Set; 53 54 /** 55 * Tests for {@link SystemConfig}. 56 * 57 * Build/Install/Run: 58 * atest FrameworksServicesTests:SystemConfigTest 59 */ 60 @SmallTest 61 @Presubmit 62 @RunWith(AndroidJUnit4.class) 63 public class SystemConfigTest { 64 private static final String LOG_TAG = "SystemConfigTest"; 65 66 private SystemConfig mSysConfig; 67 private File mFooJar; 68 69 @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder(); 70 71 @Before setUp()72 public void setUp() throws Exception { 73 mSysConfig = new SystemConfigTestClass(); 74 mFooJar = createTempFile( 75 mTemporaryFolder.getRoot().getCanonicalFile(), "foo.jar", "JAR"); 76 } 77 78 /** 79 * Subclass of SystemConfig without running the constructor. 80 */ 81 private class SystemConfigTestClass extends SystemConfig { SystemConfigTestClass()82 SystemConfigTestClass() { 83 super(false); 84 } 85 } 86 readPermissions(File libraryDir, int permissionFlag)87 private void readPermissions(File libraryDir, int permissionFlag) { 88 final XmlPullParser parser = Xml.newPullParser(); 89 mSysConfig.readPermissions(parser, libraryDir, permissionFlag); 90 } 91 92 /** 93 * Tests that readPermissions works correctly for the tag: install-in-user-type 94 */ 95 @Test testInstallInUserType()96 public void testInstallInUserType() throws Exception { 97 final String contents1 = 98 "<permissions>\n" 99 + " <install-in-user-type package=\"com.android.package1\">\n" 100 + " <install-in user-type=\"FULL\" />\n" 101 + " <install-in user-type=\"PROFILE\" />\n" 102 + " </install-in-user-type>\n" 103 + " <install-in-user-type package=\"com.android.package2\">\n" 104 + " <install-in user-type=\"FULL\" />\n" 105 + " <install-in user-type=\"PROFILE\" />\n" 106 + " <do-not-install-in user-type=\"GUEST\" />\n" 107 + " </install-in-user-type>\n" 108 + "</permissions>"; 109 110 final String contents2 = 111 "<permissions>\n" 112 + " <install-in-user-type package=\"com.android.package2\">\n" 113 + " <install-in user-type=\"SYSTEM\" />\n" 114 + " <do-not-install-in user-type=\"PROFILE\" />\n" 115 + " </install-in-user-type>\n" 116 + "</permissions>"; 117 118 final String contents3 = 119 "<permissions>\n" 120 + " <install-in-user-type package=\"com.android.package2\">\n" 121 + " <install-in invalid-attribute=\"ADMIN\" />\n" // Ignore invalid attribute 122 + " </install-in-user-type>\n" 123 + " <install-in-user-type package=\"com.android.package2\">\n" 124 + " <install-in user-type=\"RESTRICTED\" />\n" // Valid 125 + " </install-in-user-type>\n" 126 + " <install-in-user-type>\n" // Ignored since missing package name 127 + " <install-in user-type=\"ADMIN\" />\n" 128 + " </install-in-user-type>\n" 129 + "</permissions>"; 130 131 Map<String, Set<String>> expectedWhite = new ArrayMap<>(); 132 expectedWhite.put("com.android.package1", 133 new ArraySet<>(Arrays.asList("FULL", "PROFILE"))); 134 expectedWhite.put("com.android.package2", 135 new ArraySet<>(Arrays.asList("FULL", "PROFILE", "RESTRICTED", "SYSTEM"))); 136 137 Map<String, Set<String>> expectedBlack = new ArrayMap<>(); 138 expectedBlack.put("com.android.package2", 139 new ArraySet<>(Arrays.asList("GUEST", "PROFILE"))); 140 141 final File folder1 = createTempSubfolder("folder1"); 142 createTempFile(folder1, "permissionFile1.xml", contents1); 143 144 final File folder2 = createTempSubfolder("folder2"); 145 createTempFile(folder2, "permissionFile2.xml", contents2); 146 147 // Also, make a third file, but with the name folder1/permissionFile2.xml, to prove no 148 // conflicts. 149 createTempFile(folder1, "permissionFile2.xml", contents3); 150 151 readPermissions(folder1, /* No permission needed anyway */ 0); 152 readPermissions(folder2, /* No permission needed anyway */ 0); 153 154 Map<String, Set<String>> actualWhite = mSysConfig.getAndClearPackageToUserTypeWhitelist(); 155 Map<String, Set<String>> actualBlack = mSysConfig.getAndClearPackageToUserTypeBlacklist(); 156 157 assertEquals("Whitelist was not cleared", 0, 158 mSysConfig.getAndClearPackageToUserTypeWhitelist().size()); 159 assertEquals("Blacklist was not cleared", 0, 160 mSysConfig.getAndClearPackageToUserTypeBlacklist().size()); 161 162 assertEquals("Incorrect whitelist.", expectedWhite, actualWhite); 163 assertEquals("Incorrect blacklist", expectedBlack, actualBlack); 164 } 165 166 @Test testComponentOverride()167 public void testComponentOverride() throws Exception { 168 final String contents = 169 "<permissions>" 170 + " <component-override package=\"com.android.package1\">\n" 171 + " <component class=\"com.android.package1.Full\" enabled=\"true\"/>" 172 + " <component class=\".Relative\" enabled=\"false\" />\n" 173 + " </component-override>" 174 + " <component-override package=\"com.android.package2\" >\n" 175 + " <component class=\"com.android.package3.Relative2\" enabled=\"yes\" />\n" 176 + " </component-override>\n" 177 + "</permissions>"; 178 179 final File folder = createTempSubfolder("folder"); 180 createTempFile(folder, "component-override.xml", contents); 181 182 readPermissions(folder, /* No permission needed anyway */ 0); 183 184 final ArrayMap<String, Boolean> packageOneExpected = new ArrayMap<>(); 185 packageOneExpected.put("com.android.package1.Full", true); 186 packageOneExpected.put("com.android.package1.Relative", false); 187 188 final ArrayMap<String, Boolean> packageTwoExpected = new ArrayMap<>(); 189 packageTwoExpected.put("com.android.package3.Relative2", true); 190 191 final Map<String, Boolean> packageOne = mSysConfig.getComponentsEnabledStates( 192 "com.android.package1"); 193 assertEquals(packageOneExpected, packageOne); 194 195 final Map<String, Boolean> packageTwo = mSysConfig.getComponentsEnabledStates( 196 "com.android.package2"); 197 assertEquals(packageTwoExpected, packageTwo); 198 } 199 200 /** 201 * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_APP_CONFIGS} 202 * permission flag for the tag: allowlisted-staged-installer. 203 */ 204 @Test readPermissions_allowAppConfigs_parsesStagedInstallerWhitelist()205 public void readPermissions_allowAppConfigs_parsesStagedInstallerWhitelist() 206 throws IOException { 207 final String contents = 208 "<config>\n" 209 + " <whitelisted-staged-installer package=\"com.android.package1\" />\n" 210 + "</config>"; 211 final File folder = createTempSubfolder("folder"); 212 createTempFile(folder, "staged-installer-whitelist.xml", contents); 213 214 readPermissions(folder, /* Grant all permission flags */ ~0); 215 216 assertThat(mSysConfig.getWhitelistedStagedInstallers()) 217 .containsExactly("com.android.package1"); 218 assertThat(mSysConfig.getModulesInstallerPackageName()).isNull(); 219 } 220 221 @Test readPermissions_parsesStagedInstallerWhitelist_modulesInstaller()222 public void readPermissions_parsesStagedInstallerWhitelist_modulesInstaller() 223 throws IOException { 224 final String contents = 225 "<config>\n" 226 + " <whitelisted-staged-installer package=\"com.android.package1\" " 227 + " isModulesInstaller=\"true\" />\n" 228 + "</config>"; 229 final File folder = createTempSubfolder("folder"); 230 createTempFile(folder, "staged-installer-whitelist.xml", contents); 231 232 readPermissions(folder, /* Grant all permission flags */ ~0); 233 234 assertThat(mSysConfig.getWhitelistedStagedInstallers()) 235 .containsExactly("com.android.package1"); 236 assertThat(mSysConfig.getModulesInstallerPackageName()) 237 .isEqualTo("com.android.package1"); 238 } 239 240 @Test readPermissions_parsesStagedInstallerWhitelist_multipleModulesInstallers()241 public void readPermissions_parsesStagedInstallerWhitelist_multipleModulesInstallers() 242 throws IOException { 243 final String contents = 244 "<config>\n" 245 + " <whitelisted-staged-installer package=\"com.android.package1\" " 246 + " isModulesInstaller=\"true\" />\n" 247 + " <whitelisted-staged-installer package=\"com.android.package2\" " 248 + " isModulesInstaller=\"true\" />\n" 249 + "</config>"; 250 final File folder = createTempSubfolder("folder"); 251 createTempFile(folder, "staged-installer-whitelist.xml", contents); 252 253 IllegalStateException e = expectThrows( 254 IllegalStateException.class, 255 () -> readPermissions(folder, /* Grant all permission flags */ ~0)); 256 257 assertThat(e).hasMessageThat().contains("Multiple modules installers"); 258 } 259 260 /** 261 * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_APP_CONFIGS} 262 * permission flag for the tag: allowlisted-staged-installer. 263 */ 264 @Test readPermissions_notAllowAppConfigs_wontParseStagedInstallerWhitelist()265 public void readPermissions_notAllowAppConfigs_wontParseStagedInstallerWhitelist() 266 throws IOException { 267 final String contents = 268 "<config>\n" 269 + " <whitelisted-staged-installer package=\"com.android.package1\" />\n" 270 + "</config>"; 271 final File folder = createTempSubfolder("folder"); 272 createTempFile(folder, "staged-installer-whitelist.xml", contents); 273 274 readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); 275 276 assertThat(mSysConfig.getWhitelistedStagedInstallers()).isEmpty(); 277 } 278 279 /** 280 * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX} 281 * permission flag for the tag: {@code allowed-vendor-apex}. 282 */ 283 @Test readPermissions_allowVendorApex_parsesVendorApexAllowList()284 public void readPermissions_allowVendorApex_parsesVendorApexAllowList() 285 throws IOException { 286 final String contents = 287 "<config>\n" 288 + " <allowed-vendor-apex package=\"com.android.apex1\" " 289 + "installerPackage=\"com.installer\" />\n" 290 + "</config>"; 291 final File folder = createTempSubfolder("folder"); 292 createTempFile(folder, "vendor-apex-allowlist.xml", contents); 293 294 readPermissions(folder, /* Grant all permission flags */ ~0); 295 296 assertThat(mSysConfig.getAllowedVendorApexes()) 297 .containsExactly("com.android.apex1", "com.installer"); 298 } 299 300 /** 301 * Tests that readPermissions works correctly with {@link SystemConfig#ALLOW_VENDOR_APEX} 302 * permission flag for the tag: {@code allowed-vendor-apex}. 303 */ 304 @Test readPermissions_allowVendorApex_parsesVendorApexAllowList_noPackage()305 public void readPermissions_allowVendorApex_parsesVendorApexAllowList_noPackage() 306 throws IOException { 307 final String contents = 308 "<config>\n" 309 + " <allowed-vendor-apex/>\n" 310 + "</config>"; 311 final File folder = createTempSubfolder("folder"); 312 createTempFile(folder, "vendor-apex-allowlist.xml", contents); 313 314 readPermissions(folder, /* Grant all permission flags */ ~0); 315 316 assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); 317 } 318 319 320 /** 321 * Tests that readPermissions works correctly without {@link SystemConfig#ALLOW_VENDOR_APEX} 322 * permission flag for the tag: {@code allowed-oem-apex}. 323 */ 324 @Test readPermissions_notAllowVendorApex_doesNotParseVendorApexAllowList()325 public void readPermissions_notAllowVendorApex_doesNotParseVendorApexAllowList() 326 throws IOException { 327 final String contents = 328 "<config>\n" 329 + " <allowed-vendor-apex package=\"com.android.apex1\" />\n" 330 + "</config>"; 331 final File folder = createTempSubfolder("folder"); 332 createTempFile(folder, "vendor-apex-allowlist.xml", contents); 333 334 readPermissions(folder, /* Grant all but ALLOW_VENDOR_APEX flag */ ~0x400); 335 336 assertThat(mSysConfig.getAllowedVendorApexes()).isEmpty(); 337 } 338 339 /** 340 * Tests that readPermissions works correctly for the tag: {@code install-constraints-allowed}. 341 */ 342 @Test readPermissions_installConstraints_successful()343 public void readPermissions_installConstraints_successful() throws IOException { 344 final String contents = 345 "<config>\n" 346 + " <install-constraints-allowed package=\"com.android.apex1\" />\n" 347 + "</config>"; 348 final File folder = createTempSubfolder("folder"); 349 createTempFile(folder, "install-constraints-allowlist.xml", contents); 350 351 readPermissions(folder, /* Grant all permission flags */ ~0); 352 353 assertThat(mSysConfig.getInstallConstraintsAllowlist()) 354 .containsExactly("com.android.apex1"); 355 } 356 357 /** 358 * Tests that readPermissions works correctly for the tag: {@code install-constraints-allowed}. 359 */ 360 @Test readPermissions_installConstraints_noPackage()361 public void readPermissions_installConstraints_noPackage() throws IOException { 362 final String contents = 363 "<config>\n" 364 + " <install-constraints-allowed/>\n" 365 + "</config>"; 366 final File folder = createTempSubfolder("folder"); 367 createTempFile(folder, "install-constraints-allowlist.xml", contents); 368 369 readPermissions(folder, /* Grant all permission flags */ ~0); 370 371 assertThat(mSysConfig.getInstallConstraintsAllowlist()).isEmpty(); 372 } 373 374 /** 375 * Tests that readPermissions works correctly for the tag {@code install-constraints-allowed} 376 * without {@link SystemConfig#ALLOW_VENDOR_APEX}. 377 */ 378 @Test readPermissions_installConstraints_noAppConfigs()379 public void readPermissions_installConstraints_noAppConfigs() throws IOException { 380 final String contents = 381 "<config>\n" 382 + " <install-constraints-allowed package=\"com.android.apex1\" />\n" 383 + "</config>"; 384 final File folder = createTempSubfolder("folder"); 385 createTempFile(folder, "install-constraints-allowlist.xml", contents); 386 387 readPermissions(folder, /* Grant all but ALLOW_APP_CONFIGS flag */ ~0x08); 388 389 assertThat(mSysConfig.getInstallConstraintsAllowlist()).isEmpty(); 390 } 391 392 @Test readApexPrivAppPermissions_addAllPermissions()393 public void readApexPrivAppPermissions_addAllPermissions() 394 throws Exception { 395 final String contents = 396 "<privapp-permissions package=\"com.android.apk_in_apex\">" 397 + "<permission name=\"android.permission.FOO\"/>" 398 + "<deny-permission name=\"android.permission.BAR\"/>" 399 + "</privapp-permissions>"; 400 File apexDir = createTempSubfolder("apex"); 401 File permissionFile = createTempFile( 402 createTempSubfolder("apex/com.android.my_module/etc/permissions"), 403 "permissions.xml", contents); 404 XmlPullParser parser = readXmlUntilStartTag(permissionFile); 405 406 mSysConfig.readApexPrivAppPermissions(parser, permissionFile, apexDir.toPath()); 407 408 ArrayMap<String, Boolean> permissions = mSysConfig.getPermissionAllowlist() 409 .getApexPrivilegedAppAllowlists().get("com.android.my_module") 410 .get("com.android.apk_in_apex"); 411 assertThat(permissions) 412 .containsExactly("android.permission.FOO", true, "android.permission.BAR", false); 413 } 414 415 /** 416 * Tests that readPermissions works correctly for a library with on-bootclasspath-before 417 * and on-bootclasspath-since. 418 */ 419 @Test readPermissions_allowLibs_parsesSimpleLibrary()420 public void readPermissions_allowLibs_parsesSimpleLibrary() throws IOException { 421 String contents = 422 "<permissions>\n" 423 + " <library \n" 424 + " name=\"foo\"\n" 425 + " file=\"" + mFooJar + "\"\n" 426 + " on-bootclasspath-before=\"10\"\n" 427 + " on-bootclasspath-since=\"20\"\n" 428 + " />\n\n" 429 + " </permissions>"; 430 parseSharedLibraries(contents); 431 assertFooIsOnlySharedLibrary(); 432 SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); 433 assertThat(entry.onBootclasspathBefore).isEqualTo("10"); 434 assertThat(entry.onBootclasspathSince).isEqualTo("20"); 435 } 436 437 /** 438 * Tests that readPermissions works correctly for a library with on-bootclasspath-before 439 * and on-bootclasspath-since that uses codenames. 440 */ 441 @Test readPermissions_allowLibs_parsesSimpleLibraryWithCodenames()442 public void readPermissions_allowLibs_parsesSimpleLibraryWithCodenames() throws IOException { 443 String contents = 444 "<permissions>\n" 445 + " <library \n" 446 + " name=\"foo\"\n" 447 + " file=\"" + mFooJar + "\"\n" 448 + " on-bootclasspath-before=\"Q\"\n" 449 + " on-bootclasspath-since=\"W\"\n" 450 + " />\n\n" 451 + " </permissions>"; 452 parseSharedLibraries(contents); 453 assertFooIsOnlySharedLibrary(); 454 SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); 455 assertThat(entry.onBootclasspathBefore).isEqualTo("Q"); 456 assertThat(entry.onBootclasspathSince).isEqualTo("W"); 457 } 458 459 /** 460 * Tests that readPermissions works correctly for a library using the new 461 * {@code apex-library} tag. 462 */ 463 @Test readPermissions_allowLibs_parsesUpdatableLibrary()464 public void readPermissions_allowLibs_parsesUpdatableLibrary() throws IOException { 465 String contents = 466 "<permissions>\n" 467 + " <apex-library \n" 468 + " name=\"foo\"\n" 469 + " file=\"" + mFooJar + "\"\n" 470 + " on-bootclasspath-before=\"10\"\n" 471 + " on-bootclasspath-since=\"20\"\n" 472 + " />\n\n" 473 + " </permissions>"; 474 parseSharedLibraries(contents); 475 assertFooIsOnlySharedLibrary(); 476 SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); 477 assertThat(entry.onBootclasspathBefore).isEqualTo("10"); 478 assertThat(entry.onBootclasspathSince).isEqualTo("20"); 479 } 480 481 /** 482 * Tests that readPermissions for a library with {@code min-device-sdk} lower than the current 483 * SDK results in the library being added to the shared libraries. 484 */ 485 @Test readPermissions_allowLibs_allowsOldMinSdk()486 public void readPermissions_allowLibs_allowsOldMinSdk() throws IOException { 487 String contents = 488 "<permissions>\n" 489 + " <library \n" 490 + " name=\"foo\"\n" 491 + " file=\"" + mFooJar + "\"\n" 492 + " min-device-sdk=\"30\"\n" 493 + " />\n\n" 494 + " </permissions>"; 495 parseSharedLibraries(contents); 496 assertFooIsOnlySharedLibrary(); 497 } 498 499 /** 500 * Tests that readPermissions for a library with {@code min-device-sdk} equal to the current 501 * SDK results in the library being added to the shared libraries. 502 */ 503 @Test readPermissions_allowLibs_allowsCurrentMinSdk()504 public void readPermissions_allowLibs_allowsCurrentMinSdk() throws IOException { 505 String contents = 506 "<permissions>\n" 507 + " <library \n" 508 + " name=\"foo\"\n" 509 + " file=\"" + mFooJar + "\"\n" 510 + " min-device-sdk=\"" + Build.VERSION.SDK_INT + "\"\n" 511 + " />\n\n" 512 + " </permissions>"; 513 parseSharedLibraries(contents); 514 assertFooIsOnlySharedLibrary(); 515 } 516 517 /** 518 * Tests that readPermissions for a library with {@code min-device-sdk} greater than the current 519 * SDK results in the library being ignored. 520 */ 521 @Test readPermissions_allowLibs_ignoresMinSdkInFuture()522 public void readPermissions_allowLibs_ignoresMinSdkInFuture() throws IOException { 523 String contents = 524 "<permissions>\n" 525 + " <library \n" 526 + " name=\"foo\"\n" 527 + " file=\"" + mFooJar + "\"\n" 528 + " min-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n" 529 + " />\n\n" 530 + " </permissions>"; 531 parseSharedLibraries(contents); 532 assertThat(mSysConfig.getSharedLibraries()).isEmpty(); 533 } 534 535 /** 536 * Tests that readPermissions for a library with {@code max-device-sdk} less than the current 537 * SDK results in the library being ignored. 538 */ 539 @Test readPermissions_allowLibs_ignoredOldMaxSdk()540 public void readPermissions_allowLibs_ignoredOldMaxSdk() throws IOException { 541 String contents = 542 "<permissions>\n" 543 + " <library \n" 544 + " name=\"foo\"\n" 545 + " file=\"" + mFooJar + "\"\n" 546 + " max-device-sdk=\"30\"\n" 547 + " />\n\n" 548 + " </permissions>"; 549 parseSharedLibraries(contents); 550 assertThat(mSysConfig.getSharedLibraries()).isEmpty(); 551 } 552 553 /** 554 * Tests that readPermissions for a library with {@code max-device-sdk} equal to the current 555 * SDK results in the library being added to the shared libraries. 556 */ 557 @Test readPermissions_allowLibs_allowsCurrentMaxSdk()558 public void readPermissions_allowLibs_allowsCurrentMaxSdk() throws IOException { 559 // depending on whether this test is running before or after finalization, we need to 560 // pass a different parameter 561 String parameter; 562 if ("REL".equals(Build.VERSION.CODENAME)) { 563 parameter = "" + Build.VERSION.SDK_INT; 564 } else { 565 parameter = "ZZZ"; 566 } 567 String contents = 568 "<permissions>\n" 569 + " <library \n" 570 + " name=\"foo\"\n" 571 + " file=\"" + mFooJar + "\"\n" 572 + " max-device-sdk=\"" + parameter + "\"\n" 573 + " />\n\n" 574 + " </permissions>"; 575 parseSharedLibraries(contents); 576 assertFooIsOnlySharedLibrary(); 577 } 578 579 /** 580 * Tests that readPermissions for a library with {@code max-device-sdk} greater than the current 581 * SDK results in the library being added to the shared libraries. 582 */ 583 @Test readPermissions_allowLibs_allowsMaxSdkInFuture()584 public void readPermissions_allowLibs_allowsMaxSdkInFuture() throws IOException { 585 String contents = 586 "<permissions>\n" 587 + " <library \n" 588 + " name=\"foo\"\n" 589 + " file=\"" + mFooJar + "\"\n" 590 + " max-device-sdk=\"" + (Build.VERSION.SDK_INT + 1) + "\"\n" 591 + " />\n\n" 592 + " </permissions>"; 593 parseSharedLibraries(contents); 594 assertFooIsOnlySharedLibrary(); 595 } 596 597 /** 598 * Test that getRollbackDenylistedPackages works correctly for the tag: 599 * {@code automatic-rollback-denylisted-app}. 600 */ 601 @Test automaticRollbackDeny_vending()602 public void automaticRollbackDeny_vending() throws IOException { 603 final String contents = 604 "<config>\n" 605 + " <automatic-rollback-denylisted-app package=\"com.android.vending\" />\n" 606 + "</config>"; 607 final File folder = createTempSubfolder("folder"); 608 createTempFile(folder, "automatic-rollback-denylisted-app.xml", contents); 609 610 readPermissions(folder, /* Grant all permission flags */ ~0); 611 612 assertThat(mSysConfig.getAutomaticRollbackDenylistedPackages()) 613 .containsExactly("com.android.vending"); 614 } 615 616 /** 617 * Test that getRollbackDenylistedPackages works correctly for the tag: 618 * {@code automatic-rollback-denylisted-app} without any packages. 619 */ 620 @Test automaticRollbackDeny_empty()621 public void automaticRollbackDeny_empty() throws IOException { 622 final String contents = 623 "<config>\n" 624 + " <automatic-rollback-denylisted-app />\n" 625 + "</config>"; 626 final File folder = createTempSubfolder("folder"); 627 createTempFile(folder, "automatic-rollback-denylisted-app.xml", contents); 628 629 readPermissions(folder, /* Grant all permission flags */ ~0); 630 631 assertThat(mSysConfig.getAutomaticRollbackDenylistedPackages()).isEmpty(); 632 } 633 634 /** 635 * Test that getRollbackDenylistedPackages works correctly for the tag: 636 * {@code automatic-rollback-denylisted-app} without the corresponding config. 637 */ 638 @Test automaticRollbackDeny_noConfig()639 public void automaticRollbackDeny_noConfig() throws IOException { 640 final File folder = createTempSubfolder("folder"); 641 642 readPermissions(folder, /* Grant all permission flags */ ~0); 643 644 assertThat(mSysConfig.getAutomaticRollbackDenylistedPackages()).isEmpty(); 645 } 646 647 /** 648 * Tests that readPermissions works correctly for the tag: {@code update-ownership}. 649 */ 650 @Test readPermissions_updateOwnership_successful()651 public void readPermissions_updateOwnership_successful() throws IOException { 652 final String contents = 653 "<config>\n" 654 + " <update-ownership package=\"com.foo\" installer=\"com.bar\" />\n" 655 + "</config>"; 656 final File folder = createTempSubfolder("folder"); 657 createTempFile(folder, "update_ownership.xml", contents); 658 659 readPermissions(folder, /* Grant all permission flags */ ~0); 660 661 assertThat(mSysConfig.getSystemAppUpdateOwnerPackageName("com.foo")) 662 .isEqualTo("com.bar"); 663 } 664 665 /** 666 * Tests that readPermissions works correctly for the tag: {@code update-ownership}. 667 */ 668 @Test readPermissions_updateOwnership_noPackage()669 public void readPermissions_updateOwnership_noPackage() throws IOException { 670 final String contents = 671 "<config>\n" 672 + " <update-ownership />\n" 673 + "</config>"; 674 final File folder = createTempSubfolder("folder"); 675 createTempFile(folder, "update_ownership.xml", contents); 676 677 readPermissions(folder, /* Grant all permission flags */ ~0); 678 679 assertThat(mSysConfig.getSystemAppUpdateOwnerPackageName("com.foo")).isNull(); 680 } 681 682 /** 683 * Tests that readPermissions works correctly for the tag: {@code update-ownership}. 684 */ 685 @Test readPermissions_updateOwnership_noInstaller()686 public void readPermissions_updateOwnership_noInstaller() throws IOException { 687 final String contents = 688 "<config>\n" 689 + " <update-ownership package=\"com.foo\" />\n" 690 + "</config>"; 691 final File folder = createTempSubfolder("folder"); 692 createTempFile(folder, "update_ownership.xml", contents); 693 694 readPermissions(folder, /* Grant all permission flags */ ~0); 695 696 assertThat(mSysConfig.getSystemAppUpdateOwnerPackageName("com.foo")).isNull(); 697 } 698 parseSharedLibraries(String contents)699 private void parseSharedLibraries(String contents) throws IOException { 700 File folder = createTempSubfolder("permissions_folder"); 701 createTempFile(folder, "permissions.xml", contents); 702 readPermissions(folder, /* permissionFlag = ALLOW_LIBS */ 0x02); 703 } 704 705 /** 706 * Create an {@link XmlPullParser} for {@param permissionFile} and begin parsing it until 707 * reaching the root tag. 708 */ readXmlUntilStartTag(File permissionFile)709 private XmlPullParser readXmlUntilStartTag(File permissionFile) 710 throws IOException, XmlPullParserException { 711 FileReader permReader = new FileReader(permissionFile); 712 XmlPullParser parser = Xml.newPullParser(); 713 parser.setInput(permReader); 714 int type; 715 do { 716 type = parser.next(); 717 } while (type != parser.START_TAG && type != parser.END_DOCUMENT); 718 if (type != parser.START_TAG) { 719 throw new XmlPullParserException("No start tag found"); 720 } 721 return parser; 722 } 723 724 /** 725 * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. 726 * 727 * @param folderName subdirectory of mTemporaryFolder to put the file, creating if needed 728 * @return the folder 729 */ createTempSubfolder(String folderName)730 private File createTempSubfolder(String folderName) 731 throws IOException { 732 File folder = new File(mTemporaryFolder.getRoot(), folderName); 733 folder.mkdirs(); 734 return folder; 735 } 736 737 /** 738 * Creates folderName/fileName in the mTemporaryFolder and fills it with the contents. 739 * 740 * @param folder pre-existing subdirectory of mTemporaryFolder to put the file 741 * @param fileName name of the file (e.g. filename.xml) to create 742 * @param contents contents to write to the file 743 * @return the newly created file 744 */ createTempFile(File folder, String fileName, String contents)745 private File createTempFile(File folder, String fileName, String contents) 746 throws IOException { 747 File file = new File(folder, fileName); 748 BufferedWriter bw = new BufferedWriter(new FileWriter(file)); 749 bw.write(contents); 750 bw.close(); 751 752 // Print to logcat for test debugging. 753 Log.d(LOG_TAG, "Contents of file " + file.getAbsolutePath()); 754 Scanner input = new Scanner(file); 755 while (input.hasNextLine()) { 756 Log.d(LOG_TAG, input.nextLine()); 757 } 758 759 return file; 760 } 761 assertFooIsOnlySharedLibrary()762 private void assertFooIsOnlySharedLibrary() { 763 assertThat(mSysConfig.getSharedLibraries().size()).isEqualTo(1); 764 SystemConfig.SharedLibraryEntry entry = mSysConfig.getSharedLibraries().get("foo"); 765 assertThat(entry.name).isEqualTo("foo"); 766 assertThat(entry.filename).isEqualTo(mFooJar.toString()); 767 } 768 } 769