1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.pm; 18 19 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_BASE; 20 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_MOCK; 21 import static android.content.pm.SharedLibraryNames.ANDROID_TEST_RUNNER; 22 import static android.content.pm.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY; 23 24 import android.content.pm.PackageParser.Package; 25 import android.util.Log; 26 27 import com.android.internal.annotations.VisibleForTesting; 28 29 import java.util.ArrayList; 30 import java.util.List; 31 import java.util.function.Supplier; 32 33 /** 34 * Modifies {@link Package} in order to maintain backwards compatibility. 35 * 36 * @hide 37 */ 38 @VisibleForTesting 39 public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater { 40 41 private static final String TAG = PackageBackwardCompatibility.class.getSimpleName(); 42 43 private static final PackageBackwardCompatibility INSTANCE; 44 45 static { 46 final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>(); 47 48 // Attempt to load and add the optional updater that will only be available when 49 // REMOVE_OAHL_FROM_BCP=true. If that could not be found then add the default updater that 50 // will remove any references to org.apache.http.library from the package so that it does 51 // not try and load the library when it is on the bootclasspath. 52 boolean bootClassPathContainsOAHL = !addOptionalUpdater(packageUpdaters, 53 "android.content.pm.OrgApacheHttpLegacyUpdater", 54 RemoveUnnecessaryOrgApacheHttpLegacyLibrary::new); 55 56 // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before 57 // android.test.mock. packageUpdaters.add(new AndroidTestRunnerSplitUpdater())58 packageUpdaters.add(new AndroidTestRunnerSplitUpdater()); 59 60 // Attempt to load and add the optional updater that will only be available when 61 // REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that 62 // will remove any references to org.apache.http.library from the package so that it does 63 // not try and load the library when it is on the bootclasspath. 64 boolean bootClassPathContainsATB = !addOptionalUpdater(packageUpdaters, 65 "android.content.pm.AndroidTestBaseUpdater", 66 RemoveUnnecessaryAndroidTestBaseLibrary::new); 67 68 PackageSharedLibraryUpdater[] updaterArray = packageUpdaters 69 .toArray(new PackageSharedLibraryUpdater[0]); 70 INSTANCE = new PackageBackwardCompatibility( 71 bootClassPathContainsOAHL, bootClassPathContainsATB, updaterArray); 72 } 73 74 /** 75 * Add an optional {@link PackageSharedLibraryUpdater} instance to the list, if it could not be 76 * found then add a default instance instead. 77 * 78 * @param packageUpdaters the list to update. 79 * @param className the name of the optional class. 80 * @param defaultUpdater the supplier of the default instance. 81 * @return true if the optional updater was added false otherwise. 82 */ addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters, String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater)83 private static boolean addOptionalUpdater(List<PackageSharedLibraryUpdater> packageUpdaters, 84 String className, Supplier<PackageSharedLibraryUpdater> defaultUpdater) { 85 Class<? extends PackageSharedLibraryUpdater> clazz; 86 try { 87 clazz = (PackageBackwardCompatibility.class.getClassLoader() 88 .loadClass(className) 89 .asSubclass(PackageSharedLibraryUpdater.class)); 90 Log.i(TAG, "Loaded " + className); 91 } catch (ClassNotFoundException e) { 92 Log.i(TAG, "Could not find " + className + ", ignoring"); 93 clazz = null; 94 } 95 96 boolean usedOptional = false; 97 PackageSharedLibraryUpdater updater; 98 if (clazz == null) { 99 updater = defaultUpdater.get(); 100 } else { 101 try { 102 updater = clazz.getConstructor().newInstance(); 103 usedOptional = true; 104 } catch (ReflectiveOperationException e) { 105 throw new IllegalStateException("Could not create instance of " + className, e); 106 } 107 } 108 packageUpdaters.add(updater); 109 return usedOptional; 110 } 111 112 @VisibleForTesting getInstance()113 public static PackageSharedLibraryUpdater getInstance() { 114 return INSTANCE; 115 } 116 117 private final boolean mBootClassPathContainsOAHL; 118 119 private final boolean mBootClassPathContainsATB; 120 121 private final PackageSharedLibraryUpdater[] mPackageUpdaters; 122 PackageBackwardCompatibility(boolean bootClassPathContainsOAHL, boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters)123 public PackageBackwardCompatibility(boolean bootClassPathContainsOAHL, 124 boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) { 125 this.mBootClassPathContainsOAHL = bootClassPathContainsOAHL; 126 this.mBootClassPathContainsATB = bootClassPathContainsATB; 127 this.mPackageUpdaters = packageUpdaters; 128 } 129 130 /** 131 * Modify the shared libraries in the supplied {@link Package} to maintain backwards 132 * compatibility. 133 * 134 * @param pkg the {@link Package} to modify. 135 */ 136 @VisibleForTesting modifySharedLibraries(Package pkg)137 public static void modifySharedLibraries(Package pkg) { 138 INSTANCE.updatePackage(pkg); 139 } 140 141 @Override updatePackage(Package pkg)142 public void updatePackage(Package pkg) { 143 for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) { 144 packageUpdater.updatePackage(pkg); 145 } 146 } 147 148 /** 149 * True if the org.apache.http.legacy is on the bootclasspath, false otherwise. 150 */ 151 @VisibleForTesting bootClassPathContainsOAHL()152 public static boolean bootClassPathContainsOAHL() { 153 return INSTANCE.mBootClassPathContainsOAHL; 154 } 155 156 /** 157 * True if the android.test.base is on the bootclasspath, false otherwise. 158 */ 159 @VisibleForTesting bootClassPathContainsATB()160 public static boolean bootClassPathContainsATB() { 161 return INSTANCE.mBootClassPathContainsATB; 162 } 163 164 /** 165 * Add android.test.mock dependency for any APK that depends on android.test.runner. 166 * 167 * <p>This is needed to maintain backwards compatibility as in previous versions of Android the 168 * android.test.runner library included the classes from android.test.mock which have since 169 * been split out into a separate library. 170 * 171 * @hide 172 */ 173 @VisibleForTesting 174 public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater { 175 176 @Override updatePackage(Package pkg)177 public void updatePackage(Package pkg) { 178 // android.test.runner has a dependency on android.test.mock so if android.test.runner 179 // is present but android.test.mock is not then add android.test.mock. 180 prefixImplicitDependency(pkg, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK); 181 } 182 } 183 184 /** 185 * Remove any usages of org.apache.http.legacy from the shared library as the library is on the 186 * bootclasspath. 187 */ 188 @VisibleForTesting 189 public static class RemoveUnnecessaryOrgApacheHttpLegacyLibrary 190 extends PackageSharedLibraryUpdater { 191 192 @Override updatePackage(Package pkg)193 public void updatePackage(Package pkg) { 194 removeLibrary(pkg, ORG_APACHE_HTTP_LEGACY); 195 } 196 197 } 198 199 /** 200 * Remove any usages of android.test.base from the shared library as the library is on the 201 * bootclasspath. 202 */ 203 @VisibleForTesting 204 public static class RemoveUnnecessaryAndroidTestBaseLibrary 205 extends PackageSharedLibraryUpdater { 206 207 @Override updatePackage(Package pkg)208 public void updatePackage(Package pkg) { 209 removeLibrary(pkg, ANDROID_TEST_BASE); 210 } 211 } 212 } 213