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