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.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; 21 22 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; 23 24 import android.Manifest; 25 import android.annotation.NonNull; 26 import android.annotation.Nullable; 27 import android.content.Intent; 28 import android.content.IntentFilter; 29 import android.content.pm.PackageManager; 30 import android.content.pm.PackageManagerInternal; 31 import android.content.pm.PackageParser; 32 import android.content.pm.UserInfo; 33 import android.content.pm.parsing.component.ParsedComponent; 34 import android.content.pm.parsing.component.ParsedInstrumentation; 35 import android.content.pm.parsing.component.ParsedIntentInfo; 36 import android.content.pm.parsing.component.ParsedMainComponent; 37 import android.content.pm.parsing.component.ParsedProvider; 38 import android.os.Binder; 39 import android.os.Process; 40 import android.os.Trace; 41 import android.os.UserHandle; 42 import android.provider.DeviceConfig; 43 import android.text.TextUtils; 44 import android.util.ArrayMap; 45 import android.util.ArraySet; 46 import android.util.Slog; 47 import android.util.SparseArray; 48 import android.util.SparseBooleanArray; 49 import android.util.SparseSetArray; 50 51 import com.android.internal.R; 52 import com.android.internal.annotations.GuardedBy; 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.util.ArrayUtils; 55 import com.android.internal.util.function.QuadFunction; 56 import com.android.server.FgThread; 57 import com.android.server.compat.CompatChange; 58 import com.android.server.om.OverlayReferenceMapper; 59 import com.android.server.pm.parsing.pkg.AndroidPackage; 60 import com.android.server.utils.Snappable; 61 import com.android.server.utils.SnapshotCache; 62 import com.android.server.utils.Snapshots; 63 import com.android.server.utils.Watchable; 64 import com.android.server.utils.WatchableImpl; 65 import com.android.server.utils.WatchedArrayMap; 66 import com.android.server.utils.WatchedSparseBooleanMatrix; 67 import com.android.server.utils.Watcher; 68 69 import java.io.PrintWriter; 70 import java.util.Arrays; 71 import java.util.List; 72 import java.util.Objects; 73 import java.util.Set; 74 import java.util.StringTokenizer; 75 import java.util.concurrent.Executor; 76 77 /** 78 * The entity responsible for filtering visibility between apps based on declarations in their 79 * manifests. 80 */ 81 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 82 public class AppsFilter implements Watchable, Snappable { 83 84 private static final String TAG = "AppsFilter"; 85 86 // Logs all filtering instead of enforcing 87 private static final boolean DEBUG_ALLOW_ALL = false; 88 private static final boolean DEBUG_LOGGING = false; 89 private static final boolean DEBUG_TRACING = false; 90 91 /** 92 * This contains a list of app UIDs that are implicitly queryable because another app explicitly 93 * interacted with it. For example, if application A starts a service in application B, 94 * application B is implicitly allowed to query for application A; regardless of any manifest 95 * entries. 96 */ 97 private final SparseSetArray<Integer> mImplicitlyQueryable = new SparseSetArray<>(); 98 99 /** 100 * A mapping from the set of App IDs that query other App IDs via package name to the 101 * list of packages that they can see. 102 */ 103 private final SparseSetArray<Integer> mQueriesViaPackage = new SparseSetArray<>(); 104 105 /** 106 * A mapping from the set of App IDs that query others via component match to the list 107 * of packages that the they resolve to. 108 */ 109 private final SparseSetArray<Integer> mQueriesViaComponent = new SparseSetArray<>(); 110 111 /** 112 * A mapping from the set of App IDs that query other App IDs via library name to the 113 * list of packages that they can see. 114 */ 115 private final SparseSetArray<Integer> mQueryableViaUsesLibrary = new SparseSetArray<>(); 116 117 /** 118 * Executor for running reasonably short background tasks such as building the initial 119 * visibility cache. 120 */ 121 private final Executor mBackgroundExecutor; 122 123 /** 124 * Pending full recompute of mQueriesViaComponent. Occurs when a package adds a new set of 125 * protected broadcast. This in turn invalidates all prior additions and require a very 126 * computationally expensive recomputing. 127 * Full recompute is done lazily at the point when we use mQueriesViaComponent to filter apps. 128 */ 129 private boolean mQueriesViaComponentRequireRecompute = false; 130 131 /** 132 * A set of App IDs that are always queryable by any package, regardless of their manifest 133 * content. 134 */ 135 private final ArraySet<Integer> mForceQueryable = new ArraySet<>(); 136 137 /** 138 * The set of package names provided by the device that should be force queryable regardless of 139 * their manifest contents. 140 */ 141 private final String[] mForceQueryableByDevicePackageNames; 142 143 /** True if all system apps should be made queryable by default. */ 144 private final boolean mSystemAppsQueryable; 145 146 private final FeatureConfig mFeatureConfig; 147 private final OverlayReferenceMapper mOverlayReferenceMapper; 148 private final StateProvider mStateProvider; 149 150 private PackageParser.SigningDetails mSystemSigningDetails; 151 private Set<String> mProtectedBroadcasts = new ArraySet<>(); 152 153 private final Object mCacheLock = new Object(); 154 155 /** 156 * This structure maps uid -> uid and indicates whether access from the first should be 157 * filtered to the second. It's essentially a cache of the 158 * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call. 159 * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on 160 * initial scam and is null until {@link #onSystemReady()} is called. 161 */ 162 @GuardedBy("mCacheLock") 163 private volatile WatchedSparseBooleanMatrix mShouldFilterCache; 164 165 /** 166 * A cached snapshot. 167 */ 168 private final SnapshotCache<AppsFilter> mSnapshot; 169 makeCache()170 private SnapshotCache<AppsFilter> makeCache() { 171 return new SnapshotCache<AppsFilter>(this, this) { 172 @Override 173 public AppsFilter createSnapshot() { 174 AppsFilter s = new AppsFilter(mSource); 175 return s; 176 }}; 177 } 178 179 /** 180 * Watchable machinery 181 */ 182 private final WatchableImpl mWatchable = new WatchableImpl(); 183 184 /** 185 * Ensures an observer is in the list, exactly once. The observer cannot be null. The 186 * function quietly returns if the observer is already in the list. 187 * 188 * @param observer The {@link Watcher} to be notified when the {@link Watchable} changes. 189 */ 190 @Override 191 public void registerObserver(@NonNull Watcher observer) { 192 mWatchable.registerObserver(observer); 193 } 194 195 /** 196 * Ensures an observer is not in the list. The observer must not be null. The function 197 * quietly returns if the objserver is not in the list. 198 * 199 * @param observer The {@link Watcher} that should not be in the notification list. 200 */ 201 @Override 202 public void unregisterObserver(@NonNull Watcher observer) { 203 mWatchable.unregisterObserver(observer); 204 } 205 206 /** 207 * Return true if the {@link Watcher) is a registered observer. 208 * @param observer A {@link Watcher} that might be registered 209 * @return true if the observer is registered with this {@link Watchable}. 210 */ 211 @Override 212 public boolean isRegisteredObserver(@NonNull Watcher observer) { 213 return mWatchable.isRegisteredObserver(observer); 214 } 215 216 /** 217 * Invokes {@link Watcher#onChange} on each registered observer. The method can be called 218 * with the {@link Watchable} that generated the event. In a tree of {@link Watchable}s, this 219 * is generally the first (deepest) {@link Watchable} to detect a change. 220 * 221 * @param what The {@link Watchable} that generated the event. 222 */ 223 @Override 224 public void dispatchChange(@Nullable Watchable what) { 225 mWatchable.dispatchChange(what); 226 } 227 228 /** 229 * Report a change to observers. 230 */ 231 private void onChanged() { 232 dispatchChange(this); 233 } 234 235 @VisibleForTesting(visibility = PRIVATE) 236 AppsFilter(StateProvider stateProvider, 237 FeatureConfig featureConfig, 238 String[] forceQueryableList, 239 boolean systemAppsQueryable, 240 @Nullable OverlayReferenceMapper.Provider overlayProvider, 241 Executor backgroundExecutor) { 242 mFeatureConfig = featureConfig; 243 mForceQueryableByDevicePackageNames = forceQueryableList; 244 mSystemAppsQueryable = systemAppsQueryable; 245 mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, 246 overlayProvider); 247 mStateProvider = stateProvider; 248 mBackgroundExecutor = backgroundExecutor; 249 mSnapshot = makeCache(); 250 } 251 252 /** 253 * The copy constructor is used by PackageManagerService to construct a snapshot. 254 * Attributes are not deep-copied since these are supposed to be immutable. 255 * TODO: deep-copy the attributes, if necessary. 256 */ 257 private AppsFilter(AppsFilter orig) { 258 Snapshots.copy(mImplicitlyQueryable, orig.mImplicitlyQueryable); 259 Snapshots.copy(mQueriesViaPackage, orig.mQueriesViaPackage); 260 Snapshots.copy(mQueriesViaComponent, orig.mQueriesViaComponent); 261 Snapshots.copy(mQueryableViaUsesLibrary, orig.mQueryableViaUsesLibrary); 262 mQueriesViaComponentRequireRecompute = orig.mQueriesViaComponentRequireRecompute; 263 mForceQueryable.addAll(orig.mForceQueryable); 264 mForceQueryableByDevicePackageNames = orig.mForceQueryableByDevicePackageNames; 265 mSystemAppsQueryable = orig.mSystemAppsQueryable; 266 mFeatureConfig = orig.mFeatureConfig; 267 mOverlayReferenceMapper = orig.mOverlayReferenceMapper; 268 mStateProvider = orig.mStateProvider; 269 mSystemSigningDetails = orig.mSystemSigningDetails; 270 mProtectedBroadcasts = orig.mProtectedBroadcasts; 271 mShouldFilterCache = orig.mShouldFilterCache; 272 if (mShouldFilterCache != null) { 273 synchronized (orig.mCacheLock) { 274 mShouldFilterCache = mShouldFilterCache.snapshot(); 275 } 276 } 277 278 mBackgroundExecutor = null; 279 mSnapshot = new SnapshotCache.Sealed<>(); 280 } 281 282 /** 283 * Return a snapshot. If the cached snapshot is null, build a new one. The logic in 284 * the function ensures that this function returns a valid snapshot even if a race 285 * condition causes the cached snapshot to be cleared asynchronously to this method. 286 */ 287 public AppsFilter snapshot() { 288 return mSnapshot.snapshot(); 289 } 290 291 /** 292 * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding 293 * the data with the package lock. 294 */ 295 @VisibleForTesting(visibility = PRIVATE) 296 public interface StateProvider { 297 void runWithState(CurrentStateCallback callback); 298 299 interface CurrentStateCallback { 300 void currentState(ArrayMap<String, PackageSetting> settings, UserInfo[] users); 301 } 302 } 303 304 @VisibleForTesting(visibility = PRIVATE) 305 public interface FeatureConfig { 306 307 /** Called when the system is ready and components can be queried. */ 308 void onSystemReady(); 309 310 /** @return true if we should filter apps at all. */ 311 boolean isGloballyEnabled(); 312 313 /** @return true if the feature is enabled for the given package. */ 314 boolean packageIsEnabled(AndroidPackage pkg); 315 316 /** @return true if debug logging is enabled for the given package. */ 317 boolean isLoggingEnabled(int appId); 318 319 /** 320 * Turns on logging for the given appId 321 * 322 * @param enable true if logging should be enabled, false if disabled. 323 */ 324 void enableLogging(int appId, boolean enable); 325 326 /** 327 * Initializes the package enablement state for the given package. This gives opportunity 328 * to do any expensive operations ahead of the actual checks. 329 * 330 * @param removed true if adding, false if removing 331 */ 332 void updatePackageState(PackageSetting setting, boolean removed); 333 } 334 335 private static class FeatureConfigImpl implements FeatureConfig, CompatChange.ChangeListener { 336 private static final String FILTERING_ENABLED_NAME = "package_query_filtering_enabled"; 337 private final PackageManagerService.Injector mInjector; 338 private final PackageManagerInternal mPmInternal; 339 private volatile boolean mFeatureEnabled = 340 PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT; 341 private final ArraySet<String> mDisabledPackages = new ArraySet<>(); 342 343 @Nullable 344 private SparseBooleanArray mLoggingEnabled = null; 345 private AppsFilter mAppsFilter; 346 347 private FeatureConfigImpl( 348 PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { 349 mPmInternal = pmInternal; 350 mInjector = injector; 351 } 352 353 public void setAppsFilter(AppsFilter filter) { 354 mAppsFilter = filter; 355 } 356 357 @Override 358 public void onSystemReady() { 359 mFeatureEnabled = DeviceConfig.getBoolean( 360 NAMESPACE_PACKAGE_MANAGER_SERVICE, FILTERING_ENABLED_NAME, 361 PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT); 362 DeviceConfig.addOnPropertiesChangedListener( 363 NAMESPACE_PACKAGE_MANAGER_SERVICE, FgThread.getExecutor(), 364 properties -> { 365 if (properties.getKeyset().contains(FILTERING_ENABLED_NAME)) { 366 synchronized (FeatureConfigImpl.this) { 367 mFeatureEnabled = properties.getBoolean(FILTERING_ENABLED_NAME, 368 PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT); 369 } 370 } 371 }); 372 mInjector.getCompatibility().registerListener( 373 PackageManager.FILTER_APPLICATION_QUERY, this); 374 } 375 376 @Override 377 public boolean isGloballyEnabled() { 378 if (DEBUG_TRACING) { 379 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "isGloballyEnabled"); 380 } 381 try { 382 return mFeatureEnabled; 383 } finally { 384 if (DEBUG_TRACING) { 385 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 386 } 387 } 388 } 389 390 @Override 391 public boolean packageIsEnabled(AndroidPackage pkg) { 392 if (DEBUG_TRACING) { 393 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "packageIsEnabled"); 394 } 395 try { 396 return !mDisabledPackages.contains(pkg.getPackageName()); 397 } finally { 398 if (DEBUG_TRACING) { 399 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 400 } 401 } 402 } 403 404 @Override 405 public boolean isLoggingEnabled(int uid) { 406 return mLoggingEnabled != null && mLoggingEnabled.indexOfKey(uid) >= 0; 407 } 408 409 @Override 410 public void enableLogging(int appId, boolean enable) { 411 if (enable) { 412 if (mLoggingEnabled == null) { 413 mLoggingEnabled = new SparseBooleanArray(); 414 } 415 mLoggingEnabled.put(appId, true); 416 } else { 417 if (mLoggingEnabled != null) { 418 final int index = mLoggingEnabled.indexOfKey(appId); 419 if (index >= 0) { 420 mLoggingEnabled.removeAt(index); 421 if (mLoggingEnabled.size() == 0) { 422 mLoggingEnabled = null; 423 } 424 } 425 } 426 } 427 } 428 429 @Override 430 public void onCompatChange(String packageName) { 431 AndroidPackage pkg = mPmInternal.getPackage(packageName); 432 if (pkg == null) { 433 return; 434 } 435 updateEnabledState(pkg); 436 mAppsFilter.updateShouldFilterCacheForPackage(packageName); 437 } 438 439 private void updateEnabledState(@NonNull AndroidPackage pkg) { 440 // TODO(b/135203078): Do not use toAppInfo 441 // TODO(b/167551701): Make changeId non-logging 442 final boolean enabled = mInjector.getCompatibility().isChangeEnabledInternalNoLogging( 443 PackageManager.FILTER_APPLICATION_QUERY, pkg.toAppInfoWithoutState()); 444 if (enabled) { 445 mDisabledPackages.remove(pkg.getPackageName()); 446 } else { 447 mDisabledPackages.add(pkg.getPackageName()); 448 } 449 if (mAppsFilter != null) { 450 mAppsFilter.onChanged(); 451 } 452 } 453 454 @Override 455 public void updatePackageState(PackageSetting setting, boolean removed) { 456 final boolean enableLogging = setting.pkg != null && 457 !removed && (setting.pkg.isTestOnly() || setting.pkg.isDebuggable()); 458 enableLogging(setting.appId, enableLogging); 459 if (removed) { 460 mDisabledPackages.remove(setting.name); 461 } else if (setting.pkg != null) { 462 updateEnabledState(setting.pkg); 463 } 464 } 465 } 466 467 /** Builder method for an AppsFilter */ 468 public static AppsFilter create( 469 PackageManagerInternal pms, PackageManagerService.Injector injector) { 470 final boolean forceSystemAppsQueryable = 471 injector.getContext().getResources() 472 .getBoolean(R.bool.config_forceSystemPackagesQueryable); 473 final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector); 474 final String[] forcedQueryablePackageNames; 475 if (forceSystemAppsQueryable) { 476 // all system apps already queryable, no need to read and parse individual exceptions 477 forcedQueryablePackageNames = new String[]{}; 478 } else { 479 forcedQueryablePackageNames = 480 injector.getContext().getResources() 481 .getStringArray(R.array.config_forceQueryablePackages); 482 for (int i = 0; i < forcedQueryablePackageNames.length; i++) { 483 forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern(); 484 } 485 } 486 final StateProvider stateProvider = command -> { 487 synchronized (injector.getLock()) { 488 command.currentState(injector.getSettings().getPackagesLocked().untrackedStorage(), 489 injector.getUserManagerInternal().getUserInfos()); 490 } 491 }; 492 AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig, 493 forcedQueryablePackageNames, forceSystemAppsQueryable, null, 494 injector.getBackgroundExecutor()); 495 featureConfig.setAppsFilter(appsFilter); 496 return appsFilter; 497 } 498 499 public FeatureConfig getFeatureConfig() { 500 return mFeatureConfig; 501 } 502 503 /** Returns true if the querying package may query for the potential target package */ 504 private static boolean canQueryViaComponents(AndroidPackage querying, 505 AndroidPackage potentialTarget, Set<String> protectedBroadcasts) { 506 if (!querying.getQueriesIntents().isEmpty()) { 507 for (Intent intent : querying.getQueriesIntents()) { 508 if (matchesPackage(intent, potentialTarget, protectedBroadcasts)) { 509 return true; 510 } 511 } 512 } 513 if (!querying.getQueriesProviders().isEmpty() 514 && matchesProviders(querying.getQueriesProviders(), potentialTarget)) { 515 return true; 516 } 517 return false; 518 } 519 520 private static boolean canQueryViaPackage(AndroidPackage querying, 521 AndroidPackage potentialTarget) { 522 return !querying.getQueriesPackages().isEmpty() 523 && querying.getQueriesPackages().contains(potentialTarget.getPackageName()); 524 } 525 526 private static boolean canQueryAsInstaller(PackageSetting querying, 527 AndroidPackage potentialTarget) { 528 final InstallSource installSource = querying.installSource; 529 if (potentialTarget.getPackageName().equals(installSource.installerPackageName)) { 530 return true; 531 } 532 if (!installSource.isInitiatingPackageUninstalled 533 && potentialTarget.getPackageName().equals(installSource.initiatingPackageName)) { 534 return true; 535 } 536 return false; 537 } 538 539 private static boolean canQueryViaUsesLibrary(AndroidPackage querying, 540 AndroidPackage potentialTarget) { 541 if (potentialTarget.getLibraryNames().isEmpty()) { 542 return false; 543 } 544 final List<String> libNames = potentialTarget.getLibraryNames(); 545 for (int i = 0, size = libNames.size(); i < size; i++) { 546 final String libName = libNames.get(i); 547 if (querying.getUsesLibraries().contains(libName) 548 || querying.getUsesOptionalLibraries().contains(libName)) { 549 return true; 550 } 551 } 552 return false; 553 } 554 555 private static boolean matchesProviders( 556 Set<String> queriesAuthorities, AndroidPackage potentialTarget) { 557 for (int p = ArrayUtils.size(potentialTarget.getProviders()) - 1; p >= 0; p--) { 558 ParsedProvider provider = potentialTarget.getProviders().get(p); 559 if (!provider.isExported()) { 560 continue; 561 } 562 if (provider.getAuthority() == null) { 563 continue; 564 } 565 StringTokenizer authorities = new StringTokenizer(provider.getAuthority(), ";", 566 false); 567 while (authorities.hasMoreElements()) { 568 if (queriesAuthorities.contains(authorities.nextToken())) { 569 return true; 570 } 571 } 572 } 573 return false; 574 } 575 576 private static boolean matchesPackage(Intent intent, AndroidPackage potentialTarget, 577 Set<String> protectedBroadcasts) { 578 if (matchesAnyComponents( 579 intent, potentialTarget.getServices(), null /*protectedBroadcasts*/)) { 580 return true; 581 } 582 if (matchesAnyComponents( 583 intent, potentialTarget.getActivities(), null /*protectedBroadcasts*/)) { 584 return true; 585 } 586 if (matchesAnyComponents(intent, potentialTarget.getReceivers(), protectedBroadcasts)) { 587 return true; 588 } 589 if (matchesAnyComponents( 590 intent, potentialTarget.getProviders(), null /*protectedBroadcasts*/)) { 591 return true; 592 } 593 return false; 594 } 595 596 private static boolean matchesAnyComponents(Intent intent, 597 List<? extends ParsedMainComponent> components, 598 Set<String> protectedBroadcasts) { 599 for (int i = ArrayUtils.size(components) - 1; i >= 0; i--) { 600 ParsedMainComponent component = components.get(i); 601 if (!component.isExported()) { 602 continue; 603 } 604 if (matchesAnyFilter(intent, component, protectedBroadcasts)) { 605 return true; 606 } 607 } 608 return false; 609 } 610 611 private static boolean matchesAnyFilter(Intent intent, ParsedComponent component, 612 Set<String> protectedBroadcasts) { 613 List<ParsedIntentInfo> intents = component.getIntents(); 614 for (int i = ArrayUtils.size(intents) - 1; i >= 0; i--) { 615 IntentFilter intentFilter = intents.get(i); 616 if (matchesIntentFilter(intent, intentFilter, protectedBroadcasts)) { 617 return true; 618 } 619 } 620 return false; 621 } 622 623 private static boolean matchesIntentFilter(Intent intent, IntentFilter intentFilter, 624 @Nullable Set<String> protectedBroadcasts) { 625 return intentFilter.match(intent.getAction(), intent.getType(), intent.getScheme(), 626 intent.getData(), intent.getCategories(), "AppsFilter", true, protectedBroadcasts) 627 > 0; 628 } 629 630 /** 631 * Grants access based on an interaction between a calling and target package, granting 632 * visibility of the caller from the target. 633 * 634 * @param recipientUid the uid gaining visibility of the {@code visibleUid}. 635 * @param visibleUid the uid becoming visible to the {@recipientUid} 636 * @return {@code true} if implicit access was not already granted. 637 */ 638 public boolean grantImplicitAccess(int recipientUid, int visibleUid) { 639 if (recipientUid == visibleUid) { 640 return false; 641 } 642 final boolean changed = mImplicitlyQueryable.add(recipientUid, visibleUid); 643 if (changed && DEBUG_LOGGING) { 644 Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); 645 } 646 synchronized (mCacheLock) { 647 if (mShouldFilterCache != null) { 648 // update the cache in a one-off manner since we've got all the information we 649 // need. 650 mShouldFilterCache.put(recipientUid, visibleUid, false); 651 } 652 } 653 if (changed) { 654 onChanged(); 655 } 656 return changed; 657 } 658 659 public void onSystemReady() { 660 mOverlayReferenceMapper.rebuildIfDeferred(); 661 mFeatureConfig.onSystemReady(); 662 663 updateEntireShouldFilterCacheAsync(); 664 onChanged(); 665 } 666 667 /** 668 * Adds a package that should be considered when filtering visibility between apps. 669 * 670 * @param newPkgSetting the new setting being added 671 * @param isReplace if the package is being replaced and may need extra cleanup. 672 */ 673 public void addPackage(PackageSetting newPkgSetting, boolean isReplace) { 674 if (DEBUG_TRACING) { 675 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); 676 } 677 try { 678 if (isReplace) { 679 // let's first remove any prior rules for this package 680 removePackage(newPkgSetting); 681 } 682 mStateProvider.runWithState((settings, users) -> { 683 ArraySet<String> additionalChangedPackages = 684 addPackageInternal(newPkgSetting, settings); 685 synchronized (mCacheLock) { 686 if (mShouldFilterCache != null) { 687 updateShouldFilterCacheForPackage(mShouldFilterCache, null, newPkgSetting, 688 settings, users, settings.size()); 689 if (additionalChangedPackages != null) { 690 for (int index = 0; index < additionalChangedPackages.size(); index++) { 691 String changedPackage = additionalChangedPackages.valueAt(index); 692 PackageSetting changedPkgSetting = settings.get(changedPackage); 693 if (changedPkgSetting == null) { 694 // It's possible for the overlay mapper to know that an actor 695 // package changed via an explicit reference, even if the actor 696 // isn't installed, so skip if that's the case. 697 continue; 698 } 699 700 updateShouldFilterCacheForPackage(mShouldFilterCache, null, 701 changedPkgSetting, settings, users, settings.size()); 702 } 703 } 704 } // else, rebuild entire cache when system is ready 705 } 706 }); 707 } finally { 708 onChanged(); 709 if (DEBUG_TRACING) { 710 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 711 } 712 } 713 } 714 715 /** 716 * @return Additional packages that may have had their viewing visibility changed and may need 717 * to be updated in the cache. Returns null if there are no additional packages. 718 */ 719 @Nullable 720 private ArraySet<String> addPackageInternal(PackageSetting newPkgSetting, 721 ArrayMap<String, PackageSetting> existingSettings) { 722 if (Objects.equals("android", newPkgSetting.name)) { 723 // let's set aside the framework signatures 724 mSystemSigningDetails = newPkgSetting.signatures.mSigningDetails; 725 // and since we add overlays before we add the framework, let's revisit already added 726 // packages for signature matches 727 for (PackageSetting setting : existingSettings.values()) { 728 if (isSystemSigned(mSystemSigningDetails, setting)) { 729 mForceQueryable.add(setting.appId); 730 } 731 } 732 } 733 734 final AndroidPackage newPkg = newPkgSetting.pkg; 735 if (newPkg == null) { 736 return null; 737 } 738 739 if (mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts())) { 740 mQueriesViaComponentRequireRecompute = true; 741 } 742 743 final boolean newIsForceQueryable = 744 mForceQueryable.contains(newPkgSetting.appId) 745 /* shared user that is already force queryable */ 746 || newPkgSetting.forceQueryableOverride /* adb override */ 747 || (newPkgSetting.isSystem() && (mSystemAppsQueryable 748 || newPkg.isForceQueryable() 749 || ArrayUtils.contains(mForceQueryableByDevicePackageNames, 750 newPkg.getPackageName()))); 751 if (newIsForceQueryable 752 || (mSystemSigningDetails != null 753 && isSystemSigned(mSystemSigningDetails, newPkgSetting))) { 754 mForceQueryable.add(newPkgSetting.appId); 755 } 756 757 for (int i = existingSettings.size() - 1; i >= 0; i--) { 758 final PackageSetting existingSetting = existingSettings.valueAt(i); 759 if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) { 760 continue; 761 } 762 final AndroidPackage existingPkg = existingSetting.pkg; 763 // let's evaluate the ability of already added packages to see this new package 764 if (!newIsForceQueryable) { 765 if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(existingPkg, 766 newPkg, mProtectedBroadcasts)) { 767 mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); 768 } 769 if (canQueryViaPackage(existingPkg, newPkg) 770 || canQueryAsInstaller(existingSetting, newPkg)) { 771 mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); 772 } 773 if (canQueryViaUsesLibrary(existingPkg, newPkg)) { 774 mQueryableViaUsesLibrary.add(existingSetting.appId, newPkgSetting.appId); 775 } 776 } 777 // now we'll evaluate our new package's ability to see existing packages 778 if (!mForceQueryable.contains(existingSetting.appId)) { 779 if (!mQueriesViaComponentRequireRecompute && canQueryViaComponents(newPkg, 780 existingPkg, mProtectedBroadcasts)) { 781 mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); 782 } 783 if (canQueryViaPackage(newPkg, existingPkg) 784 || canQueryAsInstaller(newPkgSetting, existingPkg)) { 785 mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); 786 } 787 if (canQueryViaUsesLibrary(newPkg, existingPkg)) { 788 mQueryableViaUsesLibrary.add(newPkgSetting.appId, existingSetting.appId); 789 } 790 } 791 // if either package instruments the other, mark both as visible to one another 792 if (newPkgSetting.pkg != null && existingSetting.pkg != null 793 && (pkgInstruments(newPkgSetting.pkg, existingSetting.pkg) 794 || pkgInstruments(existingSetting.pkg, newPkgSetting.pkg))) { 795 mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); 796 mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); 797 } 798 } 799 800 int existingSize = existingSettings.size(); 801 ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); 802 for (int index = 0; index < existingSize; index++) { 803 PackageSetting pkgSetting = existingSettings.valueAt(index); 804 if (pkgSetting.pkg != null) { 805 existingPkgs.put(pkgSetting.name, pkgSetting.pkg); 806 } 807 } 808 809 ArraySet<String> changedPackages = 810 mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); 811 812 mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); 813 814 return changedPackages; 815 } 816 817 @GuardedBy("mCacheLock") 818 private void removeAppIdFromVisibilityCache(int appId) { 819 if (mShouldFilterCache == null) { 820 return; 821 } 822 for (int i = 0; i < mShouldFilterCache.size(); i++) { 823 if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) { 824 mShouldFilterCache.removeAt(i); 825 // The key was deleted so the list of keys has shifted left. That means i 826 // is now pointing at the next key to be examined. The decrement here and 827 // the loop increment together mean that i will be unchanged in the need 828 // iteration and will correctly point to the next key to be examined. 829 i--; 830 } 831 } 832 } 833 834 private void updateEntireShouldFilterCache() { 835 mStateProvider.runWithState((settings, users) -> { 836 WatchedSparseBooleanMatrix cache = 837 updateEntireShouldFilterCacheInner(settings, users); 838 synchronized (mCacheLock) { 839 mShouldFilterCache = cache; 840 } 841 }); 842 } 843 844 private WatchedSparseBooleanMatrix updateEntireShouldFilterCacheInner( 845 ArrayMap<String, PackageSetting> settings, UserInfo[] users) { 846 WatchedSparseBooleanMatrix cache = 847 new WatchedSparseBooleanMatrix(users.length * settings.size()); 848 for (int i = settings.size() - 1; i >= 0; i--) { 849 updateShouldFilterCacheForPackage(cache, 850 null /*skipPackage*/, settings.valueAt(i), settings, users, i); 851 } 852 return cache; 853 } 854 855 private void updateEntireShouldFilterCacheAsync() { 856 mBackgroundExecutor.execute(() -> { 857 final ArrayMap<String, PackageSetting> settingsCopy = new ArrayMap<>(); 858 final ArrayMap<String, AndroidPackage> packagesCache = new ArrayMap<>(); 859 final UserInfo[][] usersRef = new UserInfo[1][]; 860 mStateProvider.runWithState((settings, users) -> { 861 packagesCache.ensureCapacity(settings.size()); 862 settingsCopy.putAll(settings); 863 usersRef[0] = users; 864 // store away the references to the immutable packages, since settings are retained 865 // during updates. 866 for (int i = 0, max = settings.size(); i < max; i++) { 867 final AndroidPackage pkg = settings.valueAt(i).pkg; 868 packagesCache.put(settings.keyAt(i), pkg); 869 } 870 }); 871 WatchedSparseBooleanMatrix cache = 872 updateEntireShouldFilterCacheInner(settingsCopy, usersRef[0]); 873 boolean[] changed = new boolean[1]; 874 // We have a cache, let's make sure the world hasn't changed out from under us. 875 mStateProvider.runWithState((settings, users) -> { 876 if (settings.size() != settingsCopy.size()) { 877 changed[0] = true; 878 return; 879 } 880 for (int i = 0, max = settings.size(); i < max; i++) { 881 final AndroidPackage pkg = settings.valueAt(i).pkg; 882 if (!Objects.equals(pkg, packagesCache.get(settings.keyAt(i)))) { 883 changed[0] = true; 884 return; 885 } 886 } 887 }); 888 if (changed[0]) { 889 // Something has changed, just update the cache inline with the lock held 890 updateEntireShouldFilterCache(); 891 if (DEBUG_LOGGING) { 892 Slog.i(TAG, "Rebuilding cache with lock due to package change."); 893 } 894 } else { 895 synchronized (mCacheLock) { 896 mShouldFilterCache = cache; 897 } 898 } 899 }); 900 } 901 902 public void onUsersChanged() { 903 synchronized (mCacheLock) { 904 if (mShouldFilterCache != null) { 905 updateEntireShouldFilterCache(); 906 onChanged(); 907 } 908 } 909 } 910 911 private void updateShouldFilterCacheForPackage(String packageName) { 912 synchronized (mCacheLock) { 913 if (mShouldFilterCache != null) { 914 mStateProvider.runWithState((settings, users) -> { 915 updateShouldFilterCacheForPackage(mShouldFilterCache, null /* skipPackage */, 916 settings.get(packageName), settings, users, 917 settings.size() /*maxIndex*/); 918 }); 919 } 920 } 921 } 922 923 private void updateShouldFilterCacheForPackage(WatchedSparseBooleanMatrix cache, 924 @Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String, 925 PackageSetting> allSettings, UserInfo[] allUsers, int maxIndex) { 926 for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { 927 PackageSetting otherSetting = allSettings.valueAt(i); 928 if (subjectSetting.appId == otherSetting.appId) { 929 continue; 930 } 931 //noinspection StringEquality 932 if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) { 933 continue; 934 } 935 final int userCount = allUsers.length; 936 final int appxUidCount = userCount * allSettings.size(); 937 for (int su = 0; su < userCount; su++) { 938 int subjectUser = allUsers[su].id; 939 for (int ou = 0; ou < userCount; ou++) { 940 int otherUser = allUsers[ou].id; 941 int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId); 942 int otherUid = UserHandle.getUid(otherUser, otherSetting.appId); 943 cache.put(subjectUid, otherUid, 944 shouldFilterApplicationInternal( 945 subjectUid, subjectSetting, otherSetting, otherUser)); 946 cache.put(otherUid, subjectUid, 947 shouldFilterApplicationInternal( 948 otherUid, otherSetting, subjectSetting, subjectUser)); 949 } 950 } 951 } 952 } 953 954 private static boolean isSystemSigned(@NonNull PackageParser.SigningDetails sysSigningDetails, 955 PackageSetting pkgSetting) { 956 return pkgSetting.isSystem() 957 && pkgSetting.signatures.mSigningDetails.signaturesMatchExactly(sysSigningDetails); 958 } 959 960 private ArraySet<String> collectProtectedBroadcasts( 961 ArrayMap<String, PackageSetting> existingSettings, @Nullable String excludePackage) { 962 ArraySet<String> ret = new ArraySet<>(); 963 for (int i = existingSettings.size() - 1; i >= 0; i--) { 964 PackageSetting setting = existingSettings.valueAt(i); 965 if (setting.pkg == null || setting.pkg.getPackageName().equals(excludePackage)) { 966 continue; 967 } 968 final List<String> protectedBroadcasts = setting.pkg.getProtectedBroadcasts(); 969 if (!protectedBroadcasts.isEmpty()) { 970 ret.addAll(protectedBroadcasts); 971 } 972 } 973 return ret; 974 } 975 976 /** 977 * This method recomputes all component / intent-based visibility and is intended to match the 978 * relevant logic of {@link #addPackageInternal(PackageSetting, ArrayMap)} 979 */ 980 private void recomputeComponentVisibility( 981 ArrayMap<String, PackageSetting> existingSettings) { 982 mQueriesViaComponent.clear(); 983 for (int i = existingSettings.size() - 1; i >= 0; i--) { 984 PackageSetting setting = existingSettings.valueAt(i); 985 if (setting.pkg == null || requestsQueryAllPackages(setting.pkg)) { 986 continue; 987 } 988 for (int j = existingSettings.size() - 1; j >= 0; j--) { 989 if (i == j) { 990 continue; 991 } 992 final PackageSetting otherSetting = existingSettings.valueAt(j); 993 if (otherSetting.pkg == null || mForceQueryable.contains(otherSetting.appId)) { 994 continue; 995 } 996 if (canQueryViaComponents(setting.pkg, otherSetting.pkg, mProtectedBroadcasts)) { 997 mQueriesViaComponent.add(setting.appId, otherSetting.appId); 998 } 999 } 1000 } 1001 mQueriesViaComponentRequireRecompute = false; 1002 } 1003 1004 /** 1005 * Fetches all app Ids that a given setting is currently visible to, per provided user. This 1006 * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see 1007 * all applications. 1008 * 1009 * If the setting is visible to all UIDs, null is returned. If an app is not visible to any 1010 * applications, the int array will be empty. 1011 * 1012 * @param users the set of users that should be evaluated for this calculation 1013 * @param existingSettings the set of all package settings that currently exist on device 1014 * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the 1015 * provided setting or null if the app is visible to all and no allow list should be 1016 * applied. 1017 */ 1018 @Nullable 1019 public SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users, 1020 ArrayMap<String, PackageSetting> existingSettings) { 1021 if (mForceQueryable.contains(setting.appId)) { 1022 return null; 1023 } 1024 // let's reserve max memory to limit the number of allocations 1025 SparseArray<int[]> result = new SparseArray<>(users.length); 1026 for (int u = 0; u < users.length; u++) { 1027 final int userId = users[u]; 1028 int[] appIds = new int[existingSettings.size()]; 1029 int[] buffer = null; 1030 int allowListSize = 0; 1031 for (int i = existingSettings.size() - 1; i >= 0; i--) { 1032 final PackageSetting existingSetting = existingSettings.valueAt(i); 1033 final int existingAppId = existingSetting.appId; 1034 if (existingAppId < Process.FIRST_APPLICATION_UID) { 1035 continue; 1036 } 1037 final int loc = Arrays.binarySearch(appIds, 0, allowListSize, existingAppId); 1038 if (loc >= 0) { 1039 continue; 1040 } 1041 final int existingUid = UserHandle.getUid(userId, existingAppId); 1042 if (!shouldFilterApplication(existingUid, existingSetting, setting, userId)) { 1043 if (buffer == null) { 1044 buffer = new int[appIds.length]; 1045 } 1046 final int insert = ~loc; 1047 System.arraycopy(appIds, insert, buffer, 0, allowListSize - insert); 1048 appIds[insert] = existingAppId; 1049 System.arraycopy(buffer, 0, appIds, insert + 1, allowListSize - insert); 1050 allowListSize++; 1051 } 1052 } 1053 result.put(userId, Arrays.copyOf(appIds, allowListSize)); 1054 } 1055 return result; 1056 } 1057 1058 /** 1059 * This api does type conversion on the <existingSettings> parameter. 1060 */ 1061 @VisibleForTesting(visibility = PRIVATE) 1062 @Nullable 1063 SparseArray<int[]> getVisibilityAllowList(PackageSetting setting, int[] users, 1064 WatchedArrayMap<String, PackageSetting> existingSettings) { 1065 return getVisibilityAllowList(setting, users, existingSettings.untrackedStorage()); 1066 } 1067 1068 /** 1069 * Equivalent to calling {@link #addPackage(PackageSetting, boolean)} with {@code isReplace} 1070 * equal to {@code false}. 1071 * @see AppsFilter#addPackage(PackageSetting, boolean) 1072 */ 1073 public void addPackage(PackageSetting newPkgSetting) { 1074 addPackage(newPkgSetting, false /* isReplace */); 1075 } 1076 1077 /** 1078 * Removes a package for consideration when filtering visibility between apps. 1079 * 1080 * @param setting the setting of the package being removed. 1081 */ 1082 public void removePackage(PackageSetting setting) { 1083 mStateProvider.runWithState((settings, users) -> { 1084 final int userCount = users.length; 1085 for (int u = 0; u < userCount; u++) { 1086 final int userId = users[u].id; 1087 final int removingUid = UserHandle.getUid(userId, setting.appId); 1088 mImplicitlyQueryable.remove(removingUid); 1089 for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { 1090 mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid); 1091 } 1092 } 1093 1094 if (!mQueriesViaComponentRequireRecompute) { 1095 mQueriesViaComponent.remove(setting.appId); 1096 for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) { 1097 mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId); 1098 } 1099 } 1100 mQueriesViaPackage.remove(setting.appId); 1101 for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { 1102 mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); 1103 } 1104 mQueryableViaUsesLibrary.remove(setting.appId); 1105 for (int i = mQueryableViaUsesLibrary.size() - 1; i >= 0; i--) { 1106 mQueryableViaUsesLibrary.remove(mQueryableViaUsesLibrary.keyAt(i), setting.appId); 1107 } 1108 1109 mForceQueryable.remove(setting.appId); 1110 1111 if (setting.pkg != null && !setting.pkg.getProtectedBroadcasts().isEmpty()) { 1112 final String removingPackageName = setting.pkg.getPackageName(); 1113 final Set<String> protectedBroadcasts = mProtectedBroadcasts; 1114 mProtectedBroadcasts = collectProtectedBroadcasts(settings, removingPackageName); 1115 if (!mProtectedBroadcasts.containsAll(protectedBroadcasts)) { 1116 mQueriesViaComponentRequireRecompute = true; 1117 } 1118 } 1119 1120 ArraySet<String> additionalChangedPackages = 1121 mOverlayReferenceMapper.removePkg(setting.name); 1122 1123 mFeatureConfig.updatePackageState(setting, true /*removed*/); 1124 1125 // After removing all traces of the package, if it's part of a shared user, re-add other 1126 // shared user members to re-establish visibility between them and other packages. 1127 // NOTE: this must come after all removals from data structures but before we update the 1128 // cache 1129 if (setting.sharedUser != null) { 1130 for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { 1131 if (setting.sharedUser.packages.valueAt(i) == setting) { 1132 continue; 1133 } 1134 addPackageInternal( 1135 setting.sharedUser.packages.valueAt(i), settings); 1136 } 1137 } 1138 1139 synchronized (mCacheLock) { 1140 removeAppIdFromVisibilityCache(setting.appId); 1141 if (mShouldFilterCache != null && setting.sharedUser != null) { 1142 for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { 1143 PackageSetting siblingSetting = setting.sharedUser.packages.valueAt(i); 1144 if (siblingSetting == setting) { 1145 continue; 1146 } 1147 updateShouldFilterCacheForPackage(mShouldFilterCache, setting.name, 1148 siblingSetting, settings, users, settings.size()); 1149 } 1150 } 1151 1152 if (mShouldFilterCache != null) { 1153 if (additionalChangedPackages != null) { 1154 for (int index = 0; index < additionalChangedPackages.size(); index++) { 1155 String changedPackage = additionalChangedPackages.valueAt(index); 1156 PackageSetting changedPkgSetting = settings.get(changedPackage); 1157 if (changedPkgSetting == null) { 1158 // It's possible for the overlay mapper to know that an actor 1159 // package changed via an explicit reference, even if the actor 1160 // isn't installed, so skip if that's the case. 1161 continue; 1162 } 1163 1164 updateShouldFilterCacheForPackage(mShouldFilterCache, null, 1165 changedPkgSetting, settings, users, settings.size()); 1166 } 1167 } 1168 } 1169 1170 onChanged(); 1171 } 1172 }); 1173 } 1174 1175 /** 1176 * Returns true if the calling package should not be able to see the target package, false if no 1177 * filtering should be done. 1178 * 1179 * @param callingUid the uid of the caller attempting to access a package 1180 * @param callingSetting the setting attempting to access a package or null if it could not be 1181 * found 1182 * @param targetPkgSetting the package being accessed 1183 * @param userId the user in which this access is being attempted 1184 */ 1185 public boolean shouldFilterApplication(int callingUid, @Nullable SettingBase callingSetting, 1186 PackageSetting targetPkgSetting, int userId) { 1187 if (DEBUG_TRACING) { 1188 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); 1189 } 1190 try { 1191 int callingAppId = UserHandle.getAppId(callingUid); 1192 if (callingAppId < Process.FIRST_APPLICATION_UID 1193 || targetPkgSetting.appId < Process.FIRST_APPLICATION_UID 1194 || callingAppId == targetPkgSetting.appId) { 1195 return false; 1196 } 1197 synchronized (mCacheLock) { 1198 if (mShouldFilterCache != null) { // use cache 1199 final int callingIndex = mShouldFilterCache.indexOfKey(callingUid); 1200 if (callingIndex < 0) { 1201 Slog.wtf(TAG, "Encountered calling uid with no cached rules: " 1202 + callingUid); 1203 return true; 1204 } 1205 final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); 1206 final int targetIndex = mShouldFilterCache.indexOfKey(targetUid); 1207 if (targetIndex < 0) { 1208 Slog.w(TAG, "Encountered calling -> target with no cached rules: " 1209 + callingUid + " -> " + targetUid); 1210 return true; 1211 } 1212 return mShouldFilterCache.valueAt(callingIndex, targetIndex); 1213 } else { 1214 if (!shouldFilterApplicationInternal( 1215 callingUid, callingSetting, targetPkgSetting, userId)) { 1216 return false; 1217 } 1218 } 1219 } 1220 if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(callingAppId)) { 1221 log(callingSetting, targetPkgSetting, "BLOCKED"); 1222 } 1223 return !DEBUG_ALLOW_ALL; 1224 } finally { 1225 if (DEBUG_TRACING) { 1226 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1227 } 1228 } 1229 } 1230 1231 private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting, 1232 PackageSetting targetPkgSetting, int targetUserId) { 1233 if (DEBUG_TRACING) { 1234 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal"); 1235 } 1236 try { 1237 final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); 1238 if (!featureEnabled) { 1239 if (DEBUG_LOGGING) { 1240 Slog.d(TAG, "filtering disabled; skipped"); 1241 } 1242 return false; 1243 } 1244 if (callingSetting == null) { 1245 Slog.wtf(TAG, "No setting found for non system uid " + callingUid); 1246 return true; 1247 } 1248 final PackageSetting callingPkgSetting; 1249 final ArraySet<PackageSetting> callingSharedPkgSettings; 1250 if (DEBUG_TRACING) { 1251 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof"); 1252 } 1253 if (callingSetting instanceof PackageSetting) { 1254 if (((PackageSetting) callingSetting).sharedUser == null) { 1255 callingPkgSetting = (PackageSetting) callingSetting; 1256 callingSharedPkgSettings = null; 1257 } else { 1258 callingPkgSetting = null; 1259 callingSharedPkgSettings = 1260 ((PackageSetting) callingSetting).sharedUser.packages; 1261 } 1262 } else { 1263 callingPkgSetting = null; 1264 callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages; 1265 } 1266 if (DEBUG_TRACING) { 1267 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1268 } 1269 1270 if (callingPkgSetting != null) { 1271 if (callingPkgSetting.pkg != null 1272 && !mFeatureConfig.packageIsEnabled(callingPkgSetting.pkg)) { 1273 if (DEBUG_LOGGING) { 1274 log(callingSetting, targetPkgSetting, "DISABLED"); 1275 } 1276 return false; 1277 } 1278 } else { 1279 for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) { 1280 final AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).pkg; 1281 if (pkg != null && !mFeatureConfig.packageIsEnabled(pkg)) { 1282 if (DEBUG_LOGGING) { 1283 log(callingSetting, targetPkgSetting, "DISABLED"); 1284 } 1285 return false; 1286 } 1287 } 1288 } 1289 1290 if (DEBUG_TRACING) { 1291 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId"); 1292 } 1293 final int callingAppId; 1294 if (callingPkgSetting != null) { 1295 callingAppId = callingPkgSetting.appId; 1296 } else { 1297 callingAppId = callingSharedPkgSettings.valueAt(0).appId; // all should be the same 1298 } 1299 final int targetAppId = targetPkgSetting.appId; 1300 if (DEBUG_TRACING) { 1301 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1302 } 1303 if (callingAppId == targetAppId) { 1304 if (DEBUG_LOGGING) { 1305 log(callingSetting, targetPkgSetting, "same app id"); 1306 } 1307 return false; 1308 } 1309 1310 try { 1311 if (DEBUG_TRACING) { 1312 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages"); 1313 } 1314 if (callingPkgSetting != null) { 1315 if (callingPkgSetting.pkg != null 1316 && requestsQueryAllPackages(callingPkgSetting.pkg)) { 1317 return false; 1318 } 1319 } else { 1320 for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) { 1321 AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).pkg; 1322 if (pkg != null && requestsQueryAllPackages(pkg)) { 1323 return false; 1324 } 1325 } 1326 } 1327 } finally { 1328 if (DEBUG_TRACING) { 1329 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1330 } 1331 } 1332 1333 // This package isn't technically installed and won't be written to settings, so we can 1334 // treat it as filtered until it's available again. 1335 final AndroidPackage targetPkg = targetPkgSetting.pkg; 1336 if (targetPkg == null) { 1337 if (DEBUG_LOGGING) { 1338 Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null"); 1339 } 1340 return true; 1341 } 1342 if (targetPkg.isStaticSharedLibrary()) { 1343 // not an app, this filtering takes place at a higher level 1344 return false; 1345 } 1346 1347 try { 1348 if (DEBUG_TRACING) { 1349 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable"); 1350 } 1351 if (mForceQueryable.contains(targetAppId)) { 1352 if (DEBUG_LOGGING) { 1353 log(callingSetting, targetPkgSetting, "force queryable"); 1354 } 1355 return false; 1356 } 1357 } finally { 1358 if (DEBUG_TRACING) { 1359 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1360 } 1361 } 1362 try { 1363 if (DEBUG_TRACING) { 1364 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaPackage"); 1365 } 1366 if (mQueriesViaPackage.contains(callingAppId, targetAppId)) { 1367 if (DEBUG_LOGGING) { 1368 log(callingSetting, targetPkgSetting, "queries package"); 1369 } 1370 return false; 1371 } 1372 } finally { 1373 if (DEBUG_TRACING) { 1374 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1375 } 1376 } 1377 try { 1378 if (DEBUG_TRACING) { 1379 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent"); 1380 } 1381 if (mQueriesViaComponentRequireRecompute) { 1382 mStateProvider.runWithState((settings, users) -> { 1383 recomputeComponentVisibility(settings); 1384 }); 1385 } 1386 if (mQueriesViaComponent.contains(callingAppId, targetAppId)) { 1387 if (DEBUG_LOGGING) { 1388 log(callingSetting, targetPkgSetting, "queries component"); 1389 } 1390 return false; 1391 } 1392 } finally { 1393 if (DEBUG_TRACING) { 1394 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1395 } 1396 } 1397 1398 try { 1399 if (DEBUG_TRACING) { 1400 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable"); 1401 } 1402 final int targetUid = UserHandle.getUid(targetUserId, targetAppId); 1403 if (mImplicitlyQueryable.contains(callingUid, targetUid)) { 1404 if (DEBUG_LOGGING) { 1405 log(callingSetting, targetPkgSetting, "implicitly queryable for user"); 1406 } 1407 return false; 1408 } 1409 } finally { 1410 if (DEBUG_TRACING) { 1411 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1412 } 1413 } 1414 1415 try { 1416 if (DEBUG_TRACING) { 1417 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper"); 1418 } 1419 final String targetName = targetPkg.getPackageName(); 1420 if (callingSharedPkgSettings != null) { 1421 int size = callingSharedPkgSettings.size(); 1422 for (int index = 0; index < size; index++) { 1423 PackageSetting pkgSetting = callingSharedPkgSettings.valueAt(index); 1424 if (mOverlayReferenceMapper.isValidActor(targetName, pkgSetting.name)) { 1425 if (DEBUG_LOGGING) { 1426 log(callingPkgSetting, targetPkgSetting, 1427 "matches shared user of package that acts on target of " 1428 + "overlay"); 1429 } 1430 return false; 1431 } 1432 } 1433 } else { 1434 if (mOverlayReferenceMapper.isValidActor(targetName, callingPkgSetting.name)) { 1435 if (DEBUG_LOGGING) { 1436 log(callingPkgSetting, targetPkgSetting, "acts on target of overlay"); 1437 } 1438 return false; 1439 } 1440 } 1441 } finally { 1442 if (DEBUG_TRACING) { 1443 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1444 } 1445 } 1446 1447 try { 1448 if (DEBUG_TRACING) { 1449 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary"); 1450 } 1451 if (mQueryableViaUsesLibrary.contains(callingAppId, targetAppId)) { 1452 if (DEBUG_LOGGING) { 1453 log(callingSetting, targetPkgSetting, "queryable for library users"); 1454 } 1455 return false; 1456 } 1457 } finally { 1458 if (DEBUG_TRACING) { 1459 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1460 } 1461 } 1462 1463 return true; 1464 } finally { 1465 if (DEBUG_TRACING) { 1466 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1467 } 1468 } 1469 } 1470 1471 1472 private static boolean requestsQueryAllPackages(@NonNull AndroidPackage pkg) { 1473 // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the 1474 // package directly 1475 return pkg.getRequestedPermissions().contains( 1476 Manifest.permission.QUERY_ALL_PACKAGES); 1477 } 1478 1479 /** Returns {@code true} if the source package instruments the target package. */ 1480 private static boolean pkgInstruments( 1481 @NonNull AndroidPackage source, @NonNull AndroidPackage target) { 1482 try { 1483 if (DEBUG_TRACING) { 1484 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "pkgInstruments"); 1485 } 1486 final String packageName = target.getPackageName(); 1487 final List<ParsedInstrumentation> inst = source.getInstrumentations(); 1488 for (int i = ArrayUtils.size(inst) - 1; i >= 0; i--) { 1489 if (Objects.equals(inst.get(i).getTargetPackage(), packageName)) { 1490 return true; 1491 } 1492 } 1493 return false; 1494 } finally { 1495 if (DEBUG_TRACING) { 1496 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); 1497 } 1498 } 1499 } 1500 1501 private static void log(SettingBase callingSetting, PackageSetting targetPkgSetting, 1502 String description) { 1503 Slog.i(TAG, 1504 "interaction: " + (callingSetting == null ? "system" : callingSetting) + " -> " 1505 + targetPkgSetting + " " + description); 1506 } 1507 1508 public void dumpQueries( 1509 PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users, 1510 QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid) { 1511 final SparseArray<String> cache = new SparseArray<>(); 1512 ToString<Integer> expandPackages = input -> { 1513 String cachedValue = cache.get(input); 1514 if (cachedValue == null) { 1515 final int callingUid = Binder.getCallingUid(); 1516 final int appId = UserHandle.getAppId(input); 1517 String[] packagesForUid = null; 1518 for (int i = 0, size = users.length; packagesForUid == null && i < size; i++) { 1519 packagesForUid = getPackagesForUid.apply(callingUid, users[i], appId, 1520 false /*isCallerInstantApp*/); 1521 } 1522 if (packagesForUid == null) { 1523 cachedValue = "[app id " + input + " not installed]"; 1524 } else { 1525 cachedValue = packagesForUid.length == 1 ? packagesForUid[0] 1526 : "[" + TextUtils.join(",", packagesForUid) + "]"; 1527 } 1528 cache.put(input, cachedValue); 1529 } 1530 return cachedValue; 1531 }; 1532 pw.println(); 1533 pw.println("Queries:"); 1534 dumpState.onTitlePrinted(); 1535 if (!mFeatureConfig.isGloballyEnabled()) { 1536 pw.println(" DISABLED"); 1537 if (!DEBUG_LOGGING) { 1538 return; 1539 } 1540 } 1541 pw.println(" system apps queryable: " + mSystemAppsQueryable); 1542 dumpPackageSet(pw, filteringAppId, mForceQueryable, "forceQueryable", " ", expandPackages); 1543 pw.println(" queries via package name:"); 1544 dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, " ", expandPackages); 1545 pw.println(" queries via intent:"); 1546 dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, " ", expandPackages); 1547 pw.println(" queryable via interaction:"); 1548 for (int user : users) { 1549 pw.append(" User ").append(Integer.toString(user)).println(":"); 1550 dumpQueriesMap(pw, 1551 filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId), 1552 mImplicitlyQueryable, " ", expandPackages); 1553 } 1554 pw.println(" queryable via uses-library:"); 1555 dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, " ", expandPackages); 1556 } 1557 1558 private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId, 1559 SparseSetArray<Integer> queriesMap, String spacing, 1560 @Nullable ToString<Integer> toString) { 1561 for (int i = 0; i < queriesMap.size(); i++) { 1562 Integer callingId = queriesMap.keyAt(i); 1563 if (Objects.equals(callingId, filteringId)) { 1564 // don't filter target package names if the calling is filteringId 1565 dumpPackageSet( 1566 pw, null /*filteringId*/, queriesMap.get(callingId), 1567 toString == null 1568 ? callingId.toString() 1569 : toString.toString(callingId), 1570 spacing, toString); 1571 } else { 1572 dumpPackageSet( 1573 pw, filteringId, queriesMap.get(callingId), 1574 toString == null 1575 ? callingId.toString() 1576 : toString.toString(callingId), 1577 spacing, toString); 1578 } 1579 } 1580 } 1581 1582 private interface ToString<T> { 1583 String toString(T input); 1584 } 1585 1586 private static <T> void dumpPackageSet(PrintWriter pw, @Nullable T filteringId, 1587 Set<T> targetPkgSet, String subTitle, String spacing, 1588 @Nullable ToString<T> toString) { 1589 if (targetPkgSet != null && targetPkgSet.size() > 0 1590 && (filteringId == null || targetPkgSet.contains(filteringId))) { 1591 pw.append(spacing).append(subTitle).println(":"); 1592 for (T item : targetPkgSet) { 1593 if (filteringId == null || Objects.equals(filteringId, item)) { 1594 pw.append(spacing).append(" ") 1595 .println(toString == null ? item : toString.toString(item)); 1596 } 1597 } 1598 } 1599 } 1600 } 1601