1 /* 2 * Copyright (C) 2019 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.os.Trace.TRACE_TAG_PACKAGE_MANAGER; 20 import static android.os.UserHandle.USER_ALL; 21 import static android.os.UserHandle.USER_NULL; 22 import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; 23 24 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; 25 import static com.android.server.pm.AppsFilterUtils.canQueryAsInstaller; 26 import static com.android.server.pm.AppsFilterUtils.canQueryViaComponents; 27 import static com.android.server.pm.AppsFilterUtils.canQueryViaPackage; 28 import static com.android.server.pm.AppsFilterUtils.canQueryViaUsesLibrary; 29 import static com.android.server.pm.AppsFilterUtils.requestsQueryAllPackages; 30 31 import android.annotation.NonNull; 32 import android.annotation.Nullable; 33 import android.annotation.UserIdInt; 34 import android.content.pm.PackageManager; 35 import android.content.pm.PackageManagerInternal; 36 import android.content.pm.SigningDetails; 37 import android.content.pm.UserInfo; 38 import android.os.Handler; 39 import android.os.Trace; 40 import android.os.UserHandle; 41 import android.provider.DeviceConfig; 42 import android.util.ArrayMap; 43 import android.util.ArraySet; 44 import android.util.Slog; 45 import android.util.SparseBooleanArray; 46 47 import com.android.internal.R; 48 import com.android.internal.annotations.GuardedBy; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.util.ArrayUtils; 51 import com.android.server.FgThread; 52 import com.android.server.compat.CompatChange; 53 import com.android.server.om.OverlayReferenceMapper; 54 import com.android.server.pm.parsing.pkg.AndroidPackage; 55 import com.android.server.pm.parsing.pkg.AndroidPackageUtils; 56 import com.android.server.pm.pkg.PackageStateInternal; 57 import com.android.server.pm.pkg.component.ParsedInstrumentation; 58 import com.android.server.pm.snapshot.PackageDataSnapshot; 59 import com.android.server.utils.Snappable; 60 import com.android.server.utils.SnapshotCache; 61 import com.android.server.utils.Watchable; 62 import com.android.server.utils.WatchableImpl; 63 import com.android.server.utils.WatchedArrayList; 64 import com.android.server.utils.WatchedArraySet; 65 import com.android.server.utils.WatchedSparseBooleanMatrix; 66 import com.android.server.utils.WatchedSparseSetArray; 67 import com.android.server.utils.Watcher; 68 69 import java.util.ArrayList; 70 import java.util.Arrays; 71 import java.util.Collection; 72 import java.util.List; 73 import java.util.Objects; 74 75 /** 76 * Implementation of the methods that update the internal structures of AppsFilter. Because of the 77 * mutations, all the read accesses to those internal structures need to be locked, thus extending 78 * {@link AppsFilterLocked}. 79 */ 80 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 81 public final class AppsFilterImpl extends AppsFilterLocked implements Watchable, Snappable { 82 /** 83 * A cached snapshot. 84 */ 85 @NonNull 86 private final SnapshotCache<AppsFilterSnapshot> mSnapshot; 87 88 /** 89 * Watchable machinery 90 */ 91 private final WatchableImpl mWatchable = new WatchableImpl(); 92 93 /** 94 * Ensures an observer is in the list, exactly once. The observer cannot be null. The 95 * function quietly returns if the observer is already in the list. 96 * 97 * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes. 98 */ 99 @Override registerObserver(@onNull Watcher observer)100 public void registerObserver(@NonNull Watcher observer) { 101 mWatchable.registerObserver(observer); 102 } 103 104 /** 105 * Ensures an observer is not in the list. The observer must not be null. The function 106 * quietly returns if the objserver is not in the list. 107 * 108 * @param observer The {@link Watcher} that should not be in the notification list. 109 */ 110 @Override unregisterObserver(@onNull Watcher observer)111 public void unregisterObserver(@NonNull Watcher observer) { 112 mWatchable.unregisterObserver(observer); 113 } 114 115 /** 116 * Return true if the {@link Watcher) is a registered observer. 117 * 118 * @param observer A {@link Watcher} that might be registered 119 * @return true if the observer is registered with this {@link Watchable}. 120 */ 121 @Override isRegisteredObserver(@onNull Watcher observer)122 public boolean isRegisteredObserver(@NonNull Watcher observer) { 123 return mWatchable.isRegisteredObserver(observer); 124 } 125 126 /** 127 * Invokes {@link Watcher#onChange} on each registered observer. The method can be called 128 * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this 129 * is generally the first (deepest) {@link Watchable} to detect a change. 130 * 131 * @param what The {@link Watchable} that generated the event. 132 */ 133 @Override dispatchChange(@ullable Watchable what)134 public void dispatchChange(@Nullable Watchable what) { 135 mWatchable.dispatchChange(what); 136 } 137 138 /** 139 * Report a change to observers. 140 */ onChanged()141 private void onChanged() { 142 dispatchChange(this); 143 } 144 invalidateCache(String reason)145 private void invalidateCache(String reason) { 146 if (mCacheValid.compareAndSet(CACHE_VALID, CACHE_INVALID)) { 147 Slog.i(TAG, "Invalidating cache: " + reason); 148 } 149 } 150 151 @VisibleForTesting(visibility = PRIVATE) AppsFilterImpl(FeatureConfig featureConfig, String[] forceQueryableList, boolean systemAppsQueryable, @Nullable OverlayReferenceMapper.Provider overlayProvider, Handler backgroundHandler)152 AppsFilterImpl(FeatureConfig featureConfig, 153 String[] forceQueryableList, 154 boolean systemAppsQueryable, 155 @Nullable OverlayReferenceMapper.Provider overlayProvider, 156 Handler backgroundHandler) { 157 mFeatureConfig = featureConfig; 158 mForceQueryableByDevicePackageNames = forceQueryableList; 159 mSystemAppsQueryable = systemAppsQueryable; 160 mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, 161 overlayProvider); 162 mBackgroundHandler = backgroundHandler; 163 mShouldFilterCache = new WatchedSparseBooleanMatrix(); 164 mShouldFilterCacheSnapshot = new SnapshotCache.Auto<>( 165 mShouldFilterCache, mShouldFilterCache, "AppsFilter.mShouldFilterCache"); 166 mImplicitlyQueryable = new WatchedSparseSetArray<>(); 167 mImplicitQueryableSnapshot = new SnapshotCache.Auto<>( 168 mImplicitlyQueryable, mImplicitlyQueryable, "AppsFilter.mImplicitlyQueryable"); 169 mRetainedImplicitlyQueryable = new WatchedSparseSetArray<>(); 170 mRetainedImplicitlyQueryableSnapshot = new SnapshotCache.Auto<>( 171 mRetainedImplicitlyQueryable, mRetainedImplicitlyQueryable, 172 "AppsFilter.mRetainedImplicitlyQueryable"); 173 mQueriesViaPackage = new WatchedSparseSetArray<>(); 174 mQueriesViaPackageSnapshot = new SnapshotCache.Auto<>( 175 mQueriesViaPackage, mQueriesViaPackage, "AppsFilter.mQueriesViaPackage"); 176 mQueriesViaComponent = new WatchedSparseSetArray<>(); 177 mQueriesViaComponentSnapshot = new SnapshotCache.Auto<>( 178 mQueriesViaComponent, mQueriesViaComponent, "AppsFilter.mQueriesViaComponent"); 179 mQueryableViaUsesLibrary = new WatchedSparseSetArray<>(); 180 mQueryableViaUsesLibrarySnapshot = new SnapshotCache.Auto<>( 181 mQueryableViaUsesLibrary, mQueryableViaUsesLibrary, 182 "AppsFilter.mQueryableViaUsesLibrary"); 183 mForceQueryable = new WatchedArraySet<>(); 184 mForceQueryableSnapshot = new SnapshotCache.Auto<>( 185 mForceQueryable, mForceQueryable, "AppsFilter.mForceQueryable"); 186 mProtectedBroadcasts = new WatchedArrayList<>(); 187 mProtectedBroadcastsSnapshot = new SnapshotCache.Auto<>( 188 mProtectedBroadcasts, mProtectedBroadcasts, "AppsFilter.mProtectedBroadcasts"); 189 190 mSnapshot = new SnapshotCache<AppsFilterSnapshot>(this, this) { 191 @Override 192 public AppsFilterSnapshot createSnapshot() { 193 return new AppsFilterSnapshotImpl(AppsFilterImpl.this); 194 } 195 }; 196 } 197 198 /** 199 * Return a snapshot. If the cached snapshot is null, build a new one. The logic in 200 * the function ensures that this function returns a valid snapshot even if a race 201 * condition causes the cached snapshot to be cleared asynchronously to this method. 202 */ snapshot()203 public AppsFilterSnapshot snapshot() { 204 return mSnapshot.snapshot(); 205 } 206 207 private static class FeatureConfigImpl implements FeatureConfig, 208 CompatChange.ChangeListener { 209 private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled"; 210 private final PackageManagerServiceInjector mInjector; 211 private final PackageManagerInternal mPmInternal; 212 private volatile boolean mFeatureEnabled = 213 PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT; 214 private final ArraySet<String> mDisabledPackages = new ArraySet<>(); 215 216 @Nullable 217 private SparseBooleanArray mLoggingEnabled = null; 218 private AppsFilterImpl mAppsFilter; 219 FeatureConfigImpl( PackageManagerInternal pmInternal, PackageManagerServiceInjector injector)220 private FeatureConfigImpl( 221 PackageManagerInternal pmInternal, PackageManagerServiceInjector injector) { 222 mPmInternal = pmInternal; 223 mInjector = injector; 224 } 225 FeatureConfigImpl(FeatureConfigImpl orig)226 FeatureConfigImpl(FeatureConfigImpl orig) { 227 mInjector = null; 228 mPmInternal = null; 229 mFeatureEnabled = orig.mFeatureEnabled; 230 mDisabledPackages.addAll(orig.mDisabledPackages); 231 mLoggingEnabled = orig.mLoggingEnabled; 232 } 233 setAppsFilter(AppsFilterImpl filter)234 public void setAppsFilter(AppsFilterImpl filter) { 235 mAppsFilter = filter; 236 } 237 238 @Override onSystemReady()239 public void onSystemReady() { 240 mFeatureEnabled = DeviceConfig.getBoolean( 241 NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, 242 PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT); 243 DeviceConfig.addOnPropertiesChangedListener( 244 NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(), 245 properties -> { 246 if (properties.getKeyset().contains(FILTERING_ENABLED_NAME)) { 247 synchronized (FeatureConfigImpl.this) { 248 mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, 249 PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT); 250 } 251 } 252 }); 253 mInjector.getCompatibility().registerListener( 254 PackageManager.FILTER_APPLICATION_QUERY, this); 255 } 256 257 @Override isGloballyEnabled()258 public boolean isGloballyEnabled() { 259 if (DEBUG_TRACING) { 260 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "isGloballyEnabled"); 261 } 262 try { 263 return mFeatureEnabled; 264 } finally { 265 if (DEBUG_TRACING) { 266 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 267 } 268 } 269 } 270 271 @Override packageIsEnabled(AndroidPackage pkg)272 public boolean packageIsEnabled(AndroidPackage pkg) { 273 if (DEBUG_TRACING) { 274 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled"); 275 } 276 try { 277 return !mDisabledPackages.contains(pkg.getPackageName()); 278 } finally { 279 if (DEBUG_TRACING) { 280 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 281 } 282 } 283 } 284 285 @Override isLoggingEnabled(int uid)286 public boolean isLoggingEnabled(int uid) { 287 return mLoggingEnabled != null && mLoggingEnabled.indexOfKey(uid) >= 0; 288 } 289 290 @Override enableLogging(int appId, boolean enable)291 public void enableLogging(int appId, boolean enable) { 292 if (enable) { 293 if (mLoggingEnabled == null) { 294 mLoggingEnabled = new SparseBooleanArray(); 295 } 296 mLoggingEnabled.put(appId, true); 297 } else { 298 if (mLoggingEnabled != null) { 299 final int index = mLoggingEnabled.indexOfKey(appId); 300 if (index >= 0) { 301 mLoggingEnabled.removeAt(index); 302 if (mLoggingEnabled.size() == 0) { 303 mLoggingEnabled = null; 304 } 305 } 306 } 307 } 308 } 309 310 @Override onCompatChange(String packageName)311 public void onCompatChange(String packageName) { 312 PackageDataSnapshot snapshot = mPmInternal.snapshot(); 313 AndroidPackage pkg = snapshot.getPackage(packageName); 314 if (pkg == null) { 315 return; 316 } 317 updateEnabledState(pkg); 318 mAppsFilter.updateShouldFilterCacheForPackage(snapshot, packageName); 319 } 320 updateEnabledState(@onNull AndroidPackage pkg)321 private void updateEnabledState(@NonNull AndroidPackage pkg) { 322 // TODO(b/135203078): Do not use toAppInfo 323 // TODO(b/167551701): Make changeId non-logging 324 final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternalNoLogging( 325 PackageManager.FILTER_APPLICATION_QUERY, 326 AndroidPackageUtils.generateAppInfoWithoutState(pkg)); 327 if (enabled) { 328 mDisabledPackages.remove(pkg.getPackageName()); 329 } else { 330 mDisabledPackages.add(pkg.getPackageName()); 331 } 332 if (mAppsFilter != null) { 333 mAppsFilter.onChanged(); 334 } 335 } 336 337 @Override updatePackageState(PackageStateInternal setting, boolean removed)338 public void updatePackageState(PackageStateInternal setting, boolean removed) { 339 final boolean enableLogging = setting.getPkg() != null 340 && !removed && (setting.getPkg().isTestOnly() 341 || setting.getPkg().isDebuggable()); 342 enableLogging(setting.getAppId(), enableLogging); 343 if (removed) { 344 mDisabledPackages.remove(setting.getPackageName()); 345 if (mAppsFilter != null) { 346 mAppsFilter.onChanged(); 347 } 348 } else if (setting.getPkg() != null) { 349 updateEnabledState(setting.getPkg()); 350 } 351 } 352 353 @Override snapshot()354 public FeatureConfig snapshot() { 355 return new FeatureConfigImpl(this); 356 } 357 } 358 359 /** Builder method for an AppsFilter */ create(@onNull PackageManagerServiceInjector injector, @NonNull PackageManagerInternal pmInt)360 public static AppsFilterImpl create(@NonNull PackageManagerServiceInjector injector, 361 @NonNull PackageManagerInternal pmInt) { 362 final boolean forceSystemAppsQueryable = 363 injector.getContext().getResources() 364 .getBoolean(R.bool.config_forceSystemPackagesQueryable); 365 final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pmInt, injector); 366 final String[] forcedQueryablePackageNames; 367 if (forceSystemAppsQueryable) { 368 // all system apps already queryable, no need to read and parse individual exceptions 369 forcedQueryablePackageNames = new String[]{}; 370 } else { 371 forcedQueryablePackageNames = 372 injector.getContext().getResources() 373 .getStringArray(R.array.config_forceQueryablePackages); 374 for (int i = 0; i < forcedQueryablePackageNames.length; i++) { 375 forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern(); 376 } 377 } 378 AppsFilterImpl appsFilter = new AppsFilterImpl(featureConfig, 379 forcedQueryablePackageNames, forceSystemAppsQueryable, null, 380 injector.getBackgroundHandler()); 381 featureConfig.setAppsFilter(appsFilter); 382 return appsFilter; 383 } 384 getFeatureConfig()385 public FeatureConfig getFeatureConfig() { 386 return mFeatureConfig; 387 } 388 389 /** 390 * Grants access based on an interaction between a calling and target package, granting 391 * visibility of the caller from the target. 392 * 393 * @param recipientUid the uid gaining visibility of the {@code visibleUid}. 394 * @param visibleUid the uid becoming visible to the {@recipientUid} 395 * @param retainOnUpdate if the implicit access retained across package updates. 396 * @return {@code true} if implicit access was not already granted. 397 */ grantImplicitAccess(int recipientUid, int visibleUid, boolean retainOnUpdate)398 public boolean grantImplicitAccess(int recipientUid, int visibleUid, boolean retainOnUpdate) { 399 if (recipientUid == visibleUid) { 400 return false; 401 } 402 final boolean changed; 403 synchronized (mImplicitlyQueryableLock) { 404 changed = retainOnUpdate 405 ? mRetainedImplicitlyQueryable.add(recipientUid, visibleUid) 406 : mImplicitlyQueryable.add(recipientUid, visibleUid); 407 } 408 if (changed && DEBUG_LOGGING) { 409 Slog.i(TAG, (retainOnUpdate ? "retained " : "") + "implicit access granted: " 410 + recipientUid + " -> " + visibleUid); 411 } 412 413 if (mCacheReady) { 414 synchronized (mCacheLock) { 415 // Update the cache in a one-off manner since we've got all the information we need. 416 mShouldFilterCache.put(recipientUid, visibleUid, false); 417 } 418 } else if (changed) { 419 invalidateCache("grantImplicitAccess: " + recipientUid + " -> " + visibleUid); 420 } 421 if (changed) { 422 onChanged(); 423 } 424 return changed; 425 } 426 onSystemReady(PackageManagerInternal pmInternal)427 public void onSystemReady(PackageManagerInternal pmInternal) { 428 mOverlayReferenceMapper.rebuildIfDeferred(); 429 mFeatureConfig.onSystemReady(); 430 431 updateEntireShouldFilterCacheAsync(pmInternal); 432 } 433 434 /** 435 * Adds a package that should be considered when filtering visibility between apps. 436 * 437 * @param newPkgSetting the new setting being added 438 * @param isReplace if the package is being replaced and may need extra cleanup. 439 */ addPackage(PackageDataSnapshot snapshot, PackageStateInternal newPkgSetting, boolean isReplace)440 public void addPackage(PackageDataSnapshot snapshot, PackageStateInternal newPkgSetting, 441 boolean isReplace) { 442 if (DEBUG_TRACING) { 443 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); 444 } 445 try { 446 if (isReplace) { 447 // let's first remove any prior rules for this package 448 removePackage(snapshot, newPkgSetting, true /*isReplace*/); 449 } 450 final ArrayMap<String, ? extends PackageStateInternal> settings = 451 snapshot.getPackageStates(); 452 final UserInfo[] users = snapshot.getUserInfos(); 453 final ArraySet<String> additionalChangedPackages = 454 addPackageInternal(newPkgSetting, settings); 455 if (mCacheReady) { 456 synchronized (mCacheLock) { 457 updateShouldFilterCacheForPackage(snapshot, null, newPkgSetting, 458 settings, users, USER_ALL, settings.size()); 459 if (additionalChangedPackages != null) { 460 for (int index = 0; index < additionalChangedPackages.size(); index++) { 461 String changedPackage = additionalChangedPackages.valueAt(index); 462 PackageStateInternal changedPkgSetting = settings.get(changedPackage); 463 if (changedPkgSetting == null) { 464 // It's possible for the overlay mapper to know that an actor 465 // package changed via an explicit reference, even if the actor 466 // isn't installed, so skip if that's the case. 467 continue; 468 } 469 updateShouldFilterCacheForPackage(snapshot, null, changedPkgSetting, 470 settings, users, USER_ALL, settings.size()); 471 } 472 } 473 } 474 } else { 475 invalidateCache("addPackage: " + newPkgSetting.getPackageName()); 476 } 477 } finally { 478 onChanged(); 479 if (DEBUG_TRACING) { 480 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 481 } 482 } 483 } 484 485 /** 486 * @return Additional packages that may have had their viewing visibility changed and may need 487 * to be updated in the cache. Returns null if there are no additional packages. 488 */ 489 @Nullable addPackageInternal(PackageStateInternal newPkgSetting, ArrayMap<String, ? extends PackageStateInternal> existingSettings)490 private ArraySet<String> addPackageInternal(PackageStateInternal newPkgSetting, 491 ArrayMap<String, ? extends PackageStateInternal> existingSettings) { 492 if (Objects.equals("android", newPkgSetting.getPackageName())) { 493 // let's set aside the framework signatures 494 mSystemSigningDetails = newPkgSetting.getSigningDetails(); 495 // and since we add overlays before we add the framework, let's revisit already added 496 // packages for signature matches 497 for (PackageStateInternal setting : existingSettings.values()) { 498 if (isSystemSigned(mSystemSigningDetails, setting)) { 499 synchronized (mForceQueryableLock) { 500 mForceQueryable.add(setting.getAppId()); 501 } 502 } 503 } 504 } 505 506 final AndroidPackage newPkg = newPkgSetting.getPkg(); 507 if (newPkg == null) { 508 return null; 509 } 510 511 final boolean protectedBroadcastsChanged; 512 synchronized (mProtectedBroadcastsLock) { 513 protectedBroadcastsChanged = 514 mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts()); 515 } 516 if (protectedBroadcastsChanged) { 517 mQueriesViaComponentRequireRecompute.set(true); 518 } 519 520 final boolean newIsForceQueryable; 521 synchronized (mForceQueryableLock) { 522 newIsForceQueryable = mForceQueryable.contains(newPkgSetting.getAppId()) 523 /* shared user that is already force queryable */ 524 || newPkgSetting.isForceQueryableOverride() /* adb override */ 525 || (newPkgSetting.isSystem() && (mSystemAppsQueryable 526 || newPkg.isForceQueryable() 527 || ArrayUtils.contains(mForceQueryableByDevicePackageNames, 528 newPkg.getPackageName()))); 529 if (newIsForceQueryable 530 || (mSystemSigningDetails != null 531 && isSystemSigned(mSystemSigningDetails, newPkgSetting))) { 532 mForceQueryable.add(newPkgSetting.getAppId()); 533 } 534 } 535 536 for (int i = existingSettings.size() - 1; i >= 0; i--) { 537 final PackageStateInternal existingSetting = existingSettings.valueAt(i); 538 if (existingSetting.getAppId() == newPkgSetting.getAppId() 539 || existingSetting.getPkg() 540 == null) { 541 continue; 542 } 543 final AndroidPackage existingPkg = existingSetting.getPkg(); 544 // let's evaluate the ability of already added packages to see this new package 545 if (!newIsForceQueryable) { 546 if (!mQueriesViaComponentRequireRecompute.get() 547 && canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { 548 synchronized (mQueriesViaComponentLock) { 549 mQueriesViaComponent.add(existingSetting.getAppId(), 550 newPkgSetting.getAppId()); 551 } 552 } 553 if (canQueryViaPackage(existingPkg, newPkg) 554 || canQueryAsInstaller(existingSetting, newPkg)) { 555 synchronized (mQueriesViaPackageLock) { 556 mQueriesViaPackage.add(existingSetting.getAppId(), 557 newPkgSetting.getAppId()); 558 } 559 } 560 if (canQueryViaUsesLibrary(existingPkg, newPkg)) { 561 synchronized (mQueryableViaUsesLibraryLock) { 562 mQueryableViaUsesLibrary.add(existingSetting.getAppId(), 563 newPkgSetting.getAppId()); 564 } 565 } 566 } 567 final boolean existingIsForceQueryable; 568 synchronized (mForceQueryableLock) { 569 existingIsForceQueryable = mForceQueryable.contains(existingSetting.getAppId()); 570 } 571 // now we'll evaluate our new package's ability to see existing packages 572 if (!existingIsForceQueryable) { 573 if (!mQueriesViaComponentRequireRecompute.get() 574 && canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { 575 synchronized (mQueriesViaComponentLock) { 576 mQueriesViaComponent.add(newPkgSetting.getAppId(), 577 existingSetting.getAppId()); 578 } 579 } 580 if (canQueryViaPackage(newPkg, existingPkg) 581 || canQueryAsInstaller(newPkgSetting, existingPkg)) { 582 synchronized (mQueriesViaPackageLock) { 583 mQueriesViaPackage.add(newPkgSetting.getAppId(), 584 existingSetting.getAppId()); 585 } 586 } 587 if (canQueryViaUsesLibrary(newPkg, existingPkg)) { 588 synchronized (mQueryableViaUsesLibraryLock) { 589 mQueryableViaUsesLibrary.add(newPkgSetting.getAppId(), 590 existingSetting.getAppId()); 591 } 592 } 593 } 594 // if either package instruments the other, mark both as visible to one another 595 if (newPkgSetting.getPkg() != null && existingSetting.getPkg() != null 596 && (pkgInstruments(newPkgSetting.getPkg(), existingSetting.getPkg()) 597 || pkgInstruments(existingSetting.getPkg(), newPkgSetting.getPkg()))) { 598 synchronized (mQueriesViaPackageLock) { 599 mQueriesViaPackage.add(newPkgSetting.getAppId(), existingSetting.getAppId()); 600 mQueriesViaPackage.add(existingSetting.getAppId(), newPkgSetting.getAppId()); 601 } 602 } 603 } 604 605 int existingSize = existingSettings.size(); 606 ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); 607 for (int index = 0; index < existingSize; index++) { 608 PackageStateInternal pkgSetting = existingSettings.valueAt(index); 609 if (pkgSetting.getPkg() != null) { 610 existingPkgs.put(pkgSetting.getPackageName(), pkgSetting.getPkg()); 611 } 612 } 613 614 ArraySet<String> changedPackages = 615 mOverlayReferenceMapper.addPkg(newPkgSetting.getPkg(), existingPkgs); 616 617 mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); 618 619 return changedPackages; 620 } 621 removeAppIdFromVisibilityCache(int appId)622 private void removeAppIdFromVisibilityCache(int appId) { 623 synchronized (mCacheLock) { 624 for (int i = 0; i < mShouldFilterCache.size(); i++) { 625 if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) { 626 mShouldFilterCache.removeAt(i); 627 // The key was deleted so the list of keys has shifted left. That means i 628 // is now pointing at the next key to be examined. The decrement here and 629 // the loop increment together mean that i will be unchanged in the need 630 // iteration and will correctly point to the next key to be examined. 631 i--; 632 } 633 } 634 } 635 } 636 updateEntireShouldFilterCache(PackageDataSnapshot snapshot, int subjectUserId)637 private void updateEntireShouldFilterCache(PackageDataSnapshot snapshot, int subjectUserId) { 638 final ArrayMap<String, ? extends PackageStateInternal> settings = 639 snapshot.getPackageStates(); 640 final UserInfo[] users = snapshot.getUserInfos(); 641 int userId = USER_NULL; 642 for (int u = 0; u < users.length; u++) { 643 if (subjectUserId == users[u].id) { 644 userId = subjectUserId; 645 break; 646 } 647 } 648 if (userId == USER_NULL) { 649 Slog.e(TAG, "We encountered a new user that isn't a member of known users, " 650 + "updating the whole cache"); 651 userId = USER_ALL; 652 } 653 updateEntireShouldFilterCacheInner(snapshot, settings, users, userId); 654 655 onChanged(); 656 } 657 updateEntireShouldFilterCacheInner(PackageDataSnapshot snapshot, ArrayMap<String, ? extends PackageStateInternal> settings, UserInfo[] users, int subjectUserId)658 private void updateEntireShouldFilterCacheInner(PackageDataSnapshot snapshot, 659 ArrayMap<String, ? extends PackageStateInternal> settings, 660 UserInfo[] users, 661 int subjectUserId) { 662 synchronized (mCacheLock) { 663 if (subjectUserId == USER_ALL) { 664 mShouldFilterCache.clear(); 665 } 666 mShouldFilterCache.setCapacity(users.length * settings.size()); 667 for (int i = settings.size() - 1; i >= 0; i--) { 668 updateShouldFilterCacheForPackage(snapshot, 669 null /*skipPackage*/, settings.valueAt(i), settings, users, 670 subjectUserId, i); 671 } 672 } 673 } 674 updateEntireShouldFilterCacheAsync(PackageManagerInternal pmInternal)675 private void updateEntireShouldFilterCacheAsync(PackageManagerInternal pmInternal) { 676 updateEntireShouldFilterCacheAsync(pmInternal, CACHE_REBUILD_DELAY_MIN_MS); 677 } 678 updateEntireShouldFilterCacheAsync(PackageManagerInternal pmInternal, long delayMs)679 private void updateEntireShouldFilterCacheAsync(PackageManagerInternal pmInternal, 680 long delayMs) { 681 mBackgroundHandler.postDelayed(() -> { 682 if (!mCacheValid.compareAndSet(CACHE_INVALID, CACHE_VALID)) { 683 // Cache is already valid. 684 return; 685 } 686 687 final ArrayMap<String, AndroidPackage> packagesCache = new ArrayMap<>(); 688 final UserInfo[][] usersRef = new UserInfo[1][]; 689 final PackageDataSnapshot snapshot = pmInternal.snapshot(); 690 final ArrayMap<String, ? extends PackageStateInternal> settings = 691 snapshot.getPackageStates(); 692 final UserInfo[] users = snapshot.getUserInfos(); 693 694 packagesCache.ensureCapacity(settings.size()); 695 usersRef[0] = users; 696 // store away the references to the immutable packages, since settings are retained 697 // during updates. 698 for (int i = 0, max = settings.size(); i < max; i++) { 699 final AndroidPackage pkg = settings.valueAt(i).getPkg(); 700 packagesCache.put(settings.keyAt(i), pkg); 701 } 702 703 updateEntireShouldFilterCacheInner(snapshot, settings, usersRef[0], USER_ALL); 704 onChanged(); 705 706 if (!mCacheValid.compareAndSet(CACHE_VALID, CACHE_VALID)) { 707 Slog.i(TAG, "Cache invalidated while building, retrying."); 708 updateEntireShouldFilterCacheAsync(pmInternal, 709 Math.min(delayMs * 2, CACHE_REBUILD_DELAY_MAX_MS)); 710 return; 711 } 712 713 mCacheReady = true; 714 }, delayMs); 715 } 716 onUserCreated(PackageDataSnapshot snapshot, int newUserId)717 public void onUserCreated(PackageDataSnapshot snapshot, int newUserId) { 718 if (!mCacheReady) { 719 return; 720 } 721 updateEntireShouldFilterCache(snapshot, newUserId); 722 } 723 onUserDeleted(@serIdInt int userId)724 public void onUserDeleted(@UserIdInt int userId) { 725 if (!mCacheReady) { 726 return; 727 } 728 removeShouldFilterCacheForUser(userId); 729 onChanged(); 730 } 731 updateShouldFilterCacheForPackage(PackageDataSnapshot snapshot, String packageName)732 private void updateShouldFilterCacheForPackage(PackageDataSnapshot snapshot, 733 String packageName) { 734 if (!mCacheReady) { 735 return; 736 } 737 final ArrayMap<String, ? extends PackageStateInternal> settings = 738 snapshot.getPackageStates(); 739 final UserInfo[] users = snapshot.getUserInfos(); 740 synchronized (mCacheLock) { 741 updateShouldFilterCacheForPackage(snapshot, null /* skipPackage */, 742 settings.get(packageName), settings, users, USER_ALL, 743 settings.size() /*maxIndex*/); 744 } 745 onChanged(); 746 } 747 748 @GuardedBy("mCacheLock") updateShouldFilterCacheForPackage(PackageDataSnapshot snapshot, @Nullable String skipPackageName, PackageStateInternal subjectSetting, ArrayMap<String, ? extends PackageStateInternal> allSettings, UserInfo[] allUsers, int subjectUserId, int maxIndex)749 private void updateShouldFilterCacheForPackage(PackageDataSnapshot snapshot, 750 @Nullable String skipPackageName, PackageStateInternal subjectSetting, ArrayMap<String, 751 ? extends PackageStateInternal> allSettings, UserInfo[] allUsers, int subjectUserId, 752 int maxIndex) { 753 for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { 754 PackageStateInternal otherSetting = allSettings.valueAt(i); 755 if (subjectSetting.getAppId() == otherSetting.getAppId()) { 756 continue; 757 } 758 //noinspection StringEquality 759 if (subjectSetting.getPackageName() == skipPackageName || otherSetting.getPackageName() 760 == skipPackageName) { 761 continue; 762 } 763 if (subjectUserId == USER_ALL) { 764 for (int su = 0; su < allUsers.length; su++) { 765 updateShouldFilterCacheForUser(snapshot, subjectSetting, allUsers, otherSetting, 766 allUsers[su].id); 767 } 768 } else { 769 updateShouldFilterCacheForUser(snapshot, subjectSetting, allUsers, otherSetting, 770 subjectUserId); 771 } 772 } 773 } 774 775 @GuardedBy("mCacheLock") updateShouldFilterCacheForUser(PackageDataSnapshot snapshot, PackageStateInternal subjectSetting, UserInfo[] allUsers, PackageStateInternal otherSetting, int subjectUserId)776 private void updateShouldFilterCacheForUser(PackageDataSnapshot snapshot, 777 PackageStateInternal subjectSetting, UserInfo[] allUsers, 778 PackageStateInternal otherSetting, int subjectUserId) { 779 for (int ou = 0; ou < allUsers.length; ou++) { 780 int otherUser = allUsers[ou].id; 781 int subjectUid = UserHandle.getUid(subjectUserId, subjectSetting.getAppId()); 782 int otherUid = UserHandle.getUid(otherUser, otherSetting.getAppId()); 783 final boolean shouldFilterSubjectToOther = shouldFilterApplicationInternal(snapshot, 784 subjectUid, subjectSetting, otherSetting, otherUser); 785 final boolean shouldFilterOtherToSubject = shouldFilterApplicationInternal(snapshot, 786 otherUid, otherSetting, subjectSetting, subjectUserId); 787 mShouldFilterCache.put(subjectUid, otherUid, shouldFilterSubjectToOther); 788 mShouldFilterCache.put(otherUid, subjectUid, shouldFilterOtherToSubject); 789 } 790 } 791 removeShouldFilterCacheForUser(int userId)792 private void removeShouldFilterCacheForUser(int userId) { 793 synchronized (mCacheLock) { 794 // Sorted uids with the ascending order 795 final int[] cacheUids = mShouldFilterCache.keys(); 796 final int size = cacheUids.length; 797 int pos = Arrays.binarySearch(cacheUids, UserHandle.getUid(userId, 0)); 798 final int fromIndex = (pos >= 0 ? pos : ~pos); 799 if (fromIndex >= size || UserHandle.getUserId(cacheUids[fromIndex]) != userId) { 800 Slog.w(TAG, "Failed to remove should filter cache for user " + userId 801 + ", fromIndex=" + fromIndex); 802 return; 803 } 804 pos = Arrays.binarySearch(cacheUids, UserHandle.getUid(userId + 1, 0) - 1); 805 final int toIndex = (pos >= 0 ? pos + 1 : ~pos); 806 if (fromIndex >= toIndex || UserHandle.getUserId(cacheUids[toIndex - 1]) != userId) { 807 Slog.w(TAG, "Failed to remove should filter cache for user " + userId 808 + ", fromIndex=" + fromIndex + ", toIndex=" + toIndex); 809 return; 810 } 811 mShouldFilterCache.removeRange(fromIndex, toIndex); 812 mShouldFilterCache.compact(); 813 } 814 } 815 isSystemSigned(@onNull SigningDetails sysSigningDetails, PackageStateInternal pkgSetting)816 private static boolean isSystemSigned(@NonNull SigningDetails sysSigningDetails, 817 PackageStateInternal pkgSetting) { 818 return pkgSetting.isSystem() 819 && pkgSetting.getSigningDetails().signaturesMatchExactly(sysSigningDetails); 820 } 821 collectProtectedBroadcasts( ArrayMap<String, ? extends PackageStateInternal> existingSettings, @Nullable String excludePackage)822 private void collectProtectedBroadcasts( 823 ArrayMap<String, ? extends PackageStateInternal> existingSettings, 824 @Nullable String excludePackage) { 825 synchronized (mProtectedBroadcastsLock) { 826 mProtectedBroadcasts.clear(); 827 for (int i = existingSettings.size() - 1; i >= 0; i--) { 828 PackageStateInternal setting = existingSettings.valueAt(i); 829 if (setting.getPkg() == null || setting.getPkg().getPackageName().equals( 830 excludePackage)) { 831 continue; 832 } 833 final List<String> protectedBroadcasts = setting.getPkg().getProtectedBroadcasts(); 834 if (!protectedBroadcasts.isEmpty()) { 835 mProtectedBroadcasts.addAll(protectedBroadcasts); 836 } 837 } 838 } 839 } 840 841 @Override isQueryableViaComponentWhenRequireRecompute( ArrayMap<String, ? extends PackageStateInternal> existingSettings, PackageStateInternal callingPkgSetting, ArraySet<PackageStateInternal> callingSharedPkgSettings, AndroidPackage targetPkg, int callingAppId, int targetAppId)842 protected boolean isQueryableViaComponentWhenRequireRecompute( 843 ArrayMap<String, ? extends PackageStateInternal> existingSettings, 844 PackageStateInternal callingPkgSetting, 845 ArraySet<PackageStateInternal> callingSharedPkgSettings, 846 AndroidPackage targetPkg, 847 int callingAppId, int targetAppId) { 848 // Recompute the whole mQueriesViaComponent because mProtectedBroadcasts have changed 849 recomputeComponentVisibility(existingSettings); 850 return isQueryableViaComponent(callingAppId, targetAppId); 851 } 852 853 /** 854 * This method recomputes all component / intent-based visibility and is intended to match the 855 * relevant logic of {@link #addPackageInternal(PackageStateInternal, ArrayMap)} 856 */ recomputeComponentVisibility( ArrayMap<String, ? extends PackageStateInternal> existingSettings)857 private void recomputeComponentVisibility( 858 ArrayMap<String, ? extends PackageStateInternal> existingSettings) { 859 synchronized (mQueriesViaComponentLock) { 860 mQueriesViaComponent.clear(); 861 } 862 for (int i = existingSettings.size() - 1; i >= 0; i--) { 863 PackageStateInternal setting = existingSettings.valueAt(i); 864 if (setting.getPkg() == null || requestsQueryAllPackages(setting.getPkg())) { 865 continue; 866 } 867 for (int j = existingSettings.size() - 1; j >= 0; j--) { 868 if (i == j) { 869 continue; 870 } 871 final PackageStateInternal otherSetting = existingSettings.valueAt(j); 872 if (otherSetting.getPkg() == null || mForceQueryable.contains( 873 otherSetting.getAppId())) { 874 continue; 875 } 876 final boolean canQueryViaComponents; 877 synchronized (mProtectedBroadcastsLock) { 878 canQueryViaComponents = canQueryViaComponents(setting.getPkg(), 879 otherSetting.getPkg(), mProtectedBroadcasts); 880 } 881 if (canQueryViaComponents) { 882 synchronized (mQueriesViaComponentLock) { 883 mQueriesViaComponent.add(setting.getAppId(), otherSetting.getAppId()); 884 } 885 } 886 } 887 } 888 889 mQueriesViaComponentRequireRecompute.set(false); 890 onChanged(); 891 } 892 893 /** 894 * Equivalent to calling {@link #addPackage(PackageDataSnapshot, PackageStateInternal, boolean)} 895 * with {@code isReplace} equal to {@code false}. 896 * 897 * @see AppsFilterImpl#addPackage(PackageDataSnapshot, PackageStateInternal, boolean) 898 */ addPackage(PackageDataSnapshot snapshot, PackageStateInternal newPkgSetting)899 public void addPackage(PackageDataSnapshot snapshot, PackageStateInternal newPkgSetting) { 900 addPackage(snapshot, newPkgSetting, false /* isReplace */); 901 } 902 903 /** 904 * Removes a package for consideration when filtering visibility between apps. 905 * 906 * @param setting the setting of the package being removed. 907 * @param isReplace if the package is being replaced. 908 */ removePackage(PackageDataSnapshot snapshot, PackageStateInternal setting, boolean isReplace)909 public void removePackage(PackageDataSnapshot snapshot, PackageStateInternal setting, 910 boolean isReplace) { 911 final ArraySet<String> additionalChangedPackages; 912 final ArrayMap<String, ? extends PackageStateInternal> settings = 913 snapshot.getPackageStates(); 914 final UserInfo[] users = snapshot.getUserInfos(); 915 final Collection<SharedUserSetting> sharedUserSettings = snapshot.getAllSharedUsers(); 916 final int userCount = users.length; 917 synchronized (mImplicitlyQueryableLock) { 918 for (int u = 0; u < userCount; u++) { 919 final int userId = users[u].id; 920 final int removingUid = UserHandle.getUid(userId, setting.getAppId()); 921 mImplicitlyQueryable.remove(removingUid); 922 for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { 923 mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), 924 removingUid); 925 } 926 927 if (isReplace) { 928 continue; 929 } 930 931 mRetainedImplicitlyQueryable.remove(removingUid); 932 for (int i = mRetainedImplicitlyQueryable.size() - 1; i >= 0; i--) { 933 mRetainedImplicitlyQueryable.remove( 934 mRetainedImplicitlyQueryable.keyAt(i), removingUid); 935 } 936 } 937 } 938 939 if (!mQueriesViaComponentRequireRecompute.get()) { 940 synchronized (mQueriesViaComponentLock) { 941 mQueriesViaComponent.remove(setting.getAppId()); 942 for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) { 943 mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.getAppId()); 944 } 945 } 946 } 947 948 synchronized (mQueriesViaPackageLock) { 949 mQueriesViaPackage.remove(setting.getAppId()); 950 for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { 951 mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), 952 setting.getAppId()); 953 } 954 } 955 956 synchronized (mQueryableViaUsesLibraryLock) { 957 mQueryableViaUsesLibrary.remove(setting.getAppId()); 958 for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) { 959 mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i), 960 setting.getAppId()); 961 } 962 } 963 964 synchronized (mForceQueryableLock) { 965 mForceQueryable.remove(setting.getAppId()); 966 } 967 968 boolean protectedBroadcastsChanged = false; 969 synchronized (mProtectedBroadcastsLock) { 970 if (setting.getPkg() != null 971 && !setting.getPkg().getProtectedBroadcasts().isEmpty()) { 972 final String removingPackageName = setting.getPkg().getPackageName(); 973 final ArrayList<String> protectedBroadcasts = new ArrayList<>( 974 mProtectedBroadcasts.untrackedStorage()); 975 collectProtectedBroadcasts(settings, removingPackageName); 976 protectedBroadcastsChanged = !mProtectedBroadcasts.containsAll(protectedBroadcasts); 977 } 978 } 979 980 if (protectedBroadcastsChanged) { 981 mQueriesViaComponentRequireRecompute.set(true); 982 } 983 984 additionalChangedPackages = mOverlayReferenceMapper.removePkg(setting.getPackageName()); 985 mFeatureConfig.updatePackageState(setting, true /*removed*/); 986 987 // After removing all traces of the package, if it's part of a shared user, re-add other 988 // shared user members to re-establish visibility between them and other packages. 989 // NOTE: this must come after all removals from data structures but before we update the 990 // cache 991 if (setting.hasSharedUser()) { 992 final ArraySet<? extends PackageStateInternal> sharedUserPackages = 993 getSharedUserPackages(setting.getSharedUserAppId(), sharedUserSettings); 994 for (int i = sharedUserPackages.size() - 1; i >= 0; i--) { 995 if (sharedUserPackages.valueAt(i) == setting) { 996 continue; 997 } 998 addPackageInternal( 999 sharedUserPackages.valueAt(i), settings); 1000 } 1001 } 1002 1003 if (mCacheReady) { 1004 removeAppIdFromVisibilityCache(setting.getAppId()); 1005 1006 if (setting.hasSharedUser()) { 1007 final ArraySet<? extends PackageStateInternal> sharedUserPackages = 1008 getSharedUserPackages(setting.getSharedUserAppId(), sharedUserSettings); 1009 for (int i = sharedUserPackages.size() - 1; i >= 0; i--) { 1010 PackageStateInternal siblingSetting = 1011 sharedUserPackages.valueAt(i); 1012 if (siblingSetting == setting) { 1013 continue; 1014 } 1015 synchronized (mCacheLock) { 1016 updateShouldFilterCacheForPackage(snapshot, 1017 setting.getPackageName(), siblingSetting, settings, 1018 users, USER_ALL, settings.size()); 1019 } 1020 } 1021 } 1022 1023 if (additionalChangedPackages != null) { 1024 for (int index = 0; index < additionalChangedPackages.size(); index++) { 1025 String changedPackage = additionalChangedPackages.valueAt(index); 1026 PackageStateInternal changedPkgSetting = settings.get(changedPackage); 1027 if (changedPkgSetting == null) { 1028 // It's possible for the overlay mapper to know that an actor 1029 // package changed via an explicit reference, even if the actor 1030 // isn't installed, so skip if that's the case. 1031 continue; 1032 } 1033 synchronized (mCacheLock) { 1034 updateShouldFilterCacheForPackage(snapshot, null, changedPkgSetting, 1035 settings, users, USER_ALL, settings.size()); 1036 } 1037 } 1038 } 1039 } else { 1040 invalidateCache("removePackage: " + setting.getPackageName()); 1041 } 1042 onChanged(); 1043 } 1044 1045 /** Returns {@code true} if the source package instruments the target package. */ pkgInstruments( @onNull AndroidPackage source, @NonNull AndroidPackage target)1046 private static boolean pkgInstruments( 1047 @NonNull AndroidPackage source, @NonNull AndroidPackage target) { 1048 try { 1049 if (DEBUG_TRACING) { 1050 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "pkgInstruments"); 1051 } 1052 final String packageName = target.getPackageName(); 1053 final List<ParsedInstrumentation> inst = source.getInstrumentations(); 1054 for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) { 1055 if (Objects.equals(inst.get(i).getTargetPackage(), packageName)) { 1056 return true; 1057 } 1058 } 1059 return false; 1060 } finally { 1061 if (DEBUG_TRACING) { 1062 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1063 } 1064 } 1065 } 1066 } 1067