Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a7ad66d5 authored by Patrick Baumann's avatar Patrick Baumann
Browse files

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
parent 40ed99ac
Loading
Loading
Loading
Loading
+60 −11
Original line number Diff line number Diff line
@@ -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();
    }
+1 −0
Original line number Diff line number Diff line
@@ -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;
+7 −0
Original line number Diff line number Diff line
@@ -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);
            }
+7 −0
Original line number Diff line number Diff line
@@ -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;