Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c6b7d7c4 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Refactor the PackageBackwardCompatibilityTest"

parents 650fa857 0692a566
Loading
Loading
Loading
Loading
+3 −21
Original line number Diff line number Diff line
@@ -15,13 +15,12 @@
 */
package android.content.pm;

import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;

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.
@@ -37,30 +36,13 @@ import java.util.ArrayList;
@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);
            prefixRequiredLibrary(pkg, ORG_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;
    }
}
+56 −47
Original line number Diff line number Diff line
@@ -16,14 +16,18 @@

package android.content.pm;

import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK;
import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER;
import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;

import android.content.pm.PackageParser.Package;
import android.util.Log;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;

/**
 * Modifies {@link Package} in order to maintain backwards compatibility.
@@ -35,54 +39,77 @@ 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 PackageBackwardCompatibility INSTANCE;

    static {
        String className = "android.content.pm.OrgApacheHttpLegacyUpdater";
        final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();

        // Attempt to load and add the optional updater that will only be available when
        // REMOVE_OAHL_FROM_BCP=true. If that could not be found then add the default 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.
        boolean bootClassPathContainsOAHL = !addOptionalUpdater(packageUpdaters,
                "android.content.pm.OrgApacheHttpLegacyUpdater",
                RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new);

        packageUpdaters.add(new AndroidTestRunnerSplitUpdater());

        PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
                .toArray(new PackageSharedLibraryUpdater[0]);
        INSTANCE = new PackageBackwardCompatibility(
                bootClassPathContainsOAHL, updaterArray);
    }

    /**
     * Add an optional {@link PackageSharedLibraryUpdater} instance to the list, if it could not be
     * found then add a default instance instead.
     *
     * @param packageUpdaters the list to update.
     * @param className the name of the optional class.
     * @param defaultUpdater the supplier of the default instance.
     * @return true if the optional updater was added false otherwise.
     */
    private static boolean addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters,
            String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater) {
        Class<? extends PackageSharedLibraryUpdater> clazz;
        try {
            clazz = (PackageBackwardCompatibility.class.getClassLoader()
                    .loadClass(className)
                    .asSubclass(PackageSharedLibraryUpdater.class));
            Log.i(TAG, "Loaded " + className);
        } catch (ClassNotFoundException e) {
            Log.i(TAG, "Could not find " + className + ", ignoring");
            clazz = null;
        }

        boolean hasOrgApacheHttpLegacy = false;
        final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
        boolean usedOptional = false;
        PackageSharedLibraryUpdater updater;
        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());
            updater = defaultUpdater.get();
        } else {
            try {
                packageUpdaters.add(clazz.getConstructor().newInstance());
                hasOrgApacheHttpLegacy = true;
                updater = clazz.getConstructor().newInstance();
                usedOptional = true;
            } catch (ReflectiveOperationException e) {
                throw new IllegalStateException("Could not create instance of " + className, e);
            }
        }
        packageUpdaters.add(updater);
        return usedOptional;
    }

        packageUpdaters.add(new AndroidTestRunnerSplitUpdater());

        PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
                .toArray(new PackageSharedLibraryUpdater[0]);
        INSTANCE = new PackageBackwardCompatibility(hasOrgApacheHttpLegacy, updaterArray);
    @VisibleForTesting
    public static PackageSharedLibraryUpdater getInstance() {
        return INSTANCE;
    }

    private final boolean mRemovedOAHLFromBCP;
    private final boolean mBootClassPathContainsOAHL;

    private final PackageSharedLibraryUpdater[] mPackageUpdaters;

    public PackageBackwardCompatibility(boolean removedOAHLFromBCP,
    public PackageBackwardCompatibility(boolean bootClassPathContainsOAHL,
            PackageSharedLibraryUpdater[] packageUpdaters) {
        this.mRemovedOAHLFromBCP = removedOAHLFromBCP;
        this.mBootClassPathContainsOAHL = bootClassPathContainsOAHL;
        this.mPackageUpdaters = packageUpdaters;
    }

@@ -99,17 +126,17 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {

    @Override
    public void updatePackage(Package pkg) {

        for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
            packageUpdater.updatePackage(pkg);
        }
    }

    /**
     * True if the org.apache.http.legacy has been removed the bootclasspath, false otherwise.
     * True if the org.apache.http.legacy is on the bootclasspath, false otherwise.
     */
    public static boolean removeOAHLFromBCP() {
        return INSTANCE.mRemovedOAHLFromBCP;
    @VisibleForTesting
    public static boolean bootClassPathContainsOAHL() {
        return INSTANCE.mBootClassPathContainsOAHL;
    }

    /**
@@ -126,24 +153,9 @@ public class PackageBackwardCompatibility 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;
            prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
        }
    }

@@ -155,13 +167,10 @@ public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
    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);
            removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
        }

    }
}
+53 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@ package android.content.pm;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.os.Build;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
@@ -38,6 +39,12 @@ public abstract class PackageSharedLibraryUpdater {
     */
    public abstract void updatePackage(PackageParser.Package pkg);

    static void removeLibrary(PackageParser.Package pkg, String libraryName) {
        pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName);
        pkg.usesOptionalLibraries =
                ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName);
    }

    static @NonNull
            <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
        if (cur == null) {
@@ -47,9 +54,54 @@ public abstract class PackageSharedLibraryUpdater {
        return cur;
    }

    static boolean isLibraryPresent(ArrayList<String> usesLibraries,
    private static boolean isLibraryPresent(ArrayList<String> usesLibraries,
            ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
        return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
                || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
    }

    static boolean apkTargetsApiLevelLessThanOrEqualToOMR1(PackageParser.Package pkg) {
        int targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
        return targetSdkVersion <= Build.VERSION_CODES.O_MR1;
    }

    /**
     * Add an implicit dependency.
     *
     * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
     * the {@code implicitDependency} if it is not already in the list of libraries.
     *
     * @param pkg the {@link PackageParser.Package} to update.
     * @param existingLibrary the existing library.
     * @param implicitDependency the implicit dependency to add
     */
    void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary,
            String implicitDependency) {
        ArrayList<String> usesLibraries = pkg.usesLibraries;
        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;

        if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
            if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
                prefix(usesLibraries, implicitDependency);
            } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
                prefix(usesOptionalLibraries, implicitDependency);
            }

            pkg.usesLibraries = usesLibraries;
            pkg.usesOptionalLibraries = usesOptionalLibraries;
        }
    }

    void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) {
        ArrayList<String> usesLibraries = pkg.usesLibraries;
        ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;

        boolean alreadyPresent = isLibraryPresent(
                usesLibraries, usesOptionalLibraries, libraryName);
        if (!alreadyPresent) {
            usesLibraries = prefix(usesLibraries, libraryName);

            pkg.usesLibraries = usesLibraries;
        }
    }
}
+30 −0
Original line number Diff line number Diff line
/*
 * 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;

/**
 * A set of shared library names
 *
 * @hide
 */
public class SharedLibraryNames {

    static final String ANDROID_TEST_MOCK = "android.test.mock";

    static final String ANDROID_TEST_RUNNER = "android.test.runner";

    static final String ORG_APACHE_HTTP_LEGACY = "org.apache.http.legacy";
}
+1 −4
Original line number Diff line number Diff line
@@ -52,10 +52,7 @@ LOCAL_JAVA_LIBRARIES := \
    org.apache.http.legacy \
    android.test.base \
    android.test.mock \

ifeq ($(REMOVE_OAHL_FROM_BCP),true)
LOCAL_JAVA_LIBRARIES += framework-oahl-backward-compatibility
endif
    framework-oahl-backward-compatibility \

LOCAL_PACKAGE_NAME := FrameworksCoreTests
LOCAL_COMPATIBILITY_SUITE := device-tests
Loading