1 /*
2  * Copyright (C) 2020 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 com.android.server.pm.parsing.library;
18 
19 import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_BASE;
20 import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_MOCK;
21 import static com.android.server.pm.parsing.library.SharedLibraryNames.ANDROID_TEST_RUNNER;
22 import static com.android.server.pm.parsing.library.SharedLibraryNames.ORG_APACHE_HTTP_LEGACY;
23 
24 import android.util.Log;
25 
26 import com.android.internal.annotations.VisibleForTesting;
27 import com.android.internal.pm.parsing.pkg.ParsedPackage;
28 import com.android.internal.pm.pkg.parsing.ParsingPackage;
29 import com.android.server.SystemConfig;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 /**
35  * Modifies {@link ParsedPackage} in order to maintain backwards compatibility.
36  *
37  * @hide
38  */
39 @VisibleForTesting
40 public class PackageBackwardCompatibility extends PackageSharedLibraryUpdater {
41 
42     private static final String TAG = PackageBackwardCompatibility.class.getSimpleName();
43 
44     private static final PackageBackwardCompatibility INSTANCE;
45 
46     static {
47         final List<PackageSharedLibraryUpdater> packageUpdaters = new ArrayList<>();
48 
49         // Remove android.net.ipsec.ike library, it is added to boot classpath since Android S.
packageUpdaters.add(new AndroidNetIpSecIkeUpdater())50         packageUpdaters.add(new AndroidNetIpSecIkeUpdater());
51 
52         // Remove com.google.android.maps library.
packageUpdaters.add(new ComGoogleAndroidMapsUpdater())53         packageUpdaters.add(new ComGoogleAndroidMapsUpdater());
54 
55         // Automatically add the org.apache.http.legacy library to the app classpath if the app
56         // targets < P.
packageUpdaters.add(new OrgApacheHttpLegacyUpdater())57         packageUpdaters.add(new OrgApacheHttpLegacyUpdater());
58 
packageUpdaters.add(new AndroidHidlUpdater())59         packageUpdaters.add(new AndroidHidlUpdater());
60 
61         // Add this before adding AndroidTestBaseUpdater so that android.test.base comes before
62         // android.test.mock.
packageUpdaters.add(new AndroidTestRunnerSplitUpdater())63         packageUpdaters.add(new AndroidTestRunnerSplitUpdater());
64 
65         boolean bootClassPathContainsATB = !addUpdaterForAndroidTestBase(packageUpdaters);
66 
67         // ApexSharedLibraryUpdater should be the last one, to allow modifications introduced by
68         // mainline after dessert release.
packageUpdaters.add(new ApexSharedLibraryUpdater( SystemConfig.getInstance().getSharedLibraries()))69         packageUpdaters.add(new ApexSharedLibraryUpdater(
70                 SystemConfig.getInstance().getSharedLibraries()));
71 
72         PackageSharedLibraryUpdater[] updaterArray = packageUpdaters
73                 .toArray(new PackageSharedLibraryUpdater[0]);
74         INSTANCE = new PackageBackwardCompatibility(
75                 bootClassPathContainsATB, updaterArray);
76     }
77 
78     /**
79      * Attempt to load and add the optional updater that will only be available when
80      * REMOVE_ATB_FROM_BCP=true. If that could not be found then add the default updater that
81      * will remove any references to org.apache.http.library from the package so that
82      * it does not try and load the library when it is on the bootclasspath.
83      *
84      * TODO:(b/135203078): Find a better way to do this.
85      */
addUpdaterForAndroidTestBase( List<PackageSharedLibraryUpdater> packageUpdaters)86     private static boolean addUpdaterForAndroidTestBase(
87             List<PackageSharedLibraryUpdater> packageUpdaters) {
88         boolean hasClass = false;
89         String className = "android.content.pm.AndroidTestBaseUpdater";
90         try {
91             Class clazz = ParsingPackage.class.getClassLoader().loadClass(className);
92             hasClass = clazz != null;
93             Log.i(TAG, "Loaded " + className);
94         } catch (ClassNotFoundException e) {
95             Log.i(TAG, "Could not find " + className + ", ignoring");
96         }
97 
98         if (hasClass) {
99             packageUpdaters.add(new AndroidTestBaseUpdater());
100         } else {
101             packageUpdaters.add(new RemoveUnnecessaryAndroidTestBaseLibrary());
102         }
103         return hasClass;
104     }
105 
106     @VisibleForTesting
getInstance()107     public static PackageSharedLibraryUpdater getInstance() {
108         return INSTANCE;
109     }
110 
111     private final boolean mBootClassPathContainsATB;
112 
113     private final PackageSharedLibraryUpdater[] mPackageUpdaters;
114 
115     @VisibleForTesting
getPackageUpdaters()116     PackageSharedLibraryUpdater[] getPackageUpdaters() {
117         return mPackageUpdaters;
118     }
119 
PackageBackwardCompatibility( boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters)120     private PackageBackwardCompatibility(
121             boolean bootClassPathContainsATB, PackageSharedLibraryUpdater[] packageUpdaters) {
122         this.mBootClassPathContainsATB = bootClassPathContainsATB;
123         this.mPackageUpdaters = packageUpdaters;
124     }
125 
126     /**
127      * Modify the shared libraries in the supplied {@link ParsedPackage} to maintain backwards
128      * compatibility.
129      *
130      * @param parsedPackage the {@link ParsedPackage} to modify.
131      */
132     @VisibleForTesting
modifySharedLibraries(ParsedPackage parsedPackage, boolean isSystemApp, boolean isUpdatedSystemApp)133     public static void modifySharedLibraries(ParsedPackage parsedPackage, boolean isSystemApp,
134             boolean isUpdatedSystemApp) {
135         INSTANCE.updatePackage(parsedPackage, isSystemApp, isUpdatedSystemApp);
136     }
137 
138     @Override
updatePackage(ParsedPackage parsedPackage, boolean isSystemApp, boolean isUpdatedSystemApp)139     public void updatePackage(ParsedPackage parsedPackage, boolean isSystemApp,
140             boolean isUpdatedSystemApp) {
141         for (PackageSharedLibraryUpdater packageUpdater : mPackageUpdaters) {
142             packageUpdater.updatePackage(parsedPackage, isSystemApp, isUpdatedSystemApp);
143         }
144     }
145 
146     /**
147      * True if the android.test.base is on the bootclasspath, false otherwise.
148      */
149     @VisibleForTesting
bootClassPathContainsATB()150     public static boolean bootClassPathContainsATB() {
151         return INSTANCE.mBootClassPathContainsATB;
152     }
153 
154     /**
155      * Add android.test.mock dependency for any APK that depends on android.test.runner.
156      *
157      * <p>This is needed to maintain backwards compatibility as in previous versions of Android the
158      * android.test.runner library included the classes from android.test.mock which have since
159      * been split out into a separate library.
160      *
161      * @hide
162      */
163     @VisibleForTesting
164     public static class AndroidTestRunnerSplitUpdater extends PackageSharedLibraryUpdater {
165 
166         @Override
updatePackage(ParsedPackage parsedPackage, boolean isSystemApp, boolean isUpdatedSystemApp)167         public void updatePackage(ParsedPackage parsedPackage, boolean isSystemApp,
168                 boolean isUpdatedSystemApp) {
169             // android.test.runner has a dependency on android.test.mock so if android.test.runner
170             // is present but android.test.mock is not then add android.test.mock.
171             prefixImplicitDependency(parsedPackage, ANDROID_TEST_RUNNER, ANDROID_TEST_MOCK);
172         }
173     }
174 
175     /**
176      * Remove any usages of org.apache.http.legacy from the shared library as the library is on the
177      * bootclasspath.
178      */
179     @VisibleForTesting
180     public static class RemoveUnnecessaryOrgApacheHttpLegacyLibrary
181             extends PackageSharedLibraryUpdater {
182 
183         @Override
updatePackage(ParsedPackage parsedPackage, boolean isSystemApp, boolean isUpdatedSystemApp)184         public void updatePackage(ParsedPackage parsedPackage, boolean isSystemApp,
185                 boolean isUpdatedSystemApp) {
186             removeLibrary(parsedPackage, ORG_APACHE_HTTP_LEGACY);
187         }
188 
189     }
190 
191     /**
192      * Remove any usages of android.test.base from the shared library as the library is on the
193      * bootclasspath.
194      */
195     @VisibleForTesting
196     public static class RemoveUnnecessaryAndroidTestBaseLibrary
197             extends PackageSharedLibraryUpdater {
198 
199         @Override
updatePackage(ParsedPackage parsedPackage, boolean isSystemApp, boolean isUpdatedSystemApp)200         public void updatePackage(ParsedPackage parsedPackage, boolean isSystemApp,
201                 boolean isUpdatedSystemApp) {
202             removeLibrary(parsedPackage, ANDROID_TEST_BASE);
203         }
204     }
205 }
206