1 /*
2  * Copyright (C) 2018 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 package android.content.pm;
17 
18 import android.annotation.NonNull;
19 import android.annotation.Nullable;
20 
21 import com.android.internal.annotations.VisibleForTesting;
22 import com.android.internal.util.ArrayUtils;
23 
24 import java.util.ArrayList;
25 
26 /**
27  * Base for classes that update a {@link PackageParser.Package}'s shared libraries.
28  *
29  * @hide
30  */
31 @VisibleForTesting
32 public abstract class PackageSharedLibraryUpdater {
33 
34     /**
35      * Update the package's shared libraries.
36      *
37      * @param pkg the package to update.
38      */
updatePackage(PackageParser.Package pkg)39     public abstract void updatePackage(PackageParser.Package pkg);
40 
removeLibrary(PackageParser.Package pkg, String libraryName)41     static void removeLibrary(PackageParser.Package pkg, String libraryName) {
42         pkg.usesLibraries = ArrayUtils.remove(pkg.usesLibraries, libraryName);
43         pkg.usesOptionalLibraries =
44                 ArrayUtils.remove(pkg.usesOptionalLibraries, libraryName);
45     }
46 
47     static @NonNull
prefix(@ullable ArrayList<T> cur, T val)48             <T> ArrayList<T> prefix(@Nullable ArrayList<T> cur, T val) {
49         if (cur == null) {
50             cur = new ArrayList<>();
51         }
52         cur.add(0, val);
53         return cur;
54     }
55 
isLibraryPresent(ArrayList<String> usesLibraries, ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy)56     private static boolean isLibraryPresent(ArrayList<String> usesLibraries,
57             ArrayList<String> usesOptionalLibraries, String apacheHttpLegacy) {
58         return ArrayUtils.contains(usesLibraries, apacheHttpLegacy)
59                 || ArrayUtils.contains(usesOptionalLibraries, apacheHttpLegacy);
60     }
61 
62     /**
63      * Add an implicit dependency.
64      *
65      * <p>If the package has an existing dependency on {@code existingLibrary} then prefix it with
66      * the {@code implicitDependency} if it is not already in the list of libraries.
67      *
68      * @param pkg the {@link PackageParser.Package} to update.
69      * @param existingLibrary the existing library.
70      * @param implicitDependency the implicit dependency to add
71      */
prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary, String implicitDependency)72     void prefixImplicitDependency(PackageParser.Package pkg, String existingLibrary,
73             String implicitDependency) {
74         ArrayList<String> usesLibraries = pkg.usesLibraries;
75         ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
76 
77         if (!isLibraryPresent(usesLibraries, usesOptionalLibraries, implicitDependency)) {
78             if (ArrayUtils.contains(usesLibraries, existingLibrary)) {
79                 prefix(usesLibraries, implicitDependency);
80             } else if (ArrayUtils.contains(usesOptionalLibraries, existingLibrary)) {
81                 prefix(usesOptionalLibraries, implicitDependency);
82             }
83 
84             pkg.usesLibraries = usesLibraries;
85             pkg.usesOptionalLibraries = usesOptionalLibraries;
86         }
87     }
88 
prefixRequiredLibrary(PackageParser.Package pkg, String libraryName)89     void prefixRequiredLibrary(PackageParser.Package pkg, String libraryName) {
90         ArrayList<String> usesLibraries = pkg.usesLibraries;
91         ArrayList<String> usesOptionalLibraries = pkg.usesOptionalLibraries;
92 
93         boolean alreadyPresent = isLibraryPresent(
94                 usesLibraries, usesOptionalLibraries, libraryName);
95         if (!alreadyPresent) {
96             usesLibraries = prefix(usesLibraries, libraryName);
97 
98             pkg.usesLibraries = usesLibraries;
99         }
100     }
101 }
102