From a7ad66d59a8ba0d8774e6c412d47b035991d779d Mon Sep 17 00:00:00 2001 From: Patrick Baumann Date: Mon, 12 Aug 2019 11:11:08 -0700 Subject: [PATCH] Adds app enumeration dumps This change adds app enumeration-related data to dumps / bug reports. Also realized that we were adding duplicates to the implicitly visible list and so moved everything to sets to guard against similar bugs / inefficiencies going forward. Test: manual Bug: 136675067 Change-Id: Id4f94c8b5bc3a2102bdc7d0083ad435bb053c6ad --- .../com/android/server/pm/AppsFilter.java | 71 ++++++++++++++++--- .../java/com/android/server/pm/DumpState.java | 1 + .../server/pm/PackageManagerService.java | 7 ++ .../java/com/android/server/pm/Settings.java | 7 ++ 4 files changed, 75 insertions(+), 11 deletions(-) diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index a6502a22f1ece..7b13720cfc7a2 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -36,12 +36,12 @@ import android.util.SparseArray; import com.android.internal.R; import com.android.server.FgThread; -import java.util.ArrayList; +import java.io.PrintWriter; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -69,20 +69,20 @@ class AppsFilter { * application B is implicitly allowed to query for application A; regardless of any manifest * entries. */ - private final SparseArray>> mImplicitlyQueryable = + private final SparseArray>> mImplicitlyQueryable = new SparseArray<>(); /** * A mapping from the set of packages that query other packages via package name to the * list of packages that they can see. */ - private final HashMap> mQueriesViaPackage = new HashMap<>(); + private final HashMap> mQueriesViaPackage = new HashMap<>(); /** * A mapping from the set of packages that query others via intent to the list * of packages that the intents resolve to. */ - private final HashMap> mQueriesViaIntent = new HashMap<>(); + private final HashMap> mQueriesViaIntent = new HashMap<>(); /** * A set of packages that are always queryable by any package, regardless of their manifest @@ -189,13 +189,13 @@ class AppsFilter { */ private void markAppInteraction( PackageSetting initiatingPackage, PackageSetting targetPackage, int userId) { - HashMap> currentUser = mImplicitlyQueryable.get(userId); + HashMap> currentUser = mImplicitlyQueryable.get(userId); if (currentUser == null) { currentUser = new HashMap<>(); mImplicitlyQueryable.put(userId, currentUser); } if (!currentUser.containsKey(targetPackage.pkg.packageName)) { - currentUser.put(targetPackage.pkg.packageName, new ArrayList<>()); + currentUser.put(targetPackage.pkg.packageName, new HashSet<>()); } currentUser.get(targetPackage.pkg.packageName).add(initiatingPackage.pkg.packageName); } @@ -224,7 +224,7 @@ class AppsFilter { } } // if the new package declares them, let's evaluate its ability to see existing packages - mQueriesViaIntent.put(newPkg.packageName, new ArrayList<>()); + mQueriesViaIntent.put(newPkg.packageName, new HashSet<>()); for (PackageParser.Package existingPackage : existing.values()) { if (existingPackage.packageName == newPkg.packageName) { continue; @@ -238,7 +238,7 @@ class AppsFilter { mQueriesViaIntent.get(newPkg.packageName).add(existingPackage.packageName); } } - final ArrayList queriesPackages = new ArrayList<>( + final HashSet queriesPackages = new HashSet<>( newPkg.mQueriesPackages == null ? 0 : newPkg.mQueriesPackages.size()); if (newPkg.mQueriesPackages != null) { queriesPackages.addAll(newPkg.mQueriesPackages); @@ -256,13 +256,13 @@ class AppsFilter { for (int i = 0; i < mImplicitlyQueryable.size(); i++) { mImplicitlyQueryable.valueAt(i).remove(packageName); - for (ArrayList initiators : mImplicitlyQueryable.valueAt(i).values()) { + for (Set initiators : mImplicitlyQueryable.valueAt(i).values()) { initiators.remove(packageName); } } mQueriesViaIntent.remove(packageName); - for (List declarators : mQueriesViaIntent.values()) { + for (Set declarators : mQueriesViaIntent.values()) { declarators.remove(packageName); } @@ -408,6 +408,55 @@ class AppsFilter { || mForceQueryableByDevice.contains(targetPkgSetting.pkg.packageName)); } + public void dumpQueries( + PrintWriter pw, @Nullable String filteringPackageName, DumpState dumpState, + int[] users) { + pw.println(); + pw.println("Queries:"); + dumpState.onTitlePrinted(); + pw.println(" enabled: " + mConfigProvider.isEnabled()); + pw.println(" system apps queryable: " + mSystemAppsQueryable); + dumpPackageSet(pw, filteringPackageName, mForceQueryableByDevice, "System whitelist", " "); + dumpPackageSet(pw, filteringPackageName, mForceQueryable, "forceQueryable", " "); + pw.println(" queries via package name:"); + dumpQueriesMap(pw, filteringPackageName, mQueriesViaPackage, " "); + pw.println(" queries via intent:"); + dumpQueriesMap(pw, filteringPackageName, mQueriesViaIntent, " "); + pw.println(" queryable via interaction:"); + for (int user : users) { + pw.append(" User ").append(Integer.toString(user)).println(":"); + final HashMap> queryMapForUser = mImplicitlyQueryable.get(user); + dumpQueriesMap(pw, filteringPackageName, queryMapForUser, " "); + } + } + + private static void dumpQueriesMap(PrintWriter pw, @Nullable String filteringPackageName, + HashMap> queriesMap, String spacing) { + for (String callingPkg : queriesMap.keySet()) { + if (Objects.equals(callingPkg, filteringPackageName)) { + // don't filter target package names if the calling is filteringPackageName + dumpPackageSet(pw, null /*filteringPackageName*/, queriesMap.get(callingPkg), + callingPkg, spacing); + } else { + dumpPackageSet(pw, filteringPackageName, queriesMap.get(callingPkg), callingPkg, + spacing); + } + } + } + + private static void dumpPackageSet(PrintWriter pw, @Nullable String filteringPackageName, + Set targetPkgSet, String subTitle, String spacing) { + if (targetPkgSet != null && targetPkgSet.size() > 0 + && (filteringPackageName == null || targetPkgSet.contains(filteringPackageName))) { + pw.append(spacing).append(subTitle).println(":"); + for (String pkgName : targetPkgSet) { + if (filteringPackageName == null || Objects.equals(filteringPackageName, pkgName)) { + pw.append(spacing).append(" ").println(pkgName); + } + } + } + } + public interface ConfigProvider { boolean isEnabled(); } diff --git a/services/core/java/com/android/server/pm/DumpState.java b/services/core/java/com/android/server/pm/DumpState.java index d473fbf5ed51f..99a109367afc0 100644 --- a/services/core/java/com/android/server/pm/DumpState.java +++ b/services/core/java/com/android/server/pm/DumpState.java @@ -42,6 +42,7 @@ public final class DumpState { public static final int DUMP_VOLUMES = 1 << 23; public static final int DUMP_SERVICE_PERMISSIONS = 1 << 24; public static final int DUMP_APEX = 1 << 25; + public static final int DUMP_QUERIES = 1 << 26; public static final int OPTION_SHOW_FILTERS = 1 << 0; public static final int OPTION_DUMP_ALL_COMPONENTS = 1 << 1; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 3f6d4dfcdfcb5..af20346fc168e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -20663,6 +20663,7 @@ public class PackageManagerService extends IPackageManager.Stub pw.println(" preferred-xml [--full]: print preferred package settings as xml"); pw.println(" prov[iders]: dump content providers"); pw.println(" p[ackages]: dump installed packages"); + pw.println(" q[ueries]: dump app queryability calculations"); pw.println(" s[hared-users]: dump shared user IDs"); pw.println(" m[essages]: print collected runtime messages"); pw.println(" v[erifiers]: print package verifier info"); @@ -20785,6 +20786,8 @@ public class PackageManagerService extends IPackageManager.Stub dumpState.setDump(DumpState.DUMP_DOMAIN_PREFERRED); } else if ("p".equals(cmd) || "packages".equals(cmd)) { dumpState.setDump(DumpState.DUMP_PACKAGES); + } else if ("q".equals(cmd) || "queries".equals(cmd)) { + dumpState.setDump(DumpState.DUMP_QUERIES); } else if ("s".equals(cmd) || "shared-users".equals(cmd)) { dumpState.setDump(DumpState.DUMP_SHARED_USERS); if (opti < args.length && "noperm".equals(args[opti])) { @@ -21079,6 +21082,10 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.dumpPackagesLPr(pw, packageName, permissionNames, dumpState, checkin); } + if (dumpState.isDumping(DumpState.DUMP_QUERIES)) { + mAppsFilter.dumpQueries(pw, packageName, dumpState, mUserManager.getUserIds()); + } + if (dumpState.isDumping(DumpState.DUMP_SHARED_USERS)) { mSettings.dumpSharedUsersLPr(pw, packageName, permissionNames, dumpState, checkin); } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index c1cb53d4ff0fd..597246884ca5a 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -4570,6 +4570,13 @@ public final class Settings { pw.print(prefix); pw.print(" privateFlags="); printFlags(pw, ps.pkg.applicationInfo.privateFlags, PRIVATE_FLAG_DUMP_SPEC); pw.println(); } + pw.print(prefix); pw.print(" forceQueryable="); pw.println(ps.pkg.mForceQueryable); + if (ps.pkg.mQueriesPackages != null) { + pw.append(prefix).append(" queriesPackages=").println(ps.pkg.mQueriesPackages); + } + if (ps.pkg.mQueriesIntents != null) { + pw.append(prefix).append(" queriesIntents=").println(ps.pkg.mQueriesIntents); + } pw.print(prefix); pw.print(" dataDir="); pw.println(ps.pkg.applicationInfo.dataDir); pw.print(prefix); pw.print(" supportsScreens=["); boolean first = true;