1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199
|
/*
* Copyright (C) 2017 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 android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE;
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 java.util.ArrayList;
import java.util.List;
import java.util.function.Supplier;
/**
* Modifies {@link Package} in order to maintain backwards compatibility.
*
* @hide
*/
@VisibleForTesting
public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
private static final String TAG = PackageBackwardCompatibility.class.getSimpleName();
private static final PackageBackwardCompatibility INSTANCE;
static {
final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
// Automatically add the org.apache.http.legacy library to the app classpath if the app
// targets < P.
packageUpdaters.add(new OrgApacheHttpLegacyUpdater());
packageUpdaters.add(new AndroidHidlUpdater());
// Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
// android.test.mock.
packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
// Attempt to load and add the optional updater that will only be available when
// REMOVE_ATB_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 bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters,
"android.content.pm.AndroidTestBaseUpdater",
RemoveUnnecessaryAndroidTestBaseLibrary::new);
PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
.toArray(new PackageSharedLibraryUpdater[0]);
INSTANCE = new PackageBackwardCompatibility(
bootClassPathContainsATB, 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 usedOptional = false;
PackageSharedLibraryUpdater updater;
if (clazz == null) {
updater = defaultUpdater.get();
} else {
try {
updater = clazz.getConstructor().newInstance();
usedOptional = true;
} catch (ReflectiveOperationException e) {
throw new IllegalStateException("Could not create instance of " + className, e);
}
}
packageUpdaters.add(updater);
return usedOptional;
}
@VisibleForTesting
public static PackageSharedLibraryUpdater getInstance() {
return INSTANCE;
}
private final boolean mBootClassPathContainsATB;
private final PackageSharedLibraryUpdater[] mPackageUpdaters;
private PackageBackwardCompatibility(
boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
this.mBootClassPathContainsATB = bootClassPathContainsATB;
this.mPackageUpdaters = packageUpdaters;
}
/**
* Modify the shared libraries in the supplied {@link Package} to maintain backwards
* compatibility.
*
* @param pkg the {@link Package} to modify.
*/
@VisibleForTesting
public static void modifySharedLibraries(Package pkg) {
INSTANCE.updatePackage(pkg);
}
@Override
public void updatePackage(Package pkg) {
for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
packageUpdater.updatePackage(pkg);
}
}
/**
* True if the android.test.base is on the bootclasspath, false otherwise.
*/
@VisibleForTesting
public static boolean bootClassPathContainsATB() {
return INSTANCE.mBootClassPathContainsATB;
}
/**
* 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) {
// 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.
prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
}
}
/**
* 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 {
@Override
public void updatePackage(Package pkg) {
removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY);
}
}
/**
* Remove any usages of android.test.base from the shared library as the library is on the
* bootclasspath.
*/
@VisibleForTesting
public static class RemoveUnnecessaryAndroidTestBaseLibrary
extends PackageSharedLibraryUpdater {
@Override
public void updatePackage(Package pkg) {
removeLibrary(pkg, ANDROID_TEST_BASE);
}
}
}
|