1 /*
2  * Copyright (C) 2021 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;
18 
19 import android.annotation.Nullable;
20 import android.content.pm.SharedLibraryInfo;
21 
22 import com.android.server.pm.pkg.PackageStateInternal;
23 import com.android.server.pm.pkg.SharedLibraryWrapper;
24 import com.android.server.utils.WatchedLongSparseArray;
25 
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 
33 final class SharedLibraryUtils {
34 
35     /**
36      * Returns false if the adding shared library already exists in the map and so could not be
37      * added.
38      */
addSharedLibraryToPackageVersionMap( Map<String, WatchedLongSparseArray<SharedLibraryInfo>> target, SharedLibraryInfo library)39     public static boolean addSharedLibraryToPackageVersionMap(
40             Map<String, WatchedLongSparseArray<SharedLibraryInfo>> target,
41             SharedLibraryInfo library) {
42         final String name = library.getName();
43         if (target.containsKey(name)) {
44             if (library.getType() != SharedLibraryInfo.TYPE_STATIC) {
45                 // We've already added this non-version-specific library to the map.
46                 return false;
47             } else if (target.get(name).indexOfKey(library.getLongVersion()) >= 0) {
48                 // We've already added this version of a version-specific library to the map.
49                 return false;
50             }
51         } else {
52             target.put(name, new WatchedLongSparseArray<>());
53         }
54         target.get(name).put(library.getLongVersion(), library);
55         return true;
56     }
57 
58     @Nullable
getSharedLibraryInfo(String name, long version, Map<String, WatchedLongSparseArray<SharedLibraryInfo>> existingLibraries, @Nullable Map<String, WatchedLongSparseArray<SharedLibraryInfo>> newLibraries)59     public static SharedLibraryInfo getSharedLibraryInfo(String name, long version,
60             Map<String, WatchedLongSparseArray<SharedLibraryInfo>> existingLibraries,
61             @Nullable Map<String, WatchedLongSparseArray<SharedLibraryInfo>> newLibraries) {
62         if (newLibraries != null) {
63             final WatchedLongSparseArray<SharedLibraryInfo> versionedLib = newLibraries.get(name);
64             SharedLibraryInfo info = null;
65             if (versionedLib != null) {
66                 info = versionedLib.get(version);
67             }
68             if (info != null) {
69                 return info;
70             }
71         }
72         final WatchedLongSparseArray<SharedLibraryInfo> versionedLib = existingLibraries.get(name);
73         if (versionedLib == null) {
74             return null;
75         }
76         return versionedLib.get(version);
77     }
78 
findSharedLibraries(PackageStateInternal pkgSetting)79     public static List<SharedLibraryInfo> findSharedLibraries(PackageStateInternal pkgSetting) {
80         if (!pkgSetting.getTransientState().getUsesLibraryInfos().isEmpty()) {
81             ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
82             Set<String> collectedNames = new HashSet<>();
83             for (SharedLibraryWrapper info : pkgSetting.getTransientState().getUsesLibraryInfos()) {
84                 findSharedLibrariesRecursive(info.getInfo(), retValue, collectedNames);
85             }
86             return retValue;
87         } else {
88             return Collections.emptyList();
89         }
90     }
91 
findSharedLibrariesRecursive(SharedLibraryInfo info, ArrayList<SharedLibraryInfo> collected, Set<String> collectedNames)92     private static void findSharedLibrariesRecursive(SharedLibraryInfo info,
93             ArrayList<SharedLibraryInfo> collected, Set<String> collectedNames) {
94         if (!collectedNames.contains(info.getName())) {
95             collectedNames.add(info.getName());
96             collected.add(info);
97 
98             if (info.getDependencies() != null) {
99                 for (SharedLibraryInfo dep : info.getDependencies()) {
100                     findSharedLibrariesRecursive(dep, collected, collectedNames);
101                 }
102             }
103         }
104     }
105 
106 }
107