1 /*
2  * Copyright (C) 2022 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 
21 import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
22 import static com.android.server.pm.AppsFilterUtils.canQueryViaComponents;
23 import static com.android.server.pm.AppsFilterUtils.requestsQueryAllPackages;
24 
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.content.pm.SigningDetails;
28 import android.os.Binder;
29 import android.os.Handler;
30 import android.os.Process;
31 import android.os.Trace;
32 import android.os.UserHandle;
33 import android.text.TextUtils;
34 import android.util.ArrayMap;
35 import android.util.ArraySet;
36 import android.util.Slog;
37 import android.util.SparseArray;
38 
39 import com.android.internal.annotations.VisibleForTesting;
40 import com.android.internal.util.function.QuadFunction;
41 import com.android.server.om.OverlayReferenceMapper;
42 import com.android.server.pm.pkg.AndroidPackage;
43 import com.android.server.pm.pkg.PackageStateInternal;
44 import com.android.server.pm.pkg.SharedUserApi;
45 import com.android.server.pm.snapshot.PackageDataSnapshot;
46 import com.android.server.utils.SnapshotCache;
47 import com.android.server.utils.Watched;
48 import com.android.server.utils.WatchedArrayMap;
49 import com.android.server.utils.WatchedArraySet;
50 import com.android.server.utils.WatchedSparseBooleanMatrix;
51 import com.android.server.utils.WatchedSparseSetArray;
52 
53 import java.io.PrintWriter;
54 import java.util.Arrays;
55 import java.util.Objects;
56 import java.util.concurrent.atomic.AtomicBoolean;
57 
58 /**
59  * AppsFilter is the entity responsible for filtering visibility between apps based on declarations
60  * in their manifests. This class implements the unlocked, read-only methods of AppsFilter.
61  * See {@link AppsFilterImpl} for the write methods that updates the internal structures.
62  */
63 public abstract class AppsFilterBase implements AppsFilterSnapshot {
64     protected static final String TAG = "AppsFilter";
65 
66     // Logs all filtering instead of enforcing
67     protected static final boolean DEBUG_ALLOW_ALL = false;
68     protected static final boolean DEBUG_LOGGING = false;
69     public static final boolean DEBUG_TRACING = false;
70 
71     // Allow some time for cache rebuilds.
72     protected static final int CACHE_REBUILD_DELAY_MIN_MS = 10000;
73     // With each new rebuild the delay doubles until it reaches max delay.
74     protected static final int CACHE_REBUILD_DELAY_MAX_MS = 10000;
75 
76     /**
77      * This contains a list of app UIDs that are implicitly queryable because another app explicitly
78      * interacted with it. For example, if application A starts a service in application B,
79      * application B is implicitly allowed to query for application A; regardless of any manifest
80      * entries.
81      */
82     @NonNull
83     @Watched
84     protected WatchedSparseSetArray<Integer> mImplicitlyQueryable;
85     @NonNull
86     protected SnapshotCache<WatchedSparseSetArray<Integer>> mImplicitQueryableSnapshot;
87 
88     /**
89      * This contains a list of app UIDs that are implicitly queryable because another app explicitly
90      * interacted with it, but could keep across package updates. For example, if application A
91      * grants persistable uri permission to application B; regardless of any manifest entries.
92      */
93     @NonNull
94     @Watched
95     protected WatchedSparseSetArray<Integer> mRetainedImplicitlyQueryable;
96     @NonNull
97     protected SnapshotCache<WatchedSparseSetArray<Integer>> mRetainedImplicitlyQueryableSnapshot;
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     @NonNull
104     @Watched
105     protected WatchedSparseSetArray<Integer> mQueriesViaPackage;
106     @NonNull
107     protected SnapshotCache<WatchedSparseSetArray<Integer>> mQueriesViaPackageSnapshot;
108 
109     /**
110      * A mapping from the set of App IDs that query others via component match to the list
111      * of packages that the they resolve to.
112      */
113     @NonNull
114     @Watched
115     protected WatchedSparseSetArray<Integer> mQueriesViaComponent;
116     @NonNull
117     protected SnapshotCache<WatchedSparseSetArray<Integer>> mQueriesViaComponentSnapshot;
118 
119     /**
120      * A mapping from the set of App IDs that query other App IDs via library name to the
121      * list of packages that they can see.
122      */
123     @NonNull
124     @Watched
125     protected WatchedSparseSetArray<Integer> mQueryableViaUsesLibrary;
126     @NonNull
127     protected SnapshotCache<WatchedSparseSetArray<Integer>> mQueryableViaUsesLibrarySnapshot;
128 
129     /**
130      * A mapping from the set of App IDs that query other App IDs via custom permissions to the
131      * list of packages that they can see.
132      */
133     @NonNull
134     @Watched
135     protected WatchedSparseSetArray<Integer> mQueryableViaUsesPermission;
136     @NonNull
137     protected SnapshotCache<WatchedSparseSetArray<Integer>> mQueryableViaUsesPermissionSnapshot;
138 
139     /**
140      * Handler for running tasks such as building the initial visibility cache.
141      */
142     protected Handler mHandler;
143 
144     /**
145      * Pending full recompute of mQueriesViaComponent. Occurs when a package adds a new set of
146      * protected broadcast. This in turn invalidates all prior additions and require a very
147      * computationally expensive recomputing.
148      * Full recompute is done lazily at the point when we use mQueriesViaComponent to filter apps.
149      */
150     protected AtomicBoolean mQueriesViaComponentRequireRecompute = new AtomicBoolean(false);
151 
152     /**
153      * A set of App IDs that are always queryable by any package, regardless of their manifest
154      * content.
155      */
156     @NonNull
157     @Watched
158     protected WatchedArraySet<Integer> mForceQueryable;
159     @NonNull
160     protected SnapshotCache<WatchedArraySet<Integer>> mForceQueryableSnapshot;
161 
162     /**
163      * The set of package names provided by the device that should be force queryable regardless of
164      * their manifest contents.
165      */
166     @NonNull
167     protected String[] mForceQueryableByDevicePackageNames;
168     @NonNull
169     /** True if all system apps should be made queryable by default. */
170     protected boolean mSystemAppsQueryable;
171     @NonNull
172     protected FeatureConfig mFeatureConfig;
173     @NonNull
174     protected OverlayReferenceMapper mOverlayReferenceMapper;
175     @Nullable
176     protected SigningDetails mSystemSigningDetails;
177 
178     @NonNull
179     @Watched
180     protected WatchedArraySet<String> mProtectedBroadcasts;
181     @NonNull
182     protected SnapshotCache<WatchedArraySet<String>> mProtectedBroadcastsSnapshot;
183 
184     /**
185      * This structure maps uid -> uid and indicates whether access from the first should be
186      * filtered to the second. It's essentially a cache of the
187      * {@link #shouldFilterApplicationInternal(PackageDataSnapshot, int, Object,
188      * PackageStateInternal, int)} call.
189      * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on
190      * initial scam and is empty until {@link #mCacheReady} is true.
191      */
192     @NonNull
193     @Watched
194     protected WatchedSparseBooleanMatrix mShouldFilterCache;
195     @NonNull
196     protected SnapshotCache<WatchedSparseBooleanMatrix> mShouldFilterCacheSnapshot;
197 
198     protected volatile boolean mCacheReady = false;
199     protected volatile boolean mCacheEnabled = true;
200 
201     protected static final boolean CACHE_VALID = true;
202     protected static final boolean CACHE_INVALID = false;
203     protected AtomicBoolean mCacheValid = new AtomicBoolean(CACHE_INVALID);
204 
isForceQueryable(int callingAppId)205     protected boolean isForceQueryable(int callingAppId) {
206         return mForceQueryable.contains(callingAppId);
207     }
208 
isQueryableViaPackage(int callingAppId, int targetAppId)209     protected boolean isQueryableViaPackage(int callingAppId, int targetAppId) {
210         return mQueriesViaPackage.contains(callingAppId, targetAppId);
211     }
212 
isQueryableViaComponent(int callingAppId, int targetAppId)213     protected boolean isQueryableViaComponent(int callingAppId, int targetAppId) {
214         return mQueriesViaComponent.contains(callingAppId, targetAppId);
215     }
216 
isImplicitlyQueryable(int callingUid, int targetUid)217     protected boolean isImplicitlyQueryable(int callingUid, int targetUid) {
218         return mImplicitlyQueryable.contains(callingUid, targetUid);
219     }
220 
isRetainedImplicitlyQueryable(int callingUid, int targetUid)221     protected boolean isRetainedImplicitlyQueryable(int callingUid, int targetUid) {
222         return mRetainedImplicitlyQueryable.contains(callingUid, targetUid);
223     }
224 
isQueryableViaUsesLibrary(int callingAppId, int targetAppId)225     protected boolean isQueryableViaUsesLibrary(int callingAppId, int targetAppId) {
226         return mQueryableViaUsesLibrary.contains(callingAppId, targetAppId);
227     }
228 
isQueryableViaUsesPermission(int callingAppId, int targetAppId)229     protected boolean isQueryableViaUsesPermission(int callingAppId, int targetAppId) {
230         return mQueryableViaUsesPermission.contains(callingAppId, targetAppId);
231     }
232 
isQueryableViaComponentWhenRequireRecompute( ArrayMap<String, ? extends PackageStateInternal> existingSettings, PackageStateInternal callingPkgSetting, ArraySet<PackageStateInternal> callingSharedPkgSettings, AndroidPackage targetPkg, int callingAppId, int targetAppId)233     protected boolean isQueryableViaComponentWhenRequireRecompute(
234             ArrayMap<String, ? extends PackageStateInternal> existingSettings,
235             PackageStateInternal callingPkgSetting,
236             ArraySet<PackageStateInternal> callingSharedPkgSettings,
237             AndroidPackage targetPkg,
238             int callingAppId, int targetAppId) {
239         // Do no recompute or use mQueriesViaComponent if it's stale in snapshot
240         // Since we know we are in the snapshot, no need to acquire mLock because
241         // mProtectedBroadcasts will not change
242         if (callingPkgSetting != null) {
243             if (callingPkgSetting.getPkg() != null
244                     && canQueryViaComponents(callingPkgSetting.getPkg(), targetPkg,
245                     mProtectedBroadcasts)) {
246                 return true;
247             }
248         } else {
249             for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
250                 final AndroidPackage pkg =
251                         callingSharedPkgSettings.valueAt(i).getPkg();
252                 if (pkg != null && canQueryViaComponents(pkg, targetPkg,
253                         mProtectedBroadcasts)) {
254                     return true;
255                 }
256             }
257         }
258         return false;
259     }
260 
261     /**
262      * See {@link AppsFilterSnapshot#getVisibilityAllowList(PackageDataSnapshot,
263      * PackageStateInternal, int[], ArrayMap)}
264      */
265     @Override
266     @Nullable
getVisibilityAllowList(PackageDataSnapshot snapshot, PackageStateInternal setting, int[] users, ArrayMap<String, ? extends PackageStateInternal> existingSettings)267     public SparseArray<int[]> getVisibilityAllowList(PackageDataSnapshot snapshot,
268             PackageStateInternal setting, int[] users,
269             ArrayMap<String, ? extends PackageStateInternal> existingSettings) {
270         if (isForceQueryable(setting.getAppId())) {
271             return null;
272         }
273         // let's reserve max memory to limit the number of allocations
274         SparseArray<int[]> result = new SparseArray<>(users.length);
275         for (int u = 0; u < users.length; u++) {
276             final int userId = users[u];
277             int[] appIds = new int[existingSettings.size()];
278             int[] buffer = null;
279             int allowListSize = 0;
280             for (int i = existingSettings.size() - 1; i >= 0; i--) {
281                 final PackageStateInternal existingSetting = existingSettings.valueAt(i);
282                 final int existingAppId = existingSetting.getAppId();
283                 if (existingAppId < Process.FIRST_APPLICATION_UID) {
284                     continue;
285                 }
286                 final int loc = Arrays.binarySearch(appIds, 0, allowListSize, existingAppId);
287                 if (loc >= 0) {
288                     continue;
289                 }
290                 final int existingUid = UserHandle.getUid(userId, existingAppId);
291                 if (!shouldFilterApplication(snapshot, existingUid, existingSetting, setting,
292                         userId)) {
293                     if (buffer == null) {
294                         buffer = new int[appIds.length];
295                     }
296                     final int insert = ~loc;
297                     System.arraycopy(appIds, insert, buffer, 0, allowListSize - insert);
298                     appIds[insert] = existingAppId;
299                     System.arraycopy(buffer, 0, appIds, insert + 1, allowListSize - insert);
300                     allowListSize++;
301                 }
302             }
303             result.put(userId, Arrays.copyOf(appIds, allowListSize));
304         }
305         return result;
306     }
307 
308     /**
309      * This api does type conversion on the <existingSettings> parameter.
310      */
311     @VisibleForTesting(visibility = PRIVATE)
312     @Nullable
getVisibilityAllowList(PackageDataSnapshot snapshot, PackageStateInternal setting, int[] users, WatchedArrayMap<String, ? extends PackageStateInternal> existingSettings)313     SparseArray<int[]> getVisibilityAllowList(PackageDataSnapshot snapshot,
314             PackageStateInternal setting, int[] users,
315             WatchedArrayMap<String, ? extends PackageStateInternal> existingSettings) {
316         return getVisibilityAllowList(snapshot, setting, users,
317                 existingSettings.untrackedStorage());
318     }
319 
320     /**
321      * See
322      * {@link AppsFilterSnapshot#shouldFilterApplication(PackageDataSnapshot, int, Object,
323      * PackageStateInternal, int)}
324      */
325     @Override
shouldFilterApplication(PackageDataSnapshot snapshot, int callingUid, @Nullable Object callingSetting, PackageStateInternal targetPkgSetting, int userId)326     public boolean shouldFilterApplication(PackageDataSnapshot snapshot, int callingUid,
327             @Nullable Object callingSetting, PackageStateInternal targetPkgSetting, int userId) {
328         if (DEBUG_TRACING) {
329             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
330         }
331         try {
332             int callingAppId = UserHandle.getAppId(callingUid);
333             if (callingAppId < Process.FIRST_APPLICATION_UID
334                     || targetPkgSetting.getAppId() < Process.FIRST_APPLICATION_UID
335                     || callingAppId == targetPkgSetting.getAppId()) {
336                 return false;
337             } else if (Process.isSdkSandboxUid(callingAppId)) {
338                 final int targetAppId = targetPkgSetting.getAppId();
339                 final int targetUid = UserHandle.getUid(userId, targetAppId);
340                 // we only allow sdk sandbox processes access to forcequeryable packages
341                 return !isForceQueryable(targetPkgSetting.getAppId())
342                       && !isImplicitlyQueryable(callingUid, targetUid);
343             }
344             // use cache
345             if (mCacheReady && mCacheEnabled) {
346                 if (!shouldFilterApplicationUsingCache(callingUid,
347                         targetPkgSetting.getAppId(),
348                         userId)) {
349                     return false;
350                 }
351             } else {
352                 if (!shouldFilterApplicationInternal((Computer) snapshot,
353                         callingUid, callingSetting, targetPkgSetting, userId)) {
354                     return false;
355                 }
356             }
357             if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(callingAppId)) {
358                 log(callingSetting, targetPkgSetting, "BLOCKED");
359             }
360             return !DEBUG_ALLOW_ALL;
361         } finally {
362             if (DEBUG_TRACING) {
363                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
364             }
365         }
366     }
367 
shouldFilterApplicationUsingCache(int callingUid, int appId, int userId)368     protected boolean shouldFilterApplicationUsingCache(int callingUid, int appId, int userId) {
369         final int callingIndex = mShouldFilterCache.indexOfKey(callingUid);
370         if (callingIndex < 0) {
371             Slog.wtf(TAG, "Encountered calling uid with no cached rules: "
372                     + callingUid);
373             return true;
374         }
375         final int targetUid = UserHandle.getUid(userId, appId);
376         final int targetIndex = mShouldFilterCache.indexOfKey(targetUid);
377         if (targetIndex < 0) {
378             Slog.w(TAG, "Encountered calling -> target with no cached rules: "
379                     + callingUid + " -> " + targetUid);
380             return true;
381         }
382         return mShouldFilterCache.valueAt(callingIndex, targetIndex);
383     }
384 
shouldFilterApplicationInternal(Computer snapshot, int callingUid, Object callingSetting, PackageStateInternal targetPkgSetting, int targetUserId)385     protected boolean shouldFilterApplicationInternal(Computer snapshot, int callingUid,
386             Object callingSetting, PackageStateInternal targetPkgSetting, int targetUserId) {
387         if (DEBUG_TRACING) {
388             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal");
389         }
390         try {
391             final boolean featureEnabled = mFeatureConfig.isGloballyEnabled();
392             if (!featureEnabled) {
393                 if (DEBUG_LOGGING) {
394                     Slog.d(TAG, "filtering disabled; skipped");
395                 }
396                 return false;
397             }
398             if (callingSetting == null) {
399                 Slog.wtf(TAG, "No setting found for non system uid " + callingUid);
400                 return true;
401             }
402 
403             if (DEBUG_TRACING) {
404                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "getAppId");
405             }
406             final int callingAppId = UserHandle.getAppId(callingUid);
407             final int targetAppId = targetPkgSetting.getAppId();
408             if (DEBUG_TRACING) {
409                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
410             }
411             if (callingAppId == targetAppId
412                     || callingAppId < Process.FIRST_APPLICATION_UID
413                     || targetAppId < Process.FIRST_APPLICATION_UID) {
414                 if (DEBUG_LOGGING) {
415                     log(callingSetting, targetPkgSetting, "same app id or core app id");
416                 }
417                 return false;
418             }
419 
420             final PackageStateInternal callingPkgSetting;
421             if (DEBUG_TRACING) {
422                 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof");
423             }
424             final ArraySet<PackageStateInternal> callingSharedPkgSettings = new ArraySet<>();
425 
426             if (callingSetting instanceof PackageStateInternal) {
427                 final PackageStateInternal packageState = (PackageStateInternal) callingSetting;
428                 if (packageState.hasSharedUser()) {
429                     callingPkgSetting = null;
430                     final SharedUserApi sharedUserApi =
431                             snapshot.getSharedUser(packageState.getSharedUserAppId());
432                     if (sharedUserApi != null) {
433                         callingSharedPkgSettings.addAll(sharedUserApi.getPackageStates());
434                     }
435                 } else {
436                     callingPkgSetting = packageState;
437                 }
438             } else {
439                 callingPkgSetting = null;
440                 callingSharedPkgSettings.addAll(
441                         ((SharedUserSetting) callingSetting).getPackageStates());
442             }
443             if (DEBUG_TRACING) {
444                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
445             }
446 
447             if (callingPkgSetting != null) {
448                 if (callingPkgSetting.getPkg() != null
449                         && !mFeatureConfig.packageIsEnabled(callingPkgSetting.getPkg())) {
450                     if (DEBUG_LOGGING) {
451                         log(callingSetting, targetPkgSetting, "DISABLED");
452                     }
453                     return false;
454                 }
455             } else {
456                 for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
457                     final AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).getPkg();
458                     if (pkg != null && !mFeatureConfig.packageIsEnabled(pkg)) {
459                         if (DEBUG_LOGGING) {
460                             log(callingSetting, targetPkgSetting, "DISABLED");
461                         }
462                         return false;
463                     }
464                 }
465             }
466 
467             try {
468                 if (DEBUG_TRACING) {
469                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages");
470                 }
471                 if (callingPkgSetting != null) {
472                     if (callingPkgSetting.getPkg() != null
473                             && requestsQueryAllPackages(callingPkgSetting.getPkg())) {
474                         return false;
475                     }
476                 } else {
477                     for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) {
478                         AndroidPackage pkg = callingSharedPkgSettings.valueAt(i).getPkg();
479                         if (pkg != null && requestsQueryAllPackages(pkg)) {
480                             return false;
481                         }
482                     }
483                 }
484             } finally {
485                 if (DEBUG_TRACING) {
486                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
487                 }
488             }
489 
490             // This package isn't technically installed and won't be written to settings, so we can
491             // treat it as filtered until it's available again.
492             final AndroidPackage targetPkg = targetPkgSetting.getPkg();
493             if (targetPkg == null) {
494                 if (DEBUG_LOGGING) {
495                     Slog.wtf(TAG, "shouldFilterApplication: " + "targetPkg is null");
496                 }
497                 return true;
498             }
499             if (targetPkg.isStaticSharedLibrary()) {
500                 // not an app, this filtering takes place at a higher level
501                 return false;
502             }
503 
504             try {
505                 if (DEBUG_TRACING) {
506                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mForceQueryable");
507                 }
508                 if (isForceQueryable(targetAppId)) {
509                     if (DEBUG_LOGGING) {
510                         log(callingSetting, targetPkgSetting, "force queryable");
511                     }
512                     return false;
513                 }
514             } finally {
515                 if (DEBUG_TRACING) {
516                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
517                 }
518             }
519             try {
520                 if (DEBUG_TRACING) {
521                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaPackage");
522                 }
523                 if (isQueryableViaPackage(callingAppId, targetAppId)) {
524                     if (DEBUG_LOGGING) {
525                         log(callingSetting, targetPkgSetting, "queries package");
526                     }
527                     return false;
528                 }
529             } finally {
530                 if (DEBUG_TRACING) {
531                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
532                 }
533             }
534             try {
535                 if (DEBUG_TRACING) {
536                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueriesViaComponent");
537                 }
538                 if (!mQueriesViaComponentRequireRecompute.get()) {
539                     if (isQueryableViaComponent(callingAppId, targetAppId)) {
540                         if (DEBUG_LOGGING) {
541                             log(callingSetting, targetPkgSetting, "queries component");
542                         }
543                         return false;
544                     }
545                 } else { // mQueriesViaComponent is stale
546                     if (isQueryableViaComponentWhenRequireRecompute(snapshot.getPackageStates(),
547                             callingPkgSetting, callingSharedPkgSettings, targetPkg,
548                             callingAppId, targetAppId)) {
549                         if (DEBUG_LOGGING) {
550                             log(callingSetting, targetPkgSetting, "queries component");
551                         }
552                         return false;
553                     }
554                 }
555             } finally {
556                 if (DEBUG_TRACING) {
557                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
558                 }
559             }
560 
561             try {
562                 if (DEBUG_TRACING) {
563                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable");
564                 }
565                 final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
566                 if (isImplicitlyQueryable(callingUid, targetUid)) {
567                     if (DEBUG_LOGGING) {
568                         log(callingSetting, targetPkgSetting, "implicitly queryable for user");
569                     }
570                     return false;
571                 }
572             } finally {
573                 if (DEBUG_TRACING) {
574                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
575                 }
576             }
577 
578             try {
579                 if (DEBUG_TRACING) {
580                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mRetainedImplicitlyQueryable");
581                 }
582                 final int targetUid = UserHandle.getUid(targetUserId, targetAppId);
583                 if (isRetainedImplicitlyQueryable(callingUid, targetUid)) {
584                     if (DEBUG_LOGGING) {
585                         log(callingSetting, targetPkgSetting,
586                                 "retained implicitly queryable for user");
587                     }
588                     return false;
589                 }
590             } finally {
591                 if (DEBUG_TRACING) {
592                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
593                 }
594             }
595 
596             try {
597                 if (DEBUG_TRACING) {
598                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mOverlayReferenceMapper");
599                 }
600                 final String targetName = targetPkg.getPackageName();
601                 if (!callingSharedPkgSettings.isEmpty()) {
602                     int size = callingSharedPkgSettings.size();
603                     for (int index = 0; index < size; index++) {
604                         PackageStateInternal pkgSetting = callingSharedPkgSettings.valueAt(index);
605                         if (mOverlayReferenceMapper.isValidActor(targetName,
606                                 pkgSetting.getPackageName())) {
607                             if (DEBUG_LOGGING) {
608                                 log(callingPkgSetting, targetPkgSetting,
609                                         "matches shared user of package that acts on target of "
610                                                 + "overlay");
611                             }
612                             return false;
613                         }
614                     }
615                 } else {
616                     if (mOverlayReferenceMapper.isValidActor(targetName,
617                             callingPkgSetting.getPackageName())) {
618                         if (DEBUG_LOGGING) {
619                             log(callingPkgSetting, targetPkgSetting, "acts on target of overlay");
620                         }
621                         return false;
622                     }
623                 }
624             } finally {
625                 if (DEBUG_TRACING) {
626                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
627                 }
628             }
629 
630             try {
631                 if (DEBUG_TRACING) {
632                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesLibrary");
633                 }
634                 if (isQueryableViaUsesLibrary(callingAppId, targetAppId)) {
635                     if (DEBUG_LOGGING) {
636                         log(callingSetting, targetPkgSetting, "queryable for library users");
637                     }
638                     return false;
639                 }
640             } finally {
641                 if (DEBUG_TRACING) {
642                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
643                 }
644             }
645 
646             try {
647                 if (DEBUG_TRACING) {
648                     Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mQueryableViaUsesPermission");
649                 }
650                 if (isQueryableViaUsesPermission(callingAppId, targetAppId)) {
651                     if (DEBUG_LOGGING) {
652                         log(callingSetting, targetPkgSetting, "queryable for permission users");
653                     }
654                     return false;
655                 }
656             } finally {
657                 if (DEBUG_TRACING) {
658                     Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
659                 }
660             }
661 
662             return true;
663         } finally {
664             if (DEBUG_TRACING) {
665                 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
666             }
667         }
668     }
669 
670     /**
671      * See {@link AppsFilterSnapshot#canQueryPackage(AndroidPackage, String)}
672      */
673     @Override
canQueryPackage(@onNull AndroidPackage querying, String potentialTarget)674     public boolean canQueryPackage(@NonNull AndroidPackage querying, String potentialTarget) {
675         int appId = UserHandle.getAppId(querying.getUid());
676         if (appId < Process.FIRST_APPLICATION_UID) {
677             return true;
678         }
679 
680         // Check if FILTER_APPLICATION_QUERY is enabled on the given package.
681         if (!mFeatureConfig.packageIsEnabled(querying)) {
682             return true;
683         }
684 
685         if (requestsQueryAllPackages(querying)) {
686             return true;
687         }
688 
689         return !querying.getQueriesPackages().isEmpty()
690                 && querying.getQueriesPackages().contains(potentialTarget);
691     }
692 
log(Object callingSetting, PackageStateInternal targetPkgSetting, String description)693     private static void log(Object callingSetting, PackageStateInternal targetPkgSetting,
694             String description) {
695         Slog.i(TAG,
696                 "interaction: " + (callingSetting == null ? "system" : callingSetting) + " -> "
697                         + targetPkgSetting + " " + description);
698     }
699 
700     /**
701      * See {@link AppsFilterSnapshot#dumpQueries(PrintWriter, Integer, DumpState, int[],
702      * QuadFunction)}
703      */
704     @Override
dumpQueries( PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users, QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid)705     public void dumpQueries(
706             PrintWriter pw, @Nullable Integer filteringAppId, DumpState dumpState, int[] users,
707             QuadFunction<Integer, Integer, Integer, Boolean, String[]> getPackagesForUid) {
708         final SparseArray<String> cache = new SparseArray<>();
709         ToString<Integer> expandPackages = input -> {
710             String cachedValue = cache.get(input);
711             if (cachedValue == null) {
712                 final int callingUid = Binder.getCallingUid();
713                 final int appId = UserHandle.getAppId(input);
714                 String[] packagesForUid = null;
715                 for (int i = 0, size = users.length; packagesForUid == null && i < size; i++) {
716                     packagesForUid = getPackagesForUid.apply(callingUid, users[i], appId,
717                             false /*isCallerInstantApp*/);
718                 }
719                 if (packagesForUid == null) {
720                     cachedValue = "[app id " + input + " not installed]";
721                 } else {
722                     cachedValue = packagesForUid.length == 1 ? packagesForUid[0]
723                             : "[" + TextUtils.join(",", packagesForUid) + "]";
724                 }
725                 cache.put(input, cachedValue);
726             }
727             return cachedValue;
728         };
729         pw.println();
730         pw.println("Queries:");
731         dumpState.onTitlePrinted();
732         if (!mFeatureConfig.isGloballyEnabled()) {
733             pw.println("  DISABLED");
734             if (!DEBUG_LOGGING) {
735                 return;
736             }
737         }
738         pw.println("  system apps queryable: " + mSystemAppsQueryable);
739         dumpForceQueryable(pw, filteringAppId, expandPackages);
740         dumpQueriesViaPackage(pw, filteringAppId, expandPackages);
741         dumpQueriesViaComponent(pw, filteringAppId, expandPackages);
742         dumpQueriesViaImplicitlyQueryable(pw, filteringAppId, users, expandPackages);
743         dumpQueriesViaUsesLibrary(pw, filteringAppId, expandPackages);
744     }
745 
dumpForceQueryable(PrintWriter pw, @Nullable Integer filteringAppId, ToString<Integer> expandPackages)746     protected void dumpForceQueryable(PrintWriter pw, @Nullable Integer filteringAppId,
747             ToString<Integer> expandPackages) {
748         pw.println("  queries via forceQueryable:");
749         dumpPackageSet(pw, filteringAppId, mForceQueryable.untrackedStorage(),
750                 "forceQueryable", "  ", expandPackages);
751     }
752 
dumpQueriesViaPackage(PrintWriter pw, @Nullable Integer filteringAppId, ToString<Integer> expandPackages)753     protected void dumpQueriesViaPackage(PrintWriter pw, @Nullable Integer filteringAppId,
754             ToString<Integer> expandPackages) {
755         pw.println("  queries via package name:");
756         dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, "    ", expandPackages);
757     }
758 
dumpQueriesViaComponent(PrintWriter pw, @Nullable Integer filteringAppId, ToString<Integer> expandPackages)759     protected void dumpQueriesViaComponent(PrintWriter pw, @Nullable Integer filteringAppId,
760             ToString<Integer> expandPackages) {
761         pw.println("  queries via component:");
762         dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, "    ", expandPackages);
763     }
764 
dumpQueriesViaImplicitlyQueryable(PrintWriter pw, @Nullable Integer filteringAppId, int[] users, ToString<Integer> expandPackages)765     protected void dumpQueriesViaImplicitlyQueryable(PrintWriter pw,
766             @Nullable Integer filteringAppId, int[] users, ToString<Integer> expandPackages) {
767         pw.println("  queryable via interaction:");
768         for (int user : users) {
769             pw.append("    User ").append(Integer.toString(user)).println(":");
770             dumpQueriesMap(pw,
771                     filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
772                     mImplicitlyQueryable, "      ", expandPackages);
773             dumpQueriesMap(pw,
774                     filteringAppId == null ? null : UserHandle.getUid(user, filteringAppId),
775                     mRetainedImplicitlyQueryable, "      ", expandPackages);
776         }
777     }
778 
dumpQueriesViaUsesLibrary(PrintWriter pw, @Nullable Integer filteringAppId, ToString<Integer> expandPackages)779     protected void dumpQueriesViaUsesLibrary(PrintWriter pw, @Nullable Integer filteringAppId,
780             ToString<Integer> expandPackages) {
781         pw.println("  queryable via uses-library:");
782         dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesLibrary, "    ",
783                 expandPackages);
784     }
785 
dumpQueriesViaUsesPermission(PrintWriter pw, @Nullable Integer filteringAppId, ToString<Integer> expandPackages)786     protected void dumpQueriesViaUsesPermission(PrintWriter pw, @Nullable Integer filteringAppId,
787             ToString<Integer> expandPackages) {
788         pw.println("  queryable via uses-permission:");
789         dumpQueriesMap(pw, filteringAppId, mQueryableViaUsesPermission, "    ",
790                 expandPackages);
791     }
792 
dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId, WatchedSparseSetArray<Integer> queriesMap, String spacing, @Nullable ToString<Integer> toString)793     private static void dumpQueriesMap(PrintWriter pw, @Nullable Integer filteringId,
794             WatchedSparseSetArray<Integer> queriesMap, String spacing,
795             @Nullable ToString<Integer> toString) {
796         for (int i = 0; i < queriesMap.size(); i++) {
797             Integer callingId = queriesMap.keyAt(i);
798             if (Objects.equals(callingId, filteringId)) {
799                 // don't filter target package names if the calling is filteringId
800                 dumpPackageSet(
801                         pw, null /*filteringId*/, queriesMap.get(callingId),
802                         toString == null
803                                 ? callingId.toString()
804                                 : toString.toString(callingId),
805                         spacing, toString);
806             } else {
807                 dumpPackageSet(
808                         pw, filteringId, queriesMap.get(callingId),
809                         toString == null
810                                 ? callingId.toString()
811                                 : toString.toString(callingId),
812                         spacing, toString);
813             }
814         }
815     }
816 
817     protected interface ToString<T> {
toString(T input)818         String toString(T input);
819     }
820 
dumpPackageSet(PrintWriter pw, @Nullable T filteringId, ArraySet<T> targetPkgSet, String subTitle, String spacing, @Nullable ToString<T> toString)821     private static <T> void dumpPackageSet(PrintWriter pw, @Nullable T filteringId,
822             ArraySet<T> targetPkgSet, String subTitle, String spacing,
823             @Nullable ToString<T> toString) {
824         if (targetPkgSet != null && targetPkgSet.size() > 0
825                 && (filteringId == null || targetPkgSet.contains(filteringId))) {
826             pw.append(spacing).append(subTitle).println(":");
827             for (T item : targetPkgSet) {
828                 if (filteringId == null || Objects.equals(filteringId, item)) {
829                     pw.append(spacing).append("  ")
830                             .println(toString == null ? item : toString.toString(item));
831                 }
832             }
833         }
834     }
835 }
836