diff options
| -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 |