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 android.content.pm; 18 19 import static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertNotNull; 21 import static org.junit.Assert.assertNull; 22 import static org.junit.Assert.assertTrue; 23 24 import android.content.Context; 25 import android.content.pm.PackageParser.Component; 26 import android.content.pm.PackageParser.Package; 27 import android.content.pm.PackageParser.Permission; 28 import android.os.Build; 29 import android.os.Bundle; 30 import android.os.FileUtils; 31 import android.os.SystemProperties; 32 import android.support.test.InstrumentationRegistry; 33 import android.support.test.runner.AndroidJUnit4; 34 import android.test.suitebuilder.annotation.SmallTest; 35 36 import com.android.frameworks.coretests.R; 37 38 import org.junit.Test; 39 import org.junit.runner.RunWith; 40 41 import java.io.File; 42 import java.io.InputStream; 43 import java.util.Arrays; 44 import java.util.function.Function; 45 46 @SmallTest 47 @RunWith(AndroidJUnit4.class) 48 public class PackageParserTest { 49 private static final String RELEASED = null; 50 private static final String OLDER_PRE_RELEASE = "A"; 51 private static final String PRE_RELEASE = "B"; 52 private static final String NEWER_PRE_RELEASE = "C"; 53 54 private static final String[] CODENAMES_RELEASED = { /* empty */ }; 55 private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE }; 56 57 private static final int OLDER_VERSION = 10; 58 private static final int PLATFORM_VERSION = 20; 59 private static final int NEWER_VERSION = 30; 60 verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename, boolean isPlatformReleased, int expectedMinSdk)61 private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename, 62 boolean isPlatformReleased, int expectedMinSdk) { 63 final String[] outError = new String[1]; 64 final int result = PackageParser.computeMinSdkVersion( 65 minSdkVersion, 66 minSdkCodename, 67 PLATFORM_VERSION, 68 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE, 69 outError); 70 71 assertEquals(result, expectedMinSdk); 72 73 if (expectedMinSdk == -1) { 74 assertNotNull(outError[0]); 75 } else { 76 assertNull(outError[0]); 77 } 78 } 79 80 @Test testComputeMinSdkVersion_preReleasePlatform()81 public void testComputeMinSdkVersion_preReleasePlatform() { 82 // Do allow older release minSdkVersion on pre-release platform. 83 // APP: Released API 10 84 // DEV: Pre-release API 20 85 verifyComputeMinSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION); 86 87 // Do allow same release minSdkVersion on pre-release platform. 88 // APP: Released API 20 89 // DEV: Pre-release API 20 90 verifyComputeMinSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION); 91 92 // Don't allow newer release minSdkVersion on pre-release platform. 93 // APP: Released API 30 94 // DEV: Pre-release API 20 95 verifyComputeMinSdkVersion(NEWER_VERSION, RELEASED, false, -1); 96 97 // Don't allow older pre-release minSdkVersion on pre-release platform. 98 // APP: Pre-release API 10 99 // DEV: Pre-release API 20 100 verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1); 101 102 // Do allow same pre-release minSdkVersion on pre-release platform, 103 // but overwrite the specified version with CUR_DEVELOPMENT. 104 // APP: Pre-release API 20 105 // DEV: Pre-release API 20 106 verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false, 107 Build.VERSION_CODES.CUR_DEVELOPMENT); 108 109 // Don't allow newer pre-release minSdkVersion on pre-release platform. 110 // APP: Pre-release API 30 111 // DEV: Pre-release API 20 112 verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1); 113 } 114 115 @Test testComputeMinSdkVersion_releasedPlatform()116 public void testComputeMinSdkVersion_releasedPlatform() { 117 // Do allow older release minSdkVersion on released platform. 118 // APP: Released API 10 119 // DEV: Released API 20 120 verifyComputeMinSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION); 121 122 // Do allow same release minSdkVersion on released platform. 123 // APP: Released API 20 124 // DEV: Released API 20 125 verifyComputeMinSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION); 126 127 // Don't allow newer release minSdkVersion on released platform. 128 // APP: Released API 30 129 // DEV: Released API 20 130 verifyComputeMinSdkVersion(NEWER_VERSION, RELEASED, true, -1); 131 132 // Don't allow older pre-release minSdkVersion on released platform. 133 // APP: Pre-release API 10 134 // DEV: Released API 20 135 verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1); 136 137 // Don't allow same pre-release minSdkVersion on released platform. 138 // APP: Pre-release API 20 139 // DEV: Released API 20 140 verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1); 141 142 // Don't allow newer pre-release minSdkVersion on released platform. 143 // APP: Pre-release API 30 144 // DEV: Released API 20 145 verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1); 146 } 147 verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename, boolean isPlatformReleased, int expectedTargetSdk, boolean forceCurrentDev)148 private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename, 149 boolean isPlatformReleased, int expectedTargetSdk, boolean forceCurrentDev) { 150 final String[] outError = new String[1]; 151 final int result = PackageParser.computeTargetSdkVersion( 152 targetSdkVersion, 153 targetSdkCodename, 154 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE, 155 outError, 156 forceCurrentDev); 157 158 assertEquals(result, expectedTargetSdk); 159 160 if (expectedTargetSdk == -1) { 161 assertNotNull(outError[0]); 162 } else { 163 assertNull(outError[0]); 164 } 165 } 166 167 @Test testComputeTargetSdkVersion_preReleasePlatform()168 public void testComputeTargetSdkVersion_preReleasePlatform() { 169 // Do allow older release targetSdkVersion on pre-release platform. 170 // APP: Released API 10 171 // DEV: Pre-release API 20 172 verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION, 173 false /* forceCurrentDev */); 174 175 // Do allow same release targetSdkVersion on pre-release platform. 176 // APP: Released API 20 177 // DEV: Pre-release API 20 178 verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION, 179 false /* forceCurrentDev */); 180 181 // Do allow newer release targetSdkVersion on pre-release platform. 182 // APP: Released API 30 183 // DEV: Pre-release API 20 184 verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION, 185 false /* forceCurrentDev */); 186 187 // Don't allow older pre-release targetSdkVersion on pre-release platform. 188 // APP: Pre-release API 10 189 // DEV: Pre-release API 20 190 verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1, 191 false /* forceCurrentDev */); 192 193 // Do allow same pre-release targetSdkVersion on pre-release platform, 194 // but overwrite the specified version with CUR_DEVELOPMENT. 195 // APP: Pre-release API 20 196 // DEV: Pre-release API 20 197 verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false, 198 Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */); 199 200 // Don't allow newer pre-release targetSdkVersion on pre-release platform. 201 // APP: Pre-release API 30 202 // DEV: Pre-release API 20 203 verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1, 204 false /* forceCurrentDev */); 205 206 // Force newer pre-release targetSdkVersion to current pre-release platform. 207 // APP: Pre-release API 30 208 // DEV: Pre-release API 20 209 verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, 210 Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */); 211 } 212 213 @Test testComputeTargetSdkVersion_releasedPlatform()214 public void testComputeTargetSdkVersion_releasedPlatform() { 215 // Do allow older release targetSdkVersion on released platform. 216 // APP: Released API 10 217 // DEV: Released API 20 218 verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION, 219 false /* forceCurrentDev */); 220 221 // Do allow same release targetSdkVersion on released platform. 222 // APP: Released API 20 223 // DEV: Released API 20 224 verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION, 225 false /* forceCurrentDev */); 226 227 // Do allow newer release targetSdkVersion on released platform. 228 // APP: Released API 30 229 // DEV: Released API 20 230 verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION, 231 false /* forceCurrentDev */); 232 233 // Don't allow older pre-release targetSdkVersion on released platform. 234 // APP: Pre-release API 10 235 // DEV: Released API 20 236 verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1, 237 false /* forceCurrentDev */); 238 239 // Don't allow same pre-release targetSdkVersion on released platform. 240 // APP: Pre-release API 20 241 // DEV: Released API 20 242 verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1, 243 false /* forceCurrentDev */); 244 245 // Don't allow newer pre-release targetSdkVersion on released platform. 246 // APP: Pre-release API 30 247 // DEV: Released API 20 248 verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1, 249 false /* forceCurrentDev */); 250 } 251 252 /** 253 * Unit test for PackageParser.getActivityConfigChanges(). 254 * If the bit is 1 in the original configChanges, it is still 1 in the final configChanges. 255 * If the bit is 0 in the original configChanges and the bit is not set to 1 in 256 * recreateOnConfigChanges, the bit is changed to 1 in the final configChanges by default. 257 */ 258 @Test testGetActivityConfigChanges()259 public void testGetActivityConfigChanges() { 260 // Not set in either configChanges or recreateOnConfigChanges. 261 int configChanges = 0x0000; // 00000000. 262 int recreateOnConfigChanges = 0x0000; // 00000000. 263 int finalConfigChanges = 264 PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges); 265 assertEquals(0x0003, finalConfigChanges); // Should be 00000011. 266 267 // Not set in configChanges, but set in recreateOnConfigChanges. 268 configChanges = 0x0000; // 00000000. 269 recreateOnConfigChanges = 0x0003; // 00000011. 270 finalConfigChanges = 271 PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges); 272 assertEquals(0x0000, finalConfigChanges); // Should be 00000000. 273 274 // Set in configChanges. 275 configChanges = 0x0003; // 00000011. 276 recreateOnConfigChanges = 0X0000; // 00000000. 277 finalConfigChanges = 278 PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges); 279 assertEquals(0x0003, finalConfigChanges); // Should be 00000011. 280 281 recreateOnConfigChanges = 0x0003; // 00000011. 282 finalConfigChanges = 283 PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges); 284 assertEquals(0x0003, finalConfigChanges); // Should still be 00000011. 285 286 // Other bit set in configChanges. 287 configChanges = 0x0080; // 10000000, orientation. 288 recreateOnConfigChanges = 0x0000; // 00000000. 289 finalConfigChanges = 290 PackageParser.getActivityConfigChanges(configChanges, recreateOnConfigChanges); 291 assertEquals(0x0083, finalConfigChanges); // Should be 10000011. 292 } 293 parsePackage(String apkFileName, int apkResourceId)294 Package parsePackage(String apkFileName, int apkResourceId) throws Exception { 295 return parsePackage(apkFileName, apkResourceId, p -> p); 296 } 297 298 /** 299 * Attempts to parse a package. 300 * 301 * APKs are put into coretests/apks/packageparser_*. 302 * 303 * @param apkFileName temporary file name to store apk extracted from resources 304 * @param apkResourceId identifier of the apk as a resource 305 */ parsePackage(String apkFileName, int apkResourceId, Function<Package, Package> converter)306 Package parsePackage(String apkFileName, int apkResourceId, 307 Function<Package, Package> converter) throws Exception { 308 // Copy the resource to a file. 309 Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); 310 File outFile = new File(context.getFilesDir(), apkFileName); 311 try { 312 InputStream is = context.getResources().openRawResource(apkResourceId); 313 assertTrue(FileUtils.copyToFile(is, outFile)); 314 return converter.apply(new PackageParser().parsePackage(outFile, 0 /* flags */)); 315 } finally { 316 outFile.delete(); 317 } 318 } 319 320 /** 321 * Asserts basic properties about a component. 322 */ assertComponent(String className, String packageName, int numIntents, Component<?> component)323 private void assertComponent(String className, String packageName, int numIntents, 324 Component<?> component) { 325 assertEquals(className, component.className); 326 assertEquals(packageName, component.owner.packageName); 327 assertEquals(numIntents, component.intents.size()); 328 } 329 330 /** 331 * Asserts four regularly-named components of each type: one Activity, one Service, one 332 * Provider, and one Receiver. 333 * @param template templated string with %s subbed with Activity, Service, Provider, Receiver 334 */ assertOneComponentOfEachType(String template, Package p)335 private void assertOneComponentOfEachType(String template, Package p) { 336 String packageName = p.packageName; 337 338 assertEquals(1, p.activities.size()); 339 assertComponent(String.format(template, "Activity"), 340 packageName, 0 /* intents */, p.activities.get(0)); 341 assertEquals(1, p.services.size()); 342 assertComponent(String.format(template, "Service"), 343 packageName, 0 /* intents */, p.services.get(0)); 344 assertEquals(1, p.providers.size()); 345 assertComponent(String.format(template, "Provider"), 346 packageName, 0 /* intents */, p.providers.get(0)); 347 assertEquals(1, p.receivers.size()); 348 assertComponent(String.format(template, "Receiver"), 349 packageName, 0 /* intents */, p.receivers.get(0)); 350 } 351 assertPermission(String name, String packageName, int protectionLevel, Permission permission)352 private void assertPermission(String name, String packageName, int protectionLevel, 353 Permission permission) { 354 assertEquals(packageName, permission.owner.packageName); 355 assertEquals(name, permission.info.name); 356 assertEquals(protectionLevel, permission.info.protectionLevel); 357 } 358 assertMetadata(Bundle b, String... keysAndValues)359 private void assertMetadata(Bundle b, String... keysAndValues) { 360 assertTrue("Odd number of elements in keysAndValues", (keysAndValues.length % 2) == 0); 361 362 assertNotNull(b); 363 assertEquals(keysAndValues.length / 2, b.size()); 364 365 for (int i = 0; i < keysAndValues.length; i += 2) { 366 final String key = keysAndValues[i]; 367 final String value = keysAndValues[i + 1]; 368 369 assertEquals(value, b.getString(key)); 370 } 371 } 372 373 // TODO Add a "_cached" test for testMultiPackageComponents() too, after fixing b/64295061. 374 // Package.writeToParcel can't handle circular package references. 375 376 @Test testPackageWithComponents_no_cache()377 public void testPackageWithComponents_no_cache() throws Exception { 378 checkPackageWithComponents(p -> p); 379 } 380 381 @Test testPackageWithComponents_cached()382 public void testPackageWithComponents_cached() throws Exception { 383 checkPackageWithComponents(p -> 384 PackageParser.fromCacheEntryStatic(PackageParser.toCacheEntryStatic(p))); 385 } 386 checkPackageWithComponents( Function<Package, Package> converter)387 private void checkPackageWithComponents( 388 Function<Package, Package> converter) throws Exception { 389 Package p = parsePackage( 390 "install_complete_package_info.apk", R.raw.install_complete_package_info, 391 converter); 392 String packageName = "com.android.frameworks.coretests.install_complete_package_info"; 393 394 assertEquals(packageName, p.packageName); 395 assertEquals(1, p.permissions.size()); 396 assertPermission( 397 "com.android.frameworks.coretests.install_complete_package_info.test_permission", 398 packageName, PermissionInfo.PROTECTION_NORMAL, p.permissions.get(0)); 399 400 assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", p); 401 402 assertMetadata(p.mAppMetaData, 403 "key1", "value1", 404 "key2", "this_is_app"); 405 assertMetadata(p.activities.get(0).metaData, 406 "key1", "value1", 407 "key2", "this_is_activity"); 408 assertMetadata(p.services.get(0).metaData, 409 "key1", "value1", 410 "key2", "this_is_service"); 411 assertMetadata(p.receivers.get(0).metaData, 412 "key1", "value1", 413 "key2", "this_is_receiver"); 414 assertMetadata(p.providers.get(0).metaData, 415 "key1", "value1", 416 "key2", "this_is_provider"); 417 } 418 419 /** 420 * Determines if the current device supports multi-package APKs. 421 */ supportsMultiPackageApk()422 private boolean supportsMultiPackageApk() { 423 return SystemProperties.getBoolean("persist.sys.child_packages_enabled", false); 424 } 425 426 @Test testMultiPackageComponents()427 public void testMultiPackageComponents() throws Exception { 428 // TODO(gboyer): Remove once we decide to launch multi-package APKs. 429 if (!supportsMultiPackageApk()) { 430 return; 431 } 432 String parentName = "com.android.frameworks.coretests.install_multi_package"; 433 String firstChildName = 434 "com.android.frameworks.coretests.install_multi_package.first_child"; 435 String secondChildName = // NOTE: intentionally inconsistent! 436 "com.android.frameworks.coretests.blah.second_child"; 437 438 Package parent = parsePackage("install_multi_package.apk", R.raw.install_multi_package); 439 assertEquals(parentName, parent.packageName); 440 assertEquals(2, parent.childPackages.size()); 441 assertOneComponentOfEachType("com.android.frameworks.coretests.Test%s", parent); 442 assertEquals(1, parent.permissions.size()); 443 assertPermission(parentName + ".test_permission", parentName, 444 PermissionInfo.PROTECTION_NORMAL, parent.permissions.get(0)); 445 assertEquals(Arrays.asList("android.permission.INTERNET"), 446 parent.requestedPermissions); 447 448 Package firstChild = parent.childPackages.get(0); 449 assertEquals(firstChildName, firstChild.packageName); 450 assertOneComponentOfEachType( 451 "com.android.frameworks.coretests.FirstChildTest%s", firstChild); 452 assertEquals(0, firstChild.permissions.size()); // Child APKs cannot declare permissions. 453 assertEquals(Arrays.asList("android.permission.NFC"), 454 firstChild.requestedPermissions); 455 456 Package secondChild = parent.childPackages.get(1); 457 assertEquals(secondChildName, secondChild.packageName); 458 assertOneComponentOfEachType( 459 "com.android.frameworks.coretests.SecondChildTest%s", secondChild); 460 assertEquals(0, secondChild.permissions.size()); // Child APKs cannot declare permissions. 461 assertEquals( 462 Arrays.asList( 463 "android.permission.ACCESS_NETWORK_STATE", 464 "android.permission.READ_CONTACTS"), 465 secondChild.requestedPermissions); 466 } 467 } 468