• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
20 import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST;
21 
22 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
23 import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
24 import static com.android.server.pm.PackageManagerService.TAG;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.compat.annotation.ChangeId;
29 import android.compat.annotation.EnabledAfter;
30 import android.content.pm.Flags;
31 import android.content.pm.PackageManager;
32 import android.content.pm.SharedLibraryInfo;
33 import android.content.pm.Signature;
34 import android.content.pm.SigningDetails;
35 import android.content.pm.VersionedPackage;
36 import android.content.pm.parsing.PackageLite;
37 import android.os.Build;
38 import android.os.Process;
39 import android.os.UserHandle;
40 import android.os.storage.StorageManager;
41 import android.service.pm.PackageServiceDumpProto;
42 import android.util.ArraySet;
43 import android.util.PackageUtils;
44 import android.util.Pair;
45 import android.util.Slog;
46 import android.util.proto.ProtoOutputStream;
47 
48 import com.android.internal.annotations.GuardedBy;
49 import com.android.internal.annotations.VisibleForTesting;
50 import com.android.internal.pm.parsing.pkg.ParsedPackage;
51 import com.android.internal.util.ArrayUtils;
52 import com.android.server.SystemConfig;
53 import com.android.server.compat.PlatformCompat;
54 import com.android.server.pm.parsing.pkg.AndroidPackageUtils;
55 import com.android.server.pm.pkg.AndroidPackage;
56 import com.android.server.pm.pkg.PackageStateInternal;
57 import com.android.server.utils.Snappable;
58 import com.android.server.utils.SnapshotCache;
59 import com.android.server.utils.Watchable;
60 import com.android.server.utils.WatchableImpl;
61 import com.android.server.utils.Watched;
62 import com.android.server.utils.WatchedArrayMap;
63 import com.android.server.utils.WatchedLongSparseArray;
64 import com.android.server.utils.Watcher;
65 
66 import libcore.util.HexEncoding;
67 
68 import java.io.File;
69 import java.io.IOException;
70 import java.io.PrintWriter;
71 import java.util.ArrayList;
72 import java.util.Arrays;
73 import java.util.Collections;
74 import java.util.LinkedHashSet;
75 import java.util.List;
76 import java.util.Map;
77 import java.util.Set;
78 import java.util.function.BiConsumer;
79 
80 /**
81  * Current known shared libraries on the device.
82  */
83 public final class SharedLibrariesImpl implements SharedLibrariesRead, Watchable, Snappable {
84     private static final boolean DEBUG_SHARED_LIBRARIES = false;
85 
86     private static final String LIBRARY_TYPE_SDK = "sdk";
87     private static final String LIBRARY_TYPE_STATIC = "static shared";
88 
89     /**
90      * Apps targeting Android S and above need to declare dependencies to the public native
91      * shared libraries that are defined by the device maker using {@code uses-native-library} tag
92      * in its {@code AndroidManifest.xml}.
93      *
94      * If any of the dependencies cannot be satisfied, i.e. one of the dependency doesn't exist,
95      * the package manager rejects to install the app. The dependency can be specified as optional
96      * using {@code android:required} attribute in the tag, in which case failing to satisfy the
97      * dependency doesn't stop the installation.
98      * <p>Once installed, an app is provided with only the native shared libraries that are
99      * specified in the app manifest. {@code dlopen}ing a native shared library that doesn't appear
100      * in the app manifest will fail even if it actually exists on the device.
101      */
102     @ChangeId
103     @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
104     private static final long ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES = 142191088;
105 
106     // TODO(b/200588896): remove PMS dependency
107     private final PackageManagerService mPm;
108     private final PackageManagerServiceInjector mInjector;
109     private DeletePackageHelper mDeletePackageHelper; // late init
110 
111     // A map of library name to a list of {@link SharedLibraryInfo}s with different versions.
112     @Watched
113     private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
114             mSharedLibraries;
115     private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
116             mSharedLibrariesSnapshot;
117 
118     // A map of declaring package name to a list of {@link SharedLibraryInfo}s with different
119     // versions.
120     @Watched
121     private final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
122             mStaticLibsByDeclaringPackage;
123     private final SnapshotCache<WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>>
124             mStaticLibsByDeclaringPackageSnapshot;
125 
126     /**
127      * Watchable machinery
128      */
129     private final WatchableImpl mWatchable = new WatchableImpl();
130 
131     /**
132      * The observer that watches for changes from array members
133      */
134     private final Watcher mObserver = new Watcher() {
135         @Override
136         public void onChange(@Nullable Watchable what) {
137             SharedLibrariesImpl.this.dispatchChange(what);
138         }
139     };
140 
141     private final SnapshotCache<SharedLibrariesImpl> mSnapshot;
142 
143     // Create a snapshot cache
makeCache()144     private SnapshotCache<SharedLibrariesImpl> makeCache() {
145         return new SnapshotCache<SharedLibrariesImpl>(this /* source */, this /* watchable */) {
146             @Override
147             public SharedLibrariesImpl createSnapshot() {
148                 final SharedLibrariesImpl sharedLibrariesImpl = new SharedLibrariesImpl(mSource);
149                 sharedLibrariesImpl.mWatchable.seal();
150                 return sharedLibrariesImpl;
151             }};
152     }
153 
154     /**
155      * Default constructor used in PackageManagerService.
156      */
157     SharedLibrariesImpl(PackageManagerService pm, PackageManagerServiceInjector injector) {
158         mPm = pm;
159         mInjector = injector;
160 
161         mSharedLibraries = new WatchedArrayMap<>();
162         mSharedLibrariesSnapshot = new SnapshotCache.Auto<>(mSharedLibraries, mSharedLibraries,
163                 "SharedLibrariesImpl.mSharedLibraries");
164         mStaticLibsByDeclaringPackage = new WatchedArrayMap<>();
165         mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Auto<>(
166                 mStaticLibsByDeclaringPackage, mStaticLibsByDeclaringPackage,
167                 "SharedLibrariesImpl.mStaticLibsByDeclaringPackage");
168 
169         registerObservers();
170         Watchable.verifyWatchedAttributes(this, mObserver);
171         mSnapshot = makeCache();
172     }
173 
174     /**
175      * Invoked by PMS constructor after the instance of {@link DeletePackageHelper} is ready.
176      */
177     void setDeletePackageHelper(DeletePackageHelper deletePackageHelper) {
178         mDeletePackageHelper = deletePackageHelper;
179     }
180 
181     private void registerObservers() {
182         mSharedLibraries.registerObserver(mObserver);
183         mStaticLibsByDeclaringPackage.registerObserver(mObserver);
184     }
185 
186     /**
187      * A copy constructor used in snapshot().
188      */
189     private SharedLibrariesImpl(SharedLibrariesImpl source) {
190         mPm = source.mPm;
191         mInjector = source.mInjector;
192 
193         mSharedLibraries = source.mSharedLibrariesSnapshot.snapshot();
194         mSharedLibrariesSnapshot = new SnapshotCache.Sealed<>();
195         mStaticLibsByDeclaringPackage = source.mStaticLibsByDeclaringPackageSnapshot.snapshot();
196         mStaticLibsByDeclaringPackageSnapshot = new SnapshotCache.Sealed<>();
197 
198         // Do not register any Watchables and do not create a snapshot cache.
199         mSnapshot = new SnapshotCache.Sealed();
200     }
201 
202     /**
203      * Ensures an observer is in the list, exactly once. The observer cannot be null.  The
204      * function quietly returns if the observer is already in the list.
205      *
206      * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes.
207      */
208     @Override
209     public void registerObserver(@NonNull Watcher observer) {
210         mWatchable.registerObserver(observer);
211     }
212 
213     /**
214      * Ensures an observer is not in the list. The observer must not be null.  The function
215      * quietly returns if the objserver is not in the list.
216      *
217      * @param observer The {@link Watcher} that should not be in the notification list.
218      */
219     @Override
220     public void unregisterObserver(@NonNull Watcher observer) {
221         mWatchable.unregisterObserver(observer);
222     }
223 
224     /**
225      * Return true if the {@link Watcher} is a registered observer.
226      * @param observer A {@link Watcher} that might be registered
227      * @return true if the observer is registered with this {@link Watchable}.
228      */
229     @Override
230     public boolean isRegisteredObserver(@NonNull Watcher observer) {
231         return mWatchable.isRegisteredObserver(observer);
232     }
233 
234     /**
235      * Invokes {@link Watcher#onChange} on each registered observer.  The method can be called
236      * with the {@link Watchable} that generated the event.  In a tree of {@link Watchable}s, this
237      * is generally the first (deepest) {@link Watchable} to detect a change.
238      *
239      * @param what The {@link Watchable} that generated the event.
240      */
241     @Override
242     public void dispatchChange(@Nullable Watchable what) {
243         mWatchable.dispatchChange(what);
244     }
245 
246     /**
247      * Create an immutable copy of the object, suitable for read-only methods.  A snapshot
248      * is free to omit state that is only needed for mutating methods.
249      */
250     @Override
251     public @NonNull SharedLibrariesRead snapshot() {
252         return mSnapshot.snapshot();
253     }
254 
255     /**
256      * Returns all shared libraries on the device.
257      */
258     @GuardedBy("mPm.mLock")
259     @Override
260     public @NonNull WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getAll() {
261         return mSharedLibraries;
262     }
263 
264     /**
265      * Given the library name, returns a list of shared libraries on all versions.
266      * TODO: Remove, this is used for live mutation outside of the defined commit path
267      */
268 
269     @Override
270     public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getSharedLibraryInfos(
271             @NonNull String libName) {
272         synchronized (mPm.mLock) {
273             return mSharedLibraries.get(libName);
274         }
275     }
276 
277     @VisibleForTesting
278     public WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>> getSharedLibraries() {
279         return mSharedLibraries;
280     }
281 
282     /**
283      * Returns the shared library with given library name and version number.
284      */
285     @GuardedBy("mPm.mLock")
286     @Override
287     public @Nullable SharedLibraryInfo getSharedLibraryInfo(@NonNull String libName, long version) {
288         final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
289                 mSharedLibraries.get(libName);
290         if (versionedLib == null) {
291             return null;
292         }
293         return versionedLib.get(version);
294     }
295 
296     /**
297      * Given the declaring package name, returns a list of static shared libraries on all versions.
298      */
299     @GuardedBy("mPm.mLock")
300     @Override
301     public @NonNull WatchedLongSparseArray<SharedLibraryInfo> getStaticLibraryInfos(
302             @NonNull String declaringPackageName) {
303         return mStaticLibsByDeclaringPackage.get(declaringPackageName);
304     }
305 
306     @Nullable
307     private PackageStateInternal getLibraryPackage(@NonNull Computer computer,
308             @NonNull SharedLibraryInfo libInfo) {
309         final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
310         if (libInfo.isStatic()) {
311             // Resolve the package name - we use synthetic package names internally
312             final String internalPackageName = computer.resolveInternalPackageName(
313                     declaringPackage.getPackageName(),
314                     declaringPackage.getLongVersionCode());
315             return computer.getPackageStateInternal(internalPackageName);
316         }
317         if (libInfo.isSdk()) {
318             return computer.getPackageStateInternal(declaringPackage.getPackageName());
319         }
320         return null;
321     }
322 
323     /**
324      * Finds all unused shared libraries which have cached more than the given
325      * {@code maxCachePeriod}. Deletes them one by one until the available storage space on the
326      * device is larger than {@code neededSpace}.
327      *
328      * @param neededSpace A minimum available storage space the device needs to reach
329      * @param maxCachePeriod A maximum period of time an unused shared library can be cached
330      *                       on the device.
331      * @return {@code true} if the available storage space is reached.
332      */
333     boolean pruneUnusedStaticSharedLibraries(@NonNull Computer computer, long neededSpace,
334             long maxCachePeriod)
335             throws IOException {
336         final StorageManager storage = mInjector.getSystemService(StorageManager.class);
337         final File volume = storage.findPathForUuid(StorageManager.UUID_PRIVATE_INTERNAL);
338 
339         final ArrayList<VersionedPackage> packagesToDelete = new ArrayList<>();
340         final long now = System.currentTimeMillis();
341 
342         // Important: We skip shared libs used for some user since
343         // in such a case we need to keep the APK on the device. The check for
344         // a lib being used for any user is performed by the uninstall call.
345         final WatchedArrayMap<String, WatchedLongSparseArray<SharedLibraryInfo>>
346                 sharedLibraries = computer.getSharedLibraries();
347         final int libCount = sharedLibraries.size();
348         for (int i = 0; i < libCount; i++) {
349             final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
350                     sharedLibraries.valueAt(i);
351             if (versionedLib == null) {
352                 continue;
353             }
354             final int versionCount = versionedLib.size();
355             for (int j = 0; j < versionCount; j++) {
356                 SharedLibraryInfo libInfo = versionedLib.valueAt(j);
357                 final PackageStateInternal ps = getLibraryPackage(computer, libInfo);
358                 if (ps == null) {
359                     continue;
360                 }
361                 // Skip unused libs cached less than the min period to prevent pruning a lib
362                 // needed by a subsequently installed package.
363                 if (now - ps.getLastUpdateTime() < maxCachePeriod) {
364                     continue;
365                 }
366 
367                 if (ps.isSystem()) {
368                     continue;
369                 }
370 
371                 packagesToDelete.add(new VersionedPackage(ps.getPkg().getPackageName(),
372                         libInfo.getDeclaringPackage().getLongVersionCode()));
373             }
374         }
375 
376         final int packageCount = packagesToDelete.size();
377         for (int i = 0; i < packageCount; i++) {
378             final VersionedPackage pkgToDelete = packagesToDelete.get(i);
379             // Delete the package synchronously (will fail of the lib used for any user).
380             if (mDeletePackageHelper.deletePackageX(pkgToDelete.getPackageName(),
381                     pkgToDelete.getLongVersionCode(), UserHandle.USER_SYSTEM,
382                     PackageManager.DELETE_ALL_USERS,
383                     true /*removedBySystem*/) == PackageManager.DELETE_SUCCEEDED) {
384                 if (volume.getUsableSpace() >= neededSpace) {
385                     return true;
386                 }
387             }
388         }
389 
390         return false;
391     }
392 
393     @Nullable SharedLibraryInfo getLatestStaticSharedLibraVersion(@NonNull AndroidPackage pkg) {
394         synchronized (mPm.mLock) {
395             return getLatestStaticSharedLibraVersionLPr(pkg);
396         }
397     }
398     /**
399      * Given a package of static shared library, returns its shared library info of
400      * the latest version.
401      *
402      * @param pkg A package of static shared library.
403      * @return The latest version of shared library info.
404      */
405     @GuardedBy("mPm.mLock")
406     @Nullable
407     private SharedLibraryInfo getLatestStaticSharedLibraVersionLPr(@NonNull AndroidPackage pkg) {
408         WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(
409                 pkg.getStaticSharedLibraryName());
410         if (versionedLib == null) {
411             return null;
412         }
413         long previousLibVersion = -1;
414         final int versionCount = versionedLib.size();
415         for (int i = 0; i < versionCount; i++) {
416             final long libVersion = versionedLib.keyAt(i);
417             if (libVersion < pkg.getStaticSharedLibraryVersion()) {
418                 previousLibVersion = Math.max(previousLibVersion, libVersion);
419             }
420         }
421         if (previousLibVersion >= 0) {
422             return versionedLib.get(previousLibVersion);
423         }
424         return null;
425     }
426 
427     /**
428      * Given a package scanned result of a static shared library, returns its package setting of
429      * the latest version
430      *
431      * @param installRequest The install result of a static shared library package.
432      * @return The package setting that represents the latest version of shared library info.
433      */
434     @Nullable
435     PackageSetting getStaticSharedLibLatestVersionSetting(@NonNull InstallRequest installRequest) {
436         if (installRequest.getParsedPackage() == null) {
437             return null;
438         }
439         PackageSetting sharedLibPackage = null;
440         synchronized (mPm.mLock) {
441             final SharedLibraryInfo latestSharedLibraVersionLPr =
442                     getLatestStaticSharedLibraVersionLPr(installRequest.getParsedPackage());
443             if (latestSharedLibraVersionLPr != null) {
444                 sharedLibPackage = mPm.mSettings.getPackageLPr(
445                         latestSharedLibraVersionLPr.getPackageName());
446             }
447         }
448         return sharedLibPackage;
449     }
450 
451     /**
452      * Apply a given {@code action} to all the libraries defining in the package.
453      *
454      * @param pkg A package defining libraries.
455      * @param libInfo An extra shared library info passing to the action.
456      * @param action The action to apply.
457      */
458     @GuardedBy("mPm.mLock")
459     private void applyDefiningSharedLibraryUpdateLPr(
460             @NonNull AndroidPackage pkg, @Nullable SharedLibraryInfo libInfo,
461             @NonNull BiConsumer<SharedLibraryInfo, SharedLibraryInfo> action) {
462         // Note that libraries defined by this package may be null if:
463         // - Package manager was unable to create the shared library. The package still
464         //   gets installed, but the shared library does not get created.
465         // Or:
466         // - Package manager is in a state where package isn't scanned yet. This will
467         //   get called again after scanning to fix the dependencies.
468         if (AndroidPackageUtils.isLibrary(pkg)) {
469             if (pkg.getSdkLibraryName() != null) {
470                 SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
471                         pkg.getSdkLibraryName(), pkg.getSdkLibVersionMajor());
472                 if (definedLibrary != null) {
473                     action.accept(definedLibrary, libInfo);
474                 }
475             } else if (pkg.getStaticSharedLibraryName() != null) {
476                 SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
477                         pkg.getStaticSharedLibraryName(), pkg.getStaticSharedLibraryVersion());
478                 if (definedLibrary != null) {
479                     action.accept(definedLibrary, libInfo);
480                 }
481             } else {
482                 for (String libraryName : pkg.getLibraryNames()) {
483                     SharedLibraryInfo definedLibrary = getSharedLibraryInfo(
484                             libraryName, SharedLibraryInfo.VERSION_UNDEFINED);
485                     if (definedLibrary != null) {
486                         action.accept(definedLibrary, libInfo);
487                     }
488                 }
489             }
490         }
491     }
492 
493     /**
494      * Adds shared library {@code libInfo}'s self code paths and using library files to the list
495      * {@code usesLibraryFiles}. Also, adds the dependencies to the shared libraries that are
496      * defining in the {@code pkg}.
497      *
498      * @param pkg A package that is using the {@code libInfo}.
499      * @param usesLibraryFiles A list to add code paths to.
500      * @param libInfo A shared library info that is used by the {@code pkg}.
501      * @param changingLib The updating library package.
502      * @param changingLibSetting The updating library package setting.
503      */
504     @GuardedBy("mPm.mLock")
505     private void addSharedLibraryLPr(@NonNull AndroidPackage pkg,
506             @NonNull Set<String> usesLibraryFiles, @NonNull SharedLibraryInfo libInfo,
507             @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting) {
508         if (libInfo.getPath() != null) {
509             usesLibraryFiles.add(libInfo.getPath());
510             return;
511         }
512         AndroidPackage pkgForCodePaths = mPm.mPackages.get(libInfo.getPackageName());
513         PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(libInfo.getPackageName());
514         if (changingLib != null && changingLib.getPackageName().equals(libInfo.getPackageName())) {
515             // If we are doing this while in the middle of updating a library apk,
516             // then we need to make sure to use that new apk for determining the
517             // dependencies here.  (We haven't yet finished committing the new apk
518             // to the package manager state.)
519             if (pkgForCodePaths == null
520                     || pkgForCodePaths.getPackageName().equals(changingLib.getPackageName())) {
521                 pkgForCodePaths = changingLib;
522                 pkgSetting = changingLibSetting;
523             }
524         }
525         if (pkgForCodePaths != null) {
526             usesLibraryFiles.addAll(AndroidPackageUtils.getAllCodePaths(pkgForCodePaths));
527             // If the package provides libraries, add the dependency to them.
528             applyDefiningSharedLibraryUpdateLPr(pkg, libInfo, SharedLibraryInfo::addDependency);
529             if (pkgSetting != null) {
530                 usesLibraryFiles.addAll(pkgSetting.getPkgState().getUsesLibraryFiles());
531             }
532         }
533     }
534 
535     /**
536      * Collects all shared libraries being used by the target package. Rebuilds the dependencies
537      * of shared libraries and update the correct shared library code paths for it.
538      *
539      * @param pkg The target package to update shared library dependency.
540      * @param pkgSetting The target's package setting.
541      * @param changingLib The updating library package.
542      * @param changingLibSetting The updating library package setting.
543      * @param availablePackages All installed packages and current being installed packages.
544      */
545     void updateSharedLibraries(@NonNull AndroidPackage pkg, @NonNull PackageSetting pkgSetting,
546             @Nullable AndroidPackage changingLib, @Nullable PackageSetting changingLibSetting,
547             @NonNull Map<String, AndroidPackage> availablePackages)
548             throws PackageManagerException {
549         final ArrayList<SharedLibraryInfo> sharedLibraryInfos = collectSharedLibraryInfos(
550                 pkg, availablePackages, null /* newLibraries */);
551         synchronized (mPm.mLock) {
552             executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting,
553                     sharedLibraryInfos, mPm.mUserManager.getUserIds());
554         }
555     }
556 
557     void executeSharedLibrariesUpdate(AndroidPackage pkg,
558             @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
559             @Nullable PackageSetting changingLibSetting,
560             ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) {
561         synchronized (mPm.mLock) {
562             executeSharedLibrariesUpdateLPw(pkg, pkgSetting, changingLib, changingLibSetting,
563                     usesLibraryInfos, allUsers);
564         }
565     }
566 
567     /**
568      * Rebuilds the dependencies of shared libraries for the target package, and update the
569      * shared library code paths to its package setting.
570      *
571      * @param pkg The target package to update shared library dependency.
572      * @param pkgSetting The target's package setting.
573      * @param changingLib The updating library package.
574      * @param changingLibSetting The updating library package setting.
575      * @param usesLibraryInfos The shared libraries used by the target package.
576      * @param allUsers All user ids on the device.
577      */
578     @GuardedBy("mPm.mLock")
579     private void executeSharedLibrariesUpdateLPw(AndroidPackage pkg,
580             @NonNull PackageSetting pkgSetting, @Nullable AndroidPackage changingLib,
581             @Nullable PackageSetting changingLibSetting,
582             ArrayList<SharedLibraryInfo> usesLibraryInfos, int[] allUsers) {
583         // If the package provides libraries, clear their old dependencies.
584         // This method will set them up again.
585         applyDefiningSharedLibraryUpdateLPr(pkg, null, (definingLibrary, dependency) -> {
586             definingLibrary.clearDependencies();
587         });
588         if (usesLibraryInfos != null) {
589             pkgSetting.getPkgState().setUsesLibraryInfos(usesLibraryInfos);
590             // Use LinkedHashSet to preserve the order of files added to
591             // usesLibraryFiles while eliminating duplicates.
592             Set<String> usesLibraryFiles = new LinkedHashSet<>();
593             for (SharedLibraryInfo libInfo : usesLibraryInfos) {
594                 addSharedLibraryLPr(pkg, usesLibraryFiles, libInfo, changingLib,
595                         changingLibSetting);
596             }
597             pkgSetting.setPkgStateLibraryFiles(usesLibraryFiles);
598 
599             // let's make sure we mark all static shared libraries as installed for the same users
600             // that its dependent packages are installed for.
601             int[] installedUsers = new int[allUsers.length];
602             int installedUserCount = 0;
603             for (int u = 0; u < allUsers.length; u++) {
604                 if (pkgSetting.getInstalled(allUsers[u])) {
605                     installedUsers[installedUserCount++] = allUsers[u];
606                 }
607             }
608             for (SharedLibraryInfo sharedLibraryInfo : usesLibraryInfos) {
609                 if (!sharedLibraryInfo.isStatic()) {
610                     continue;
611                 }
612                 final PackageSetting staticLibPkgSetting =
613                         mPm.getPackageSettingForMutation(sharedLibraryInfo.getPackageName());
614                 if (staticLibPkgSetting == null) {
615                     Slog.w(TAG, "Shared lib without setting: " + sharedLibraryInfo);
616                     continue;
617                 }
618                 for (int u = 0; u < installedUserCount; u++) {
619                     staticLibPkgSetting.setInstalled(true, installedUsers[u]);
620                 }
621             }
622         } else {
623             pkgSetting.getPkgState().setUsesLibraryInfos(Collections.emptyList())
624                     .setUsesLibraryFiles(Collections.emptyList());
625         }
626     }
627 
628     private static boolean hasString(List<String> list, List<String> which) {
629         if (list == null || which == null) {
630             return false;
631         }
632         for (int i = list.size() - 1; i >= 0; i--) {
633             for (int j = which.size() - 1; j >= 0; j--) {
634                 if (which.get(j).equals(list.get(i))) {
635                     return true;
636                 }
637             }
638         }
639         return false;
640     }
641 
642     ArrayList<AndroidPackage> commitSharedLibraryChanges(@NonNull AndroidPackage pkg,
643             @NonNull PackageSetting pkgSetting, List<SharedLibraryInfo> allowedSharedLibraryInfos,
644             @NonNull Map<String, AndroidPackage> combinedSigningDetails, int scanFlags) {
645         if (ArrayUtils.isEmpty(allowedSharedLibraryInfos)) {
646             return null;
647         }
648         synchronized (mPm.mLock) {
649             for (SharedLibraryInfo info : allowedSharedLibraryInfos) {
650                 commitSharedLibraryInfoLPw(info);
651             }
652             try {
653                 // Shared libraries for the package need to be updated.
654                 updateSharedLibraries(pkg, pkgSetting, null, null, combinedSigningDetails);
655             } catch (PackageManagerException e) {
656                 Slog.e(TAG, "updateSharedLibraries failed: ", e);
657             }
658             // Update all applications that use this library. Skip when booting
659             // since this will be done after all packages are scaned.
660             if ((scanFlags & SCAN_BOOTING) == 0) {
661                 return updateAllSharedLibrariesLPw(pkg, pkgSetting, combinedSigningDetails);
662             }
663         }
664         return null;
665     }
666 
667     /**
668      * Update shared library dependencies and code paths for applications that are using the
669      * library {@code updatedPkg}. Update all applications if the {@code updatedPkg} is null.
670      *
671      * @param updatedPkg The updating shared library package.
672      * @param updatedPkgSetting The updating shared library package setting.
673      * @param availablePackages All available packages on the device.
674      * @return Packages that has been updated.
675      */
676     @GuardedBy("mPm.mLock")
677     @Nullable ArrayList<AndroidPackage> updateAllSharedLibrariesLPw(
678             @Nullable AndroidPackage updatedPkg, @Nullable PackageSetting updatedPkgSetting,
679             @NonNull Map<String, AndroidPackage> availablePackages) {
680         ArrayList<AndroidPackage> resultList = null;
681         // Set of all descendants of a library; used to eliminate cycles
682         ArraySet<String> descendants = null;
683         // The current list of packages that need updating
684         List<Pair<AndroidPackage, PackageSetting>> needsUpdating = null;
685         if (updatedPkg != null && updatedPkgSetting != null) {
686             needsUpdating = new ArrayList<>(1);
687             needsUpdating.add(Pair.create(updatedPkg, updatedPkgSetting));
688         }
689         do {
690             final Pair<AndroidPackage, PackageSetting> changingPkgPair =
691                     (needsUpdating == null) ? null : needsUpdating.remove(0);
692             final AndroidPackage changingPkg = changingPkgPair != null
693                     ? changingPkgPair.first : null;
694             final PackageSetting changingPkgSetting = changingPkgPair != null
695                     ? changingPkgPair.second : null;
696             for (int i = mPm.mPackages.size() - 1; i >= 0; --i) {
697                 final AndroidPackage pkg = mPm.mPackages.valueAt(i);
698                 final PackageSetting pkgSetting = mPm.mSettings.getPackageLPr(pkg.getPackageName());
699                 if (changingPkg != null
700                         && !hasString(pkg.getUsesLibraries(), changingPkg.getLibraryNames())
701                         && !hasString(pkg.getUsesOptionalLibraries(), changingPkg.getLibraryNames())
702                         && !ArrayUtils.contains(pkg.getUsesStaticLibraries(),
703                         changingPkg.getStaticSharedLibraryName())
704                         && !ArrayUtils.contains(pkg.getUsesSdkLibraries(),
705                         changingPkg.getSdkLibraryName())) {
706                     continue;
707                 }
708                 if (resultList == null) {
709                     resultList = new ArrayList<>();
710                 }
711                 resultList.add(pkg);
712                 // if we're updating a shared library, all of its descendants must be updated
713                 if (changingPkg != null) {
714                     if (descendants == null) {
715                         descendants = new ArraySet<>();
716                     }
717                     if (!descendants.contains(pkg.getPackageName())) {
718                         descendants.add(pkg.getPackageName());
719                         needsUpdating.add(Pair.create(pkg, pkgSetting));
720                     }
721                 }
722                 try {
723                     updateSharedLibraries(pkg, pkgSetting, changingPkg,
724                             changingPkgSetting, availablePackages);
725                 } catch (PackageManagerException e) {
726                     // If a system app update or an app and a required lib missing we
727                     // delete the package and for updated system apps keep the data as
728                     // it is better for the user to reinstall than to be in an limbo
729                     // state. Also libs disappearing under an app should never happen
730                     // - just in case.
731                     if (!pkgSetting.isSystem() || pkgSetting.isUpdatedSystemApp()) {
732                         final int flags = pkgSetting.isUpdatedSystemApp()
733                                 ? PackageManager.DELETE_KEEP_DATA : 0;
734                         try (var installLock = mPm.mInstallLock.acquireLock()) {
735                             mDeletePackageHelper.deletePackageLIF(pkg.getPackageName(), null, true,
736                                     mPm.mUserManager.getUserIds(), flags, new PackageRemovedInfo(),
737                                     true);
738                         }
739                     }
740                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
741                 }
742             }
743         } while (needsUpdating != null && needsUpdating.size() > 0);
744         return resultList;
745     }
746 
747     /**
748      * Add a build-in shared library info by given system configuration.
749      */
750     @GuardedBy("mPm.mLock")
751     void addBuiltInSharedLibraryLPw(@NonNull SystemConfig.SharedLibraryEntry entry) {
752         // check if built-in or dynamic library exists
753         if (getSharedLibraryInfo(entry.name, SharedLibraryInfo.VERSION_UNDEFINED) != null) {
754             return;
755         }
756 
757         SharedLibraryInfo libraryInfo = new SharedLibraryInfo(entry.filename, null, null,
758                 entry.name, SharedLibraryInfo.VERSION_UNDEFINED,
759                 SharedLibraryInfo.TYPE_BUILTIN,
760                 new VersionedPackage(PLATFORM_PACKAGE_NAME, 0L), null, null,
761                 entry.isNative);
762 
763         commitSharedLibraryInfoLPw(libraryInfo);
764     }
765 
766     /**
767      * Add a shared library info to the system. This is invoked when the package is being added or
768      * scanned.
769      */
770     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
771     @GuardedBy("mPm.mLock")
772     void commitSharedLibraryInfoLPw(@NonNull SharedLibraryInfo libraryInfo) {
773         final String name = libraryInfo.getName();
774         WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
775         if (versionedLib == null) {
776             versionedLib = new WatchedLongSparseArray<>();
777             mSharedLibraries.put(name, versionedLib);
778         }
779         final String declaringPackageName = libraryInfo.getDeclaringPackage().getPackageName();
780         if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
781             mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
782         }
783         versionedLib.put(libraryInfo.getLongVersion(), libraryInfo);
784     }
785 
786     /**
787      * Remove a shared library from the system.
788      */
789     boolean removeSharedLibrary(@NonNull String libName, long version) {
790         synchronized (mPm.mLock) {
791             WatchedLongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(libName);
792             if (versionedLib == null) {
793                 return false;
794             }
795             final int libIdx = versionedLib.indexOfKey(version);
796             if (libIdx < 0) {
797                 return false;
798             }
799             SharedLibraryInfo libraryInfo = versionedLib.valueAt(libIdx);
800 
801             final Computer snapshot = mPm.snapshotComputer();
802 
803             // Remove the shared library overlays from its dependent packages.
804             for (int currentUserId : mPm.mUserManager.getUserIds()) {
805                 var usingSharedLibraryPair = snapshot.getPackagesUsingSharedLibrary(libraryInfo, 0,
806                         Process.SYSTEM_UID, currentUserId);
807                 final List<VersionedPackage> dependents = usingSharedLibraryPair.first;
808                 if (dependents == null) {
809                     continue;
810                 }
811                 for (VersionedPackage dependentPackage : dependents) {
812                     final PackageSetting ps = mPm.mSettings.getPackageLPr(
813                             dependentPackage.getPackageName());
814                     if (ps != null) {
815                         ps.setOverlayPathsForLibrary(libraryInfo.getName(), null, currentUserId);
816                     }
817                 }
818             }
819 
820             versionedLib.remove(version);
821             if (versionedLib.size() <= 0) {
822                 mSharedLibraries.remove(libName);
823                 if (libraryInfo.getType() == SharedLibraryInfo.TYPE_STATIC) {
824                     mStaticLibsByDeclaringPackage.remove(libraryInfo.getDeclaringPackage()
825                             .getPackageName());
826                 }
827             }
828             return true;
829         }
830     }
831 
832     /**
833      * Compare the newly scanned package with current system state to see which of its declared
834      * shared libraries should be allowed to be added to the system.
835      */
836     List<SharedLibraryInfo> getAllowedSharedLibInfos(InstallRequest installRequest) {
837         // Let's used the parsed package as scanResult.pkgSetting may be null
838         final ParsedPackage parsedPackage = installRequest.getParsedPackage();
839         if (installRequest.getSdkSharedLibraryInfo() == null
840                 && installRequest.getStaticSharedLibraryInfo() == null
841                 && installRequest.getDynamicSharedLibraryInfos() == null) {
842             return null;
843         }
844 
845         // Any app can add new SDKs and static shared libraries.
846         if (installRequest.getSdkSharedLibraryInfo() != null) {
847             return Collections.singletonList(installRequest.getSdkSharedLibraryInfo());
848         }
849         if (installRequest.getStaticSharedLibraryInfo() != null) {
850             return Collections.singletonList(installRequest.getStaticSharedLibraryInfo());
851         }
852         boolean isSystemApp = installRequest.getScannedPackageSetting() != null
853                 && installRequest.getScannedPackageSetting().isSystem();
854         final boolean hasDynamicLibraries = parsedPackage != null && isSystemApp
855                 && installRequest.getDynamicSharedLibraryInfos() != null;
856         if (!hasDynamicLibraries) {
857             return null;
858         }
859         final boolean isUpdatedSystemApp = installRequest.getScannedPackageSetting() != null
860                 && installRequest.getScannedPackageSetting().isUpdatedSystemApp();
861         // We may not yet have disabled the updated package yet, so be sure to grab the
862         // current setting if that's the case.
863         final PackageSetting updatedSystemPs = isUpdatedSystemApp
864                 ? installRequest.getScanRequestDisabledPackageSetting() == null
865                 ? installRequest.getScanRequestOldPackageSetting()
866                 : installRequest.getScanRequestDisabledPackageSetting()
867                 : null;
868         if (isUpdatedSystemApp && (updatedSystemPs.getPkg() == null
869                 || updatedSystemPs.getPkg().getLibraryNames() == null)) {
870             Slog.w(TAG, "Package " + parsedPackage.getPackageName()
871                     + " declares libraries that are not declared on the system image; skipping");
872             return null;
873         }
874         final ArrayList<SharedLibraryInfo> infos =
875                 new ArrayList<>(installRequest.getDynamicSharedLibraryInfos().size());
876         for (SharedLibraryInfo info : installRequest.getDynamicSharedLibraryInfos()) {
877             final String name = info.getName();
878             if (isUpdatedSystemApp) {
879                 // New library entries can only be added through the
880                 // system image.  This is important to get rid of a lot
881                 // of nasty edge cases: for example if we allowed a non-
882                 // system update of the app to add a library, then uninstalling
883                 // the update would make the library go away, and assumptions
884                 // we made such as through app install filtering would now
885                 // have allowed apps on the device which aren't compatible
886                 // with it.  Better to just have the restriction here, be
887                 // conservative, and create many fewer cases that can negatively
888                 // impact the user experience.
889                 if (!updatedSystemPs.getPkg().getLibraryNames().contains(name)) {
890                     Slog.w(TAG, "Package " + parsedPackage.getPackageName()
891                             + " declares library " + name
892                             + " that is not declared on system image; skipping");
893                     continue;
894                 }
895             }
896             synchronized (mPm.mLock) {
897                 if (getSharedLibraryInfo(name, SharedLibraryInfo.VERSION_UNDEFINED) != null) {
898                     Slog.w(TAG, "Package " + parsedPackage.getPackageName() + " declares library "
899                             + name + " that already exists; skipping");
900                     continue;
901                 }
902             }
903             infos.add(info);
904         }
905         return infos;
906     }
907 
908     /**
909      * Collects shared library infos that are being used by the given package.
910      *
911      * @param pkg The package using shared libraries.
912      * @param availablePackages The available packages which are installed and being installed,
913      * @param newLibraries Shared libraries defined by packages which are being installed.
914      * @return A list of shared library infos
915      */
916     ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(@Nullable AndroidPackage pkg,
917             @NonNull Map<String, AndroidPackage> availablePackages,
918             @Nullable final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> newLibraries)
919             throws PackageManagerException {
920         if (pkg == null) {
921             return null;
922         }
923         final PlatformCompat platformCompat = mInjector.getCompatibility();
924         // The collection used here must maintain the order of addition (so
925         // that libraries are searched in the correct order) and must have no
926         // duplicates.
927         ArrayList<SharedLibraryInfo> usesLibraryInfos = null;
928         if (!pkg.getUsesLibraries().isEmpty()) {
929             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesLibraries(), null, null, null,
930                     pkg.getPackageName(), "shared", true, pkg.getTargetSdkVersion(), null,
931                     availablePackages, newLibraries, null);
932         }
933         if (!pkg.getUsesStaticLibraries().isEmpty()) {
934             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesStaticLibraries(),
935                     pkg.getUsesStaticLibrariesVersions(), pkg.getUsesStaticLibrariesCertDigests(),
936                     null, pkg.getPackageName(), LIBRARY_TYPE_STATIC, true,
937                     pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages, newLibraries,
938                     null);
939         }
940         if (!pkg.getUsesOptionalLibraries().isEmpty()) {
941             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalLibraries(), null, null,
942                     null, pkg.getPackageName(), "shared", false, pkg.getTargetSdkVersion(),
943                     usesLibraryInfos, availablePackages, newLibraries, null);
944         }
945         if (platformCompat.isChangeEnabledInternal(ENFORCE_NATIVE_SHARED_LIBRARY_DEPENDENCIES,
946                 pkg.getPackageName(), pkg.getTargetSdkVersion())) {
947             if (!pkg.getUsesNativeLibraries().isEmpty()) {
948                 usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesNativeLibraries(), null,
949                         null, null, pkg.getPackageName(), "native shared", true,
950                         pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages,
951                         newLibraries, null);
952             }
953             if (!pkg.getUsesOptionalNativeLibraries().isEmpty()) {
954                 usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesOptionalNativeLibraries(),
955                         null, null, null, pkg.getPackageName(), "native shared", false,
956                         pkg.getTargetSdkVersion(), usesLibraryInfos, availablePackages,
957                         newLibraries, null);
958             }
959         }
960         if (!pkg.getUsesSdkLibraries().isEmpty()) {
961             // Allow installation even if sdk-library dependency doesn't exist
962             boolean required = !Flags.sdkLibIndependence();
963             usesLibraryInfos = collectSharedLibraryInfos(pkg.getUsesSdkLibraries(),
964                     pkg.getUsesSdkLibrariesVersionsMajor(), pkg.getUsesSdkLibrariesCertDigests(),
965                     pkg.getUsesSdkLibrariesOptional(),
966                     pkg.getPackageName(), LIBRARY_TYPE_SDK, required, pkg.getTargetSdkVersion(),
967                     usesLibraryInfos, availablePackages, newLibraries, null);
968         }
969         return usesLibraryInfos;
970     }
971 
972     List<SharedLibraryInfo> collectMissingSharedLibraryInfos(PackageLite pkgLite)
973             throws PackageManagerException {
974         ArrayList<SharedLibraryInfo> missingSharedLibrary = new ArrayList<>();
975         synchronized (mPm.mLock) {
976             collectSharedLibraryInfos(pkgLite.getUsesSdkLibraries(),
977                     pkgLite.getUsesSdkLibrariesVersionsMajor(),
978                     pkgLite.getUsesSdkLibrariesCertDigests(),
979                     /*libsOptional=*/ null, pkgLite.getPackageName(), LIBRARY_TYPE_SDK,
980                     /*required=*/ true, pkgLite.getTargetSdk(),
981                     /*outUsedLibraries=*/ null, mPm.mPackages, /*newLibraries=*/ null,
982                     missingSharedLibrary);
983 
984             collectSharedLibraryInfos(pkgLite.getUsesStaticLibraries(),
985                     pkgLite.getUsesStaticLibrariesVersions(),
986                     pkgLite.getUsesStaticLibrariesCertDigests(),
987                     /*libsOptional=*/ null, pkgLite.getPackageName(), LIBRARY_TYPE_STATIC,
988                     /*required=*/ true, pkgLite.getTargetSdk(),
989                     /*outUsedLibraries=*/ null, mPm.mPackages, /*newLibraries=*/ null,
990                     missingSharedLibrary);
991         }
992         return missingSharedLibrary;
993     }
994 
995     private ArrayList<SharedLibraryInfo> collectSharedLibraryInfos(
996             @NonNull List<String> requestedLibraries,
997             @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
998             @Nullable boolean[] libsOptional,
999             @NonNull String packageName, @NonNull String libraryType, boolean required,
1000             int targetSdk, @Nullable ArrayList<SharedLibraryInfo> outUsedLibraries,
1001             @NonNull final Map<String, AndroidPackage> availablePackages,
1002             @Nullable final Map<String, WatchedLongSparseArray<SharedLibraryInfo>> newLibraries,
1003             @Nullable final List<SharedLibraryInfo> outMissingSharedLibraryInfos)
1004             throws PackageManagerException {
1005         final int libCount = requestedLibraries.size();
1006         for (int i = 0; i < libCount; i++) {
1007             final String libName = requestedLibraries.get(i);
1008             final long libVersion = requiredVersions != null ? requiredVersions[i]
1009                     : SharedLibraryInfo.VERSION_UNDEFINED;
1010             final SharedLibraryInfo libraryInfo;
1011             synchronized (mPm.mLock) {
1012                 libraryInfo = SharedLibraryUtils.getSharedLibraryInfo(
1013                         libName, libVersion, mSharedLibraries, newLibraries);
1014             }
1015             if (libraryInfo == null) {
1016                 if (required) {
1017                     boolean isSdkOrStatic = libraryType.equals(LIBRARY_TYPE_SDK)
1018                             || libraryType.equals(LIBRARY_TYPE_STATIC);
1019                     if (isSdkOrStatic && outMissingSharedLibraryInfos != null) {
1020                         // If Dependency Installation is supported, try that instead of failing.
1021                         final List<String> libCertDigests = Arrays.asList(requiredCertDigests[i]);
1022                         SharedLibraryInfo missingLibrary = new SharedLibraryInfo(
1023                                 libName, libVersion, SharedLibraryInfo.TYPE_SDK_PACKAGE,
1024                                 libCertDigests
1025                         );
1026                         outMissingSharedLibraryInfos.add(missingLibrary);
1027                     } else {
1028                         throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1029                                 "Package " + packageName + " requires unavailable " + libraryType
1030                                 + " library " + libName + "; failing!");
1031                     }
1032                 } else {
1033                     // Only allow app be installed if the app specifies the sdk-library
1034                     // dependency is optional
1035                     boolean isOptional = libsOptional != null && libsOptional[i];
1036                     if (LIBRARY_TYPE_SDK.equals(libraryType) && !isOptional) {
1037                         throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1038                                 "Package " + packageName + " requires unavailable " + libraryType
1039                                 + " library " + libName + "; failing!");
1040                     } else if (DEBUG_SHARED_LIBRARIES) {
1041                         Slog.i(TAG, "Package " + packageName + " desires unavailable " + libraryType
1042                                 + " library " + libName + "; ignoring!");
1043                     }
1044                 }
1045             } else {
1046                 if (requiredVersions != null && requiredCertDigests != null) {
1047                     if (libraryInfo.getLongVersion() != requiredVersions[i]) {
1048                         throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1049                                 "Package " + packageName + " requires unavailable " + libraryType
1050                                         + " library " + libName + " version "
1051                                         + libraryInfo.getLongVersion() + "; failing!");
1052                     }
1053                     AndroidPackage pkg = availablePackages.get(libraryInfo.getPackageName());
1054                     SigningDetails libPkg = pkg == null ? null : pkg.getSigningDetails();
1055                     if (libPkg == null) {
1056                         throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1057                                 "Package " + packageName + " requires unavailable " + libraryType
1058                                         + " library; failing!");
1059                     }
1060                     final String[] expectedCertDigests = requiredCertDigests[i];
1061                     if (expectedCertDigests.length > 1) {
1062                         // For apps targeting O MR1 we require explicit enumeration of all certs.
1063                         final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
1064                                 ? PackageUtils.computeSignaturesSha256Digests(
1065                                 libPkg.getSignatures())
1066                                 : PackageUtils.computeSignaturesSha256Digests(
1067                                         new Signature[]{libPkg.getSignatures()[0]});
1068 
1069                         // Take a shortcut if sizes don't match. Note that if an app doesn't
1070                         // target O we don't parse the "additional-certificate" tags similarly
1071                         // how we only consider all certs only for apps targeting O (see above).
1072                         // Therefore, the size check is safe to make.
1073                         if (expectedCertDigests.length != libCertDigests.length) {
1074                             throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1075                                     "Package " + packageName + " requires differently signed "
1076                                             + libraryType + " library; failing!");
1077                         }
1078 
1079                         // Use a predictable order as signature order may vary
1080                         Arrays.sort(libCertDigests);
1081                         Arrays.sort(expectedCertDigests);
1082 
1083                         final int certCount = libCertDigests.length;
1084                         for (int j = 0; j < certCount; j++) {
1085                             if (!libCertDigests[j].equalsIgnoreCase(expectedCertDigests[j])) {
1086                                 throw new PackageManagerException(
1087                                         INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1088                                         "Package " + packageName + " requires differently signed "
1089                                                 + libraryType + " library; failing!");
1090                             }
1091                         }
1092                     } else {
1093                         // lib signing cert could have rotated beyond the one expected, check to see
1094                         // if the new one has been blessed by the old
1095                         final byte[] digestBytes;
1096                         try {
1097                             digestBytes = HexEncoding.decode(
1098                                     expectedCertDigests[0], false /* allowSingleChar */);
1099                         } catch (IllegalArgumentException e) {
1100                             throw new PackageManagerException(
1101                                     INSTALL_FAILED_SHARED_LIBRARY_BAD_CERTIFICATE_DIGEST,
1102                                     "Package " + packageName + " declares bad certificate digest "
1103                                             + "for " + libraryType + " library " + libName
1104                                             + "; failing!");
1105                         }
1106                         if (!libPkg.hasSha256Certificate(digestBytes)) {
1107                             throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
1108                                     "Package " + packageName + " requires differently signed "
1109                                             + libraryType + " library; failing!");
1110                         }
1111                     }
1112                 }
1113                 if (outUsedLibraries == null) {
1114                     outUsedLibraries = new ArrayList<>();
1115                 }
1116                 outUsedLibraries.add(libraryInfo);
1117             }
1118         }
1119         return outUsedLibraries;
1120     }
1121 
1122     /**
1123      * Dump all shared libraries.
1124      */
1125     @GuardedBy("mPm.mLock")
1126     @Override
1127     public void dump(@NonNull PrintWriter pw, @NonNull DumpState dumpState) {
1128         final boolean checkin = dumpState.isCheckIn();
1129         boolean printedHeader = false;
1130         final int numSharedLibraries = mSharedLibraries.size();
1131         for (int index = 0; index < numSharedLibraries; index++) {
1132             final String libName = mSharedLibraries.keyAt(index);
1133             final WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
1134                     mSharedLibraries.get(libName);
1135             if (versionedLib == null) {
1136                 continue;
1137             }
1138             final int versionCount = versionedLib.size();
1139             for (int i = 0; i < versionCount; i++) {
1140                 SharedLibraryInfo libraryInfo = versionedLib.valueAt(i);
1141                 if (!checkin) {
1142                     if (!printedHeader) {
1143                         if (dumpState.onTitlePrinted()) {
1144                             pw.println();
1145                         }
1146                         pw.println("Libraries:");
1147                         printedHeader = true;
1148                     }
1149                     pw.print("  ");
1150                 } else {
1151                     pw.print("lib,");
1152                 }
1153                 pw.print(libraryInfo.getName());
1154                 if (libraryInfo.isStatic()) {
1155                     pw.print(" version=" + libraryInfo.getLongVersion());
1156                 }
1157                 if (!checkin) {
1158                     pw.print(" -> ");
1159                 }
1160                 if (libraryInfo.getPath() != null) {
1161                     if (libraryInfo.isNative()) {
1162                         pw.print(" (so) ");
1163                     } else {
1164                         pw.print(" (jar) ");
1165                     }
1166                     pw.print(libraryInfo.getPath());
1167                 } else {
1168                     pw.print(" (apk) ");
1169                     pw.print(libraryInfo.getPackageName());
1170                 }
1171                 pw.println();
1172             }
1173         }
1174     }
1175 
1176     /**
1177      * Dump all shared libraries to given proto output stream.
1178      */
1179     @GuardedBy("mPm.mLock")
1180     @Override
1181     public void dumpProto(@NonNull ProtoOutputStream proto) {
1182         final int count = mSharedLibraries.size();
1183         for (int i = 0; i < count; i++) {
1184             final String libName = mSharedLibraries.keyAt(i);
1185             WatchedLongSparseArray<SharedLibraryInfo> versionedLib =
1186                     mSharedLibraries.get(libName);
1187             if (versionedLib == null) {
1188                 continue;
1189             }
1190             final int versionCount = versionedLib.size();
1191             for (int j = 0; j < versionCount; j++) {
1192                 final SharedLibraryInfo libraryInfo = versionedLib.valueAt(j);
1193                 final long sharedLibraryToken =
1194                         proto.start(PackageServiceDumpProto.SHARED_LIBRARIES);
1195                 proto.write(PackageServiceDumpProto.SharedLibraryProto.NAME, libraryInfo.getName());
1196                 final boolean isJar = (libraryInfo.getPath() != null);
1197                 proto.write(PackageServiceDumpProto.SharedLibraryProto.IS_JAR, isJar);
1198                 if (isJar) {
1199                     proto.write(PackageServiceDumpProto.SharedLibraryProto.PATH,
1200                             libraryInfo.getPath());
1201                 } else {
1202                     proto.write(PackageServiceDumpProto.SharedLibraryProto.APK,
1203                             libraryInfo.getPackageName());
1204                 }
1205                 proto.end(sharedLibraryToken);
1206             }
1207         }
1208     }
1209 }
1210