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