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