summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2016-12-19 22:23:09 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2016-12-19 22:23:12 +0000
commitccec35c456f12a9438a524793159f5b2bda69443 (patch)
treed9c6498d314e92476d84c30406961787b4a69621
parent4037fa05283f4474e2922e841d644dac852b0d8e (diff)
parent82f4b263a09630b9937ecb2cc3dea5b21eaa7b8f (diff)
Merge "Add tests, refactor min/targetSdkVersion checks in PackageParser"
-rw-r--r--core/java/android/content/pm/PackageParser.java199
-rw-r--r--core/tests/coretests/README50
-rw-r--r--core/tests/coretests/src/android/content/pm/PackageParserTest.java218
3 files changed, 413 insertions, 54 deletions
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 32bf66a92fd5..2236291fd248 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -24,7 +24,10 @@ import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Intent;
@@ -58,7 +61,6 @@ import android.util.jar.StrictJarFile;
import android.view.Gravity;
import java.io.File;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -85,7 +87,6 @@ import java.util.zip.ZipEntry;
import libcore.io.IoUtils;
import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
-import static android.content.pm.ActivityInfo.FLAG_IMMERSIVE;
import static android.content.pm.ActivityInfo.FLAG_ON_TOP_LAUNCHER;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZABLE_LANDSCAPE_ONLY;
@@ -2103,63 +2104,22 @@ public class PackageParser {
sa.recycle();
- if (minCode != null) {
- boolean allowedCodename = false;
- for (String codename : SDK_CODENAMES) {
- if (minCode.equals(codename)) {
- allowedCodename = true;
- break;
- }
- }
- if (!allowedCodename) {
- if (SDK_CODENAMES.length > 0) {
- outError[0] = "Requires development platform " + minCode
- + " (current platform is any of "
- + Arrays.toString(SDK_CODENAMES) + ")";
- } else {
- outError[0] = "Requires development platform " + minCode
- + " but this is a release platform.";
- }
- mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
- return null;
- }
- pkg.applicationInfo.minSdkVersion =
- android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
- } else if (minVers > SDK_VERSION) {
- outError[0] = "Requires newer sdk version #" + minVers
- + " (current version is #" + SDK_VERSION + ")";
+ final int minSdkVersion = PackageParser.computeMinSdkVersion(minVers, minCode,
+ SDK_VERSION, SDK_CODENAMES, outError);
+ if (minSdkVersion < 0) {
mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
return null;
- } else {
- pkg.applicationInfo.minSdkVersion = minVers;
}
- if (targetCode != null) {
- boolean allowedCodename = false;
- for (String codename : SDK_CODENAMES) {
- if (targetCode.equals(codename)) {
- allowedCodename = true;
- break;
- }
- }
- if (!allowedCodename) {
- if (SDK_CODENAMES.length > 0) {
- outError[0] = "Requires development platform " + targetCode
- + " (current platform is any of "
- + Arrays.toString(SDK_CODENAMES) + ")";
- } else {
- outError[0] = "Requires development platform " + targetCode
- + " but this is a release platform.";
- }
- mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
- return null;
- }
- // If the code matches, it definitely targets this SDK.
- pkg.applicationInfo.targetSdkVersion
- = android.os.Build.VERSION_CODES.CUR_DEVELOPMENT;
- } else {
- pkg.applicationInfo.targetSdkVersion = targetVers;
+ final int targetSdkVersion = PackageParser.computeTargetSdkVersion(targetVers,
+ targetCode, SDK_VERSION, SDK_CODENAMES, outError);
+ if (targetSdkVersion < 0) {
+ mParseError = PackageManager.INSTALL_FAILED_OLDER_SDK;
+ return null;
}
+
+ pkg.applicationInfo.minSdkVersion = minSdkVersion;
+ pkg.applicationInfo.targetSdkVersion = targetSdkVersion;
}
XmlUtils.skipCurrentTag(parser);
@@ -2407,6 +2367,137 @@ public class PackageParser {
return pkg;
}
+ /**
+ * Computes the targetSdkVersion to use at runtime. If the package is not
+ * compatible with this platform, populates {@code outError[0]} with an
+ * error message.
+ * <p>
+ * If {@code targetCode} is not specified, e.g. the value is {@code null},
+ * then the {@code targetVers} will be returned unmodified.
+ * <p>
+ * Otherwise, the behavior varies based on whether the current platform
+ * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+ * has length > 0:
+ * <ul>
+ * <li>If this is a pre-release platform and the value specified by
+ * {@code targetCode} is contained within the array of allowed pre-release
+ * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+ * <li>If this is a released platform, this method will return -1 to
+ * indicate that the package is not compatible with this platform.
+ * </ul>
+ *
+ * @param targetVers targetSdkVersion number, if specified in the
+ * application manifest, or 0 otherwise
+ * @param targetCode targetSdkVersion code, if specified in the application
+ * manifest, or {@code null} otherwise
+ * @param platformSdkVersion platform SDK version number, typically
+ * Build.VERSION.SDK_INT
+ * @param platformSdkCodenames array of allowed pre-release SDK codenames
+ * for this platform
+ * @param outError output array to populate with error, if applicable
+ * @return the targetSdkVersion to use at runtime, or -1 if the package is
+ * not compatible with this platform
+ * @hide Exposed for unit testing only.
+ */
+ @TestApi
+ public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
+ @Nullable String targetCode, @IntRange(from = 1) int platformSdkVersion,
+ @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
+ // If it's a release SDK, return the version number unmodified.
+ if (targetCode == null) {
+ return targetVers;
+ }
+
+ // If it's a pre-release SDK and the codename matches this platform, it
+ // definitely targets this SDK.
+ if (ArrayUtils.contains(platformSdkCodenames, targetCode)) {
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
+ // Otherwise, we're looking at an incompatible pre-release SDK.
+ if (platformSdkCodenames.length > 0) {
+ outError[0] = "Requires development platform " + targetCode
+ + " (current platform is any of "
+ + Arrays.toString(platformSdkCodenames) + ")";
+ } else {
+ outError[0] = "Requires development platform " + targetCode
+ + " but this is a release platform.";
+ }
+ return -1;
+ }
+
+ /**
+ * Computes the minSdkVersion to use at runtime. If the package is not
+ * compatible with this platform, populates {@code outError[0]} with an
+ * error message.
+ * <p>
+ * If {@code minCode} is not specified, e.g. the value is {@code null},
+ * then behavior varies based on the {@code platformSdkVersion}:
+ * <ul>
+ * <li>If the platform SDK version is greater than or equal to the
+ * {@code minVers}, returns the {@code mniVers} unmodified.
+ * <li>Otherwise, returns -1 to indicate that the package is not
+ * compatible with this platform.
+ * </ul>
+ * <p>
+ * Otherwise, the behavior varies based on whether the current platform
+ * is a pre-release version, e.g. the {@code platformSdkCodenames} array
+ * has length > 0:
+ * <ul>
+ * <li>If this is a pre-release platform and the value specified by
+ * {@code targetCode} is contained within the array of allowed pre-release
+ * codenames, this method will return {@link Build.VERSION_CODES#CUR_DEVELOPMENT}.
+ * <li>If this is a released platform, this method will return -1 to
+ * indicate that the package is not compatible with this platform.
+ * </ul>
+ *
+ * @param minVers minSdkVersion number, if specified in the application
+ * manifest, or 1 otherwise
+ * @param minCode minSdkVersion code, if specified in the application
+ * manifest, or {@code null} otherwise
+ * @param platformSdkVersion platform SDK version number, typically
+ * Build.VERSION.SDK_INT
+ * @param platformSdkCodenames array of allowed prerelease SDK codenames
+ * for this platform
+ * @param outError output array to populate with error, if applicable
+ * @return the minSdkVersion to use at runtime, or -1 if the package is not
+ * compatible with this platform
+ * @hide Exposed for unit testing only.
+ */
+ @TestApi
+ public static int computeMinSdkVersion(@IntRange(from = 1) int minVers,
+ @Nullable String minCode, @IntRange(from = 1) int platformSdkVersion,
+ @NonNull String[] platformSdkCodenames, @NonNull String[] outError) {
+ // If it's a release SDK, make sure we meet the minimum SDK requirement.
+ if (minCode == null) {
+ if (minVers <= platformSdkVersion) {
+ return minVers;
+ }
+
+ // We don't meet the minimum SDK requirement.
+ outError[0] = "Requires newer sdk version #" + minVers
+ + " (current version is #" + platformSdkVersion + ")";
+ return -1;
+ }
+
+ // If it's a pre-release SDK and the codename matches this platform, we
+ // definitely meet the minimum SDK requirement.
+ if (ArrayUtils.contains(platformSdkCodenames, minCode)) {
+ return Build.VERSION_CODES.CUR_DEVELOPMENT;
+ }
+
+ // Otherwise, we're looking at an incompatible pre-release SDK.
+ if (platformSdkCodenames.length > 0) {
+ outError[0] = "Requires development platform " + minCode
+ + " (current platform is any of "
+ + Arrays.toString(platformSdkCodenames) + ")";
+ } else {
+ outError[0] = "Requires development platform " + minCode
+ + " but this is a release platform.";
+ }
+ return -1;
+ }
+
private FeatureInfo parseUsesFeature(Resources res, AttributeSet attrs) {
FeatureInfo fi = new FeatureInfo();
TypedArray sa = res.obtainAttributes(attrs,
diff --git a/core/tests/coretests/README b/core/tests/coretests/README
new file mode 100644
index 000000000000..4a6984320e61
--- /dev/null
+++ b/core/tests/coretests/README
@@ -0,0 +1,50 @@
+* Copyright (C) 2016 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+
+
+INTRODUCTION
+
+The Android platform core tests (APCT) consist of unit tests for core platform
+functionality. These differ from CTS in that they are not necessarily testing
+public APIs and are not guaranteed to work outside of AOSP builds.
+
+
+INSTRUCTIONS
+
+To run a test or set of tests, first build the FrameworksCoreTests package:
+
+ make FrameworksCoreTests
+
+Next, install the resulting APK and run tests as you would normal JUnit tests:
+
+ adb install out/target/product/.../data/app/FrameworksCoreTests/FrameworksCoreTests.apk
+ adb shell am instrument -w \
+ com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
+
+To run a tests within a specific package, add the following argument AFTER -w:
+
+ -e package android.content.pm
+
+To run a specific test or method within a test:
+
+ -e class android.content.pm.PackageParserTest
+ -e class android.content.pm.PackageParserTest#testComputeMinSdkVersion
+
+To run tests in debug mode:
+
+ -e debug true
+
+For more arguments, see the guide to command=line testing:
+
+ https://developer.android.com/studio/test/command-line.html
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
new file mode 100644
index 000000000000..2a3c22c64ec2
--- /dev/null
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+import android.os.Build;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PackageParserTest {
+ private static final String RELEASED = null;
+ private static final String OLDER_PRE_RELEASE = "A";
+ private static final String PRE_RELEASE = "B";
+ private static final String NEWER_PRE_RELEASE = "C";
+
+ private static final String[] CODENAMES_RELEASED = { /* empty */ };
+ private static final String[] CODENAMES_PRE_RELEASE = { PRE_RELEASE };
+
+ private static final int OLDER_VERSION = 10;
+ private static final int PLATFORM_VERSION = 20;
+ private static final int NEWER_VERSION = 30;
+
+ private void verifyComputeMinSdkVersion(int minSdkVersion, String minSdkCodename,
+ boolean isPlatformReleased, int expectedMinSdk) {
+ final String[] outError = new String[1];
+ final int result = PackageParser.computeMinSdkVersion(
+ minSdkVersion,
+ minSdkCodename,
+ PLATFORM_VERSION,
+ isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
+ outError);
+
+ assertEquals(result, expectedMinSdk);
+
+ if (expectedMinSdk == -1) {
+ assertNotNull(outError[0]);
+ } else {
+ assertNull(outError[0]);
+ }
+ }
+
+ @Test
+ public void testComputeMinSdkVersion_preReleasePlatform() {
+ // Do allow older release minSdkVersion on pre-release platform.
+ // APP: Released API 10
+ // DEV: Pre-release API 20
+ verifyComputeMinSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION);
+
+ // Do allow same release minSdkVersion on pre-release platform.
+ // APP: Released API 20
+ // DEV: Pre-release API 20
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION);
+
+ // Don't allow newer release minSdkVersion on pre-release platform.
+ // APP: Released API 30
+ // DEV: Pre-release API 20
+ verifyComputeMinSdkVersion(NEWER_VERSION, RELEASED, false, -1);
+
+ // Don't allow older pre-release minSdkVersion on pre-release platform.
+ // APP: Pre-release API 10
+ // DEV: Pre-release API 20
+ verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+
+ // Do allow same pre-release minSdkVersion on pre-release platform,
+ // but overwrite the specified version with CUR_DEVELOPMENT.
+ // APP: Pre-release API 20
+ // DEV: Pre-release API 20
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
+ Build.VERSION_CODES.CUR_DEVELOPMENT);
+
+ // Don't allow newer pre-release minSdkVersion on pre-release platform.
+ // APP: Pre-release API 30
+ // DEV: Pre-release API 20
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+ }
+
+ @Test
+ public void testComputeMinSdkVersion_releasedPlatform() {
+ // Do allow older release minSdkVersion on released platform.
+ // APP: Released API 10
+ // DEV: Released API 20
+ verifyComputeMinSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION);
+
+ // Do allow same release minSdkVersion on released platform.
+ // APP: Released API 20
+ // DEV: Released API 20
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION);
+
+ // Don't allow newer release minSdkVersion on released platform.
+ // APP: Released API 30
+ // DEV: Released API 20
+ verifyComputeMinSdkVersion(NEWER_VERSION, RELEASED, true, -1);
+
+ // Don't allow older pre-release minSdkVersion on released platform.
+ // APP: Pre-release API 10
+ // DEV: Released API 20
+ verifyComputeMinSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+
+ // Don't allow same pre-release minSdkVersion on released platform.
+ // APP: Pre-release API 20
+ // DEV: Released API 20
+ verifyComputeMinSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+
+ // Don't allow newer pre-release minSdkVersion on released platform.
+ // APP: Pre-release API 30
+ // DEV: Released API 20
+ verifyComputeMinSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+ }
+
+ private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
+ boolean isPlatformReleased, int expectedTargetSdk) {
+ final String[] outError = new String[1];
+ final int result = PackageParser.computeTargetSdkVersion(
+ targetSdkVersion,
+ targetSdkCodename,
+ PLATFORM_VERSION,
+ isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
+ outError);
+
+ assertEquals(result, expectedTargetSdk);
+
+ if (expectedTargetSdk == -1) {
+ assertNotNull(outError[0]);
+ } else {
+ assertNull(outError[0]);
+ }
+ }
+
+ @Test
+ public void testComputeTargetSdkVersion_preReleasePlatform() {
+ // Do allow older release targetSdkVersion on pre-release platform.
+ // APP: Released API 10
+ // DEV: Pre-release API 20
+ verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION);
+
+ // Do allow same release targetSdkVersion on pre-release platform.
+ // APP: Released API 20
+ // DEV: Pre-release API 20
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION);
+
+ // Do allow newer release targetSdkVersion on pre-release platform.
+ // APP: Released API 30
+ // DEV: Pre-release API 20
+ verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION);
+
+ // Don't allow older pre-release targetSdkVersion on pre-release platform.
+ // APP: Pre-release API 10
+ // DEV: Pre-release API 20
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+
+ // Do allow same pre-release targetSdkVersion on pre-release platform,
+ // but overwrite the specified version with CUR_DEVELOPMENT.
+ // APP: Pre-release API 20
+ // DEV: Pre-release API 20
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
+ Build.VERSION_CODES.CUR_DEVELOPMENT);
+
+ // Don't allow newer pre-release targetSdkVersion on pre-release platform.
+ // APP: Pre-release API 30
+ // DEV: Pre-release API 20
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+ }
+
+ @Test
+ public void testComputeTargetSdkVersion_releasedPlatform() {
+ // Do allow older release targetSdkVersion on released platform.
+ // APP: Released API 10
+ // DEV: Released API 20
+ verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION);
+
+ // Do allow same release targetSdkVersion on released platform.
+ // APP: Released API 20
+ // DEV: Released API 20
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION);
+
+ // Do allow newer release targetSdkVersion on released platform.
+ // APP: Released API 30
+ // DEV: Released API 20
+ verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION);
+
+ // Don't allow older pre-release targetSdkVersion on released platform.
+ // APP: Pre-release API 10
+ // DEV: Released API 20
+ verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+
+ // Don't allow same pre-release targetSdkVersion on released platform.
+ // APP: Pre-release API 20
+ // DEV: Released API 20
+ verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+
+ // Don't allow newer pre-release targetSdkVersion on released platform.
+ // APP: Pre-release API 30
+ // DEV: Released API 20
+ verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+ }
+}