diff options
| author | 2018-01-23 13:39:00 +0000 | |
|---|---|---|
| committer | 2018-01-23 17:09:32 +0000 | |
| commit | beee5dcdfadf4d4b34d3d6ac733be3c420746c84 (patch) | |
| tree | a942b5c97c49d91d977bd44776a53b1c0e422b68 | |
| parent | a8c7794856c5794fa5b31cf5398b8f773650d6c7 (diff) | |
Support conditional removal of oahl from bootclasspath
This makes the runtime handling of the org.apache.http.legacy library
conditional based on a build flag REMOVE_OAHL_FROM_BCP.
When REMOVE_OAHL_FROM_BCP=true:
* The framework-oahl-backward-compatibility is added to the
bootclasspath instead of org.apache.http.legacy.
* Any APK that targets pre-P has org.apache.http.legacy added to their
library list.
Otherwise:
* The org.apache.http.legacy library is added to the bootclasspath.
* Any APK that explicitly specifies that it depends on the
org.apache.http.legacy library has the library removed as the classes
are available at runtime.
Tested both cases by building with or without the build flag, flashing,
setting up, adding an account, adding a trusted place. Adding an account
failed when REMOVE_OAHL_FROM_BCP=true.
adb install -r -g out/target/product/marlin/testcases/FrameworksCoreTests/FrameworksCoreTests.apk
adb shell am instrument -w -e class android.content.pm.PackageBackwardCompatibilityTest com.android.frameworks.coretests/android.support.test.runner.AndroidJUnitRunner
Bug: 18027885
Bug: 72375096
Test: as above
Change-Id: Ie88fb79da76d3cbbd27eaf820c872191ecba2b17
| -rw-r--r-- | Android.bp | 17 | ||||
| -rw-r--r-- | core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java | 66 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageBackwardCompatibility.java | 154 | ||||
| -rw-r--r-- | core/java/android/content/pm/PackageSharedLibraryUpdater.java | 55 | ||||
| -rw-r--r-- | core/tests/coretests/Android.mk | 4 | ||||
| -rw-r--r-- | core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java | 66 |
6 files changed, 300 insertions, 62 deletions
diff --git a/Android.bp b/Android.bp index 9e9faf2d7ffa..c775d15f6bb2 100644 --- a/Android.bp +++ b/Android.bp @@ -630,6 +630,11 @@ java_library { ], }, + // See comment on framework-oahl-backward-compatibility module below + exclude_srcs: [ + "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java", + ], + no_framework_libs: true, libs: [ "conscrypt", @@ -665,6 +670,18 @@ java_library { ], } +// A temporary build target that is conditionally included on the bootclasspath if +// org.apache.http.legacy library has been removed and which provides support for +// maintaining backwards compatibility for APKs that target pre-P and depend on +// org.apache.http.legacy classes. This is used iff REMOVE_OAHL_FROM_BCP=true is +// specified on the build command line. +java_library { + name: "framework-oahl-backward-compatibility", + srcs: [ + "core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java", + ], +} + genrule { name: "framework-statslog-gen", tools: ["stats-log-api-gen"], diff --git a/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java new file mode 100644 index 000000000000..81041e9d3ba6 --- /dev/null +++ b/core/java/android/content/pm/OrgApacheHttpLegacyUpdater.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2018 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 android.content.pm.PackageParser.Package; +import android.os.Build; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.ArrayList; + +/** + * Updates a package to ensure that if it targets < P that the org.apache.http.legacy library is + * included by default. + * + * <p>This is separated out so that it can be conditionally included at build time depending on + * whether org.apache.http.legacy is on the bootclasspath or not. In order to include this at + * build time, and remove org.apache.http.legacy from the bootclasspath pass + * REMOVE_OAHL_FROM_BCP=true on the build command line, otherwise this class will not be included + * and the + * + * @hide + */ +@VisibleForTesting +public class OrgApacheHttpLegacyUpdater extends PackageSharedLibraryUpdater { + + private static final String APACHE_HTTP_LEGACY = "org.apache.http.legacy"; + + @Override + public void updatePackage(Package pkg) { + ArrayList<String> usesLibraries = pkg.usesLibraries; + ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; + + // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library + // to be accessible so this maintains backward compatibility by adding the + // org.apache.http.legacy library to those packages. + if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) { + boolean apacheHttpLegacyPresent = isLibraryPresent( + usesLibraries, usesOptionalLibraries, APACHE_HTTP_LEGACY); + if (!apacheHttpLegacyPresent) { + usesLibraries = prefix(usesLibraries, APACHE_HTTP_LEGACY); + } + } + + pkg.usesLibraries = usesLibraries; + pkg.usesOptionalLibraries = usesOptionalLibraries; + } + + private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) { + int targetSdkVersion = pkg.applicationInfo.targetSdkVersion; + return targetSdkVersion <= Build.VERSION_CODES.O_MR1; + } +} diff --git a/core/java/android/content/pm/PackageBackwardCompatibility.java b/core/java/android/content/pm/PackageBackwardCompatibility.java index 8014c94d198d..9bdb78be5442 100644 --- a/core/java/android/content/pm/PackageBackwardCompatibility.java +++ b/core/java/android/content/pm/PackageBackwardCompatibility.java @@ -16,15 +16,14 @@ package android.content.pm; -import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.pm.PackageParser.Package; -import android.os.Build; +import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.util.ArrayList; +import java.util.List; /** * Modifies {@link Package} in order to maintain backwards compatibility. @@ -32,13 +31,60 @@ import java.util.ArrayList; * @hide */ @VisibleForTesting -public class PackageBackwardCompatibility { +public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { + + private static final String TAG = PackageBackwardCompatibility.class.getSimpleName(); private static final String ANDROID_TEST_MOCK = "android.test.mock"; private static final String ANDROID_TEST_RUNNER = "android.test.runner"; - private static final String APACHE_HTTP_LEGACY = "org.apache.http.legacy"; + private static final PackageBackwardCompatibility INSTANCE; + + static { + String className = "android.content.pm.OrgApacheHttpLegacyUpdater"; + Class<? extends PackageSharedLibraryUpdater> clazz; + try { + clazz = (PackageBackwardCompatibility.class.getClassLoader() + .loadClass(className) + .asSubclass(PackageSharedLibraryUpdater.class)); + } catch (ClassNotFoundException e) { + Log.i(TAG, "Could not find " + className + ", ignoring"); + clazz = null; + } + + boolean hasOrgApacheHttpLegacy = false; + final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>(); + if (clazz == null) { + // Add an updater that will remove any references to org.apache.http.library from the + // package so that it does not try and load the library when it is on the + // bootclasspath. + packageUpdaters.add(new RemoveUnnecessaryOrgApacheHttpLegacyLibrary()); + } else { + try { + packageUpdaters.add(clazz.getConstructor().newInstance()); + hasOrgApacheHttpLegacy = true; + } catch (ReflectiveOperationException e) { + throw new IllegalStateException("Could not create instance of " + className, e); + } + } + + packageUpdaters.add(new AndroidTestRunnerSplitUpdater()); + + PackageSharedLibraryUpdater[] updaterArray = packageUpdaters + .toArray(new PackageSharedLibraryUpdater[0]); + INSTANCE = new PackageBackwardCompatibility(hasOrgApacheHttpLegacy, updaterArray); + } + + private final boolean mRemovedOAHLFromBCP; + + private final PackageSharedLibraryUpdater[] mPackageUpdaters; + + public PackageBackwardCompatibility(boolean removedOAHLFromBCP, + PackageSharedLibraryUpdater[] packageUpdaters) { + this.mRemovedOAHLFromBCP = removedOAHLFromBCP; + this.mPackageUpdaters = packageUpdaters; + } /** * Modify the shared libraries in the supplied {@link Package} to maintain backwards @@ -48,52 +94,74 @@ public class PackageBackwardCompatibility { */ @VisibleForTesting public static void modifySharedLibraries(Package pkg) { - ArrayList<String> usesLibraries = pkg.usesLibraries; - ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; - - // Packages targeted at <= O_MR1 expect the classes in the org.apache.http.legacy library - // to be accessible so this maintains backward compatibility by adding the - // org.apache.http.legacy library to those packages. - if (apkTargetsApiLevelLessThanOrEqualToOMR1(pkg)) { - boolean apacheHttpLegacyPresent = isLibraryPresent( - usesLibraries, usesOptionalLibraries, APACHE_HTTP_LEGACY); - if (!apacheHttpLegacyPresent) { - usesLibraries = prefix(usesLibraries, APACHE_HTTP_LEGACY); - } - } + INSTANCE.updatePackage(pkg); + } - // android.test.runner has a dependency on android.test.mock so if android.test.runner - // is present but android.test.mock is not then add android.test.mock. - boolean androidTestMockPresent = isLibraryPresent( - usesLibraries, usesOptionalLibraries, ANDROID_TEST_MOCK); - if (ArrayUtils.contains(usesLibraries, ANDROID_TEST_RUNNER) && !androidTestMockPresent) { - usesLibraries.add(ANDROID_TEST_MOCK); - } - if (ArrayUtils.contains(usesOptionalLibraries, ANDROID_TEST_RUNNER) - && !androidTestMockPresent) { - usesOptionalLibraries.add(ANDROID_TEST_MOCK); - } + @Override + public void updatePackage(Package pkg) { - pkg.usesLibraries = usesLibraries; - pkg.usesOptionalLibraries = usesOptionalLibraries; + for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) { + packageUpdater.updatePackage(pkg); + } } - private static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(Package pkg) { - int targetSdkVersion = pkg.applicationInfo.targetSdkVersion; - return targetSdkVersion <= Build.VERSION_CODES.O_MR1; + /** + * True if the org.apache.http.legacy has been removed the bootclasspath, false otherwise. + */ + public static boolean removeOAHLFromBCP() { + return INSTANCE.mRemovedOAHLFromBCP; } - private static boolean isLibraryPresent(ArrayList<String> usesLibraries, - ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) { - return ArrayUtils.contains(usesLibraries, apacheHttpLegacy) - || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy); + /** + * Add android.test.mock dependency for any APK that depends on android.test.runner. + * + * <p>This is needed to maintain backwards compatibility as in previous versions of Android the + * android.test.runner library included the classes from android.test.mock which have since + * been split out into a separate library. + * + * @hide + */ + @VisibleForTesting + public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater { + + @Override + public void updatePackage(Package pkg) { + ArrayList<String> usesLibraries = pkg.usesLibraries; + ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries; + + // android.test.runner has a dependency on android.test.mock so if android.test.runner + // is present but android.test.mock is not then add android.test.mock. + boolean androidTestMockPresent = isLibraryPresent( + usesLibraries, usesOptionalLibraries, ANDROID_TEST_MOCK); + if (ArrayUtils.contains(usesLibraries, ANDROID_TEST_RUNNER) + && !androidTestMockPresent) { + usesLibraries.add(ANDROID_TEST_MOCK); + } + if (ArrayUtils.contains(usesOptionalLibraries, ANDROID_TEST_RUNNER) + && !androidTestMockPresent) { + usesOptionalLibraries.add(ANDROID_TEST_MOCK); + } + + pkg.usesLibraries = usesLibraries; + pkg.usesOptionalLibraries = usesOptionalLibraries; + } } - private static @NonNull <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) { - if (cur == null) { - cur = new ArrayList<>(); + /** + * Remove any usages of org.apache.http.legacy from the shared library as the library is on the + * bootclasspath. + */ + @VisibleForTesting + public static class RemoveUnnecessaryOrgApacheHttpLegacyLibrary + extends PackageSharedLibraryUpdater { + + private static final String APACHE_HTTP_LEGACY = "org.apache.http.legacy"; + + @Override + public void updatePackage(Package pkg) { + pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, APACHE_HTTP_LEGACY); + pkg.usesOptionalLibraries = + ArrayUtils.remove(pkg.usesOptionalLibraries, APACHE_HTTP_LEGACY); } - cur.add(0, val); - return cur; } } diff --git a/core/java/android/content/pm/PackageSharedLibraryUpdater.java b/core/java/android/content/pm/PackageSharedLibraryUpdater.java new file mode 100644 index 000000000000..49d884ca2f34 --- /dev/null +++ b/core/java/android/content/pm/PackageSharedLibraryUpdater.java @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2018 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 android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.ArrayUtils; + +import java.util.ArrayList; + +/** + * Base for classes that update a {@link PackageParser.Package}'s shared libraries. + * + * @hide + */ +@VisibleForTesting +public abstract class PackageSharedLibraryUpdater { + + /** + * Update the package's shared libraries. + * + * @param pkg the package to update. + */ + public abstract void updatePackage(PackageParser.Package pkg); + + static @NonNull + <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) { + if (cur == null) { + cur = new ArrayList<>(); + } + cur.add(0, val); + return cur; + } + + static boolean isLibraryPresent(ArrayList<String> usesLibraries, + ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) { + return ArrayUtils.contains(usesLibraries, apacheHttpLegacy) + || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy); + } +} diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index 47990a168ab3..60b46b453100 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -53,6 +53,10 @@ LOCAL_JAVA_LIBRARIES := \ android.test.base \ android.test.mock \ +ifeq ($(REMOVE_OAHL_FROM_BCP),true) +LOCAL_JAVA_LIBRARIES += framework-oahl-backward-compatibility +endif + LOCAL_PACKAGE_NAME := FrameworksCoreTests LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java index 63a5e4cc1dd8..6996e5056466 100644 --- a/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java +++ b/core/tests/coretests/src/android/content/pm/PackageBackwardCompatibilityTest.java @@ -73,9 +73,13 @@ public class PackageBackwardCompatibilityTest { public void targeted_at_O() { mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; PackageBackwardCompatibility.modifySharedLibraries(mPackage); - assertEquals("usesLibraries not updated correctly", - arrayList(ORG_APACHE_HTTP_LEGACY), - mPackage.usesLibraries); + if (PackageBackwardCompatibility.removeOAHLFromBCP()) { + assertEquals("usesLibraries not updated correctly", + arrayList(ORG_APACHE_HTTP_LEGACY), + mPackage.usesLibraries); + } else { + assertNull("usesOptionalLibraries not updated correctly", mPackage.usesLibraries); + } assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries); } @@ -84,10 +88,16 @@ public class PackageBackwardCompatibilityTest { mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; mPackage.usesLibraries = arrayList(OTHER_LIBRARY); PackageBackwardCompatibility.modifySharedLibraries(mPackage); - // The org.apache.http.legacy jar should be added at the start of the list. - assertEquals("usesLibraries not updated correctly", - arrayList(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY), - mPackage.usesLibraries); + if (PackageBackwardCompatibility.removeOAHLFromBCP()) { + // The org.apache.http.legacy jar should be added at the start of the list. + assertEquals("usesLibraries not updated correctly", + arrayList(ORG_APACHE_HTTP_LEGACY, OTHER_LIBRARY), + mPackage.usesLibraries); + } else { + assertEquals("usesLibraries not updated correctly", + arrayList(OTHER_LIBRARY), + mPackage.usesLibraries); + } assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries); } @@ -96,9 +106,13 @@ public class PackageBackwardCompatibilityTest { mPackage.applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; mPackage.usesLibraries = arrayList(ORG_APACHE_HTTP_LEGACY); PackageBackwardCompatibility.modifySharedLibraries(mPackage); - assertEquals("usesLibraries not updated correctly", - arrayList(ORG_APACHE_HTTP_LEGACY), - mPackage.usesLibraries); + if (PackageBackwardCompatibility.removeOAHLFromBCP()) { + assertEquals("usesLibraries not updated correctly", + arrayList(ORG_APACHE_HTTP_LEGACY), + mPackage.usesLibraries); + } else { + assertNull("usesLibraries not updated correctly", mPackage.usesLibraries); + } assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries); } @@ -108,18 +122,27 @@ public class PackageBackwardCompatibilityTest { mPackage.usesOptionalLibraries = arrayList(ORG_APACHE_HTTP_LEGACY); PackageBackwardCompatibility.modifySharedLibraries(mPackage); assertNull("usesLibraries not updated correctly", mPackage.usesLibraries); - assertEquals("usesOptionalLibraries not updated correctly", - arrayList(ORG_APACHE_HTTP_LEGACY), - mPackage.usesOptionalLibraries); + if (PackageBackwardCompatibility.removeOAHLFromBCP()) { + assertEquals("usesOptionalLibraries not updated correctly", + arrayList(ORG_APACHE_HTTP_LEGACY), + mPackage.usesOptionalLibraries); + } else { + assertNull("usesOptionalLibraries not updated correctly", + mPackage.usesOptionalLibraries); + } } @Test public void org_apache_http_legacy_in_usesLibraries() { mPackage.usesLibraries = arrayList(ORG_APACHE_HTTP_LEGACY); PackageBackwardCompatibility.modifySharedLibraries(mPackage); - assertEquals("usesLibraries not updated correctly", - arrayList(ORG_APACHE_HTTP_LEGACY), - mPackage.usesLibraries); + if (PackageBackwardCompatibility.removeOAHLFromBCP()) { + assertEquals("usesLibraries not updated correctly", + arrayList(ORG_APACHE_HTTP_LEGACY), + mPackage.usesLibraries); + } else { + assertNull("usesLibraries not updated correctly", mPackage.usesLibraries); + } assertNull("usesOptionalLibraries not updated correctly", mPackage.usesOptionalLibraries); } @@ -128,9 +151,14 @@ public class PackageBackwardCompatibilityTest { mPackage.usesOptionalLibraries = arrayList(ORG_APACHE_HTTP_LEGACY); PackageBackwardCompatibility.modifySharedLibraries(mPackage); assertNull("usesLibraries not updated correctly", mPackage.usesLibraries); - assertEquals("usesOptionalLibraries not updated correctly", - arrayList(ORG_APACHE_HTTP_LEGACY), - mPackage.usesOptionalLibraries); + if (PackageBackwardCompatibility.removeOAHLFromBCP()) { + assertEquals("usesOptionalLibraries not updated correctly", + arrayList(ORG_APACHE_HTTP_LEGACY), + mPackage.usesOptionalLibraries); + } else { + assertNull("usesOptionalLibraries not updated correctly", + mPackage.usesOptionalLibraries); + } } @Test |