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
This commit is contained in:
Patrick Baumann
2019-08-12 11:11:08 -07:00
parent 40ed99ac18
commit a7ad66d59a
4 changed files with 75 additions and 11 deletions

View File

@@ -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<HashMap<String, ArrayList<String>>> mImplicitlyQueryable =
private final SparseArray<HashMap<String, Set<String>>> 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<String, List<String>> mQueriesViaPackage = new HashMap<>();
private final HashMap<String, Set<String>> 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<String, List<String>> mQueriesViaIntent = new HashMap<>();
private final HashMap<String, Set<String>> 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<String, ArrayList<String>> currentUser = mImplicitlyQueryable.get(userId);
HashMap<String, Set<String>> 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<String> queriesPackages = new ArrayList<>(
final HashSet<String> 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<String> initiators : mImplicitlyQueryable.valueAt(i).values()) {
for (Set<String> initiators : mImplicitlyQueryable.valueAt(i).values()) {
initiators.remove(packageName);
}
}
mQueriesViaIntent.remove(packageName);
for (List<String> declarators : mQueriesViaIntent.values()) {
for (Set<String> 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<String, Set<String>> queryMapForUser = mImplicitlyQueryable.get(user);
dumpQueriesMap(pw, filteringPackageName, queryMapForUser, " ");
}
}
private static void dumpQueriesMap(PrintWriter pw, @Nullable String filteringPackageName,
HashMap<String, Set<String>> 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<String> 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();
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;