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:
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user