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

Commit 4b491878 authored by Patrick Baumann's avatar Patrick Baumann
Browse files

Logs for test & debug blocks

This change adds logging for debuggable and test-only apps when they are
the caller and visibility of another app is blocked due to app
enumeration.

It also adds an adb command to turn logging on and off for other apps to
help developers while debugging issues.

Test: atest AppsFilterTest AppEnumerationTests PackageManagerPerfTest
Bug: 145623959
Change-Id: I1fa930ef40bf08b00c41f51aa25c50b2189395bf
parent 15842bc4
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -748,5 +748,4 @@ interface IPackageManager {
    void clearMimeGroup(String packageName, String group);

    List<String> getMimeGroup(String packageName, String group);

}
+7 −0
Original line number Diff line number Diff line
@@ -986,4 +986,11 @@ public abstract class PackageManagerInternal {
     * Returns MIME types contained in {@code mimeGroup} from {@code packageName} package
     */
    public abstract List<String> getMimeGroup(String packageName, String mimeGroup);

    /**
     * Toggles visibility logging to help in debugging the app enumeration feature.
     * @param packageName the package name that should begin logging
     * @param enabled true if visibility blocks should be logged
     */
    public abstract void setVisibilityLogging(String packageName, boolean enabled);
}
+75 −36
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseSetArray;

import com.android.internal.R;
@@ -123,6 +124,7 @@ public class AppsFilter {
    }

    public interface FeatureConfig {

        /** Called when the system is ready and components can be queried. */
        void onSystemReady();

@@ -132,11 +134,21 @@ public class AppsFilter {
        /** @return true if the feature is enabled for the given package. */
        boolean packageIsEnabled(AndroidPackage pkg);

        /** @return true if debug logging is enabled for the given package. */
        boolean isLoggingEnabled(int appId);

        /**
         * Turns on logging for the given appId
         * @param enable true if logging should be enabled, false if disabled.
         */
        void enableLogging(int appId, boolean enable);

        /**
         * Initializes the package enablement state for the given package. This gives opportunity
         * to do any expensive operations ahead of the actual checks.
         * @param removed true if adding, false if removing
         */
        void initializePackageState(String packageName);
        void updatePackageState(PackageSetting setting, boolean removed);
    }

    private static class FeatureConfigImpl implements FeatureConfig, CompatChange.ChangeListener {
@@ -147,6 +159,9 @@ public class AppsFilter {
                PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT;
        private final ArraySet<String> mDisabledPackages = new ArraySet<>();

        @Nullable
        private SparseBooleanArray mLoggingEnabled = null;

        private FeatureConfigImpl(
                PackageManagerInternal pmInternal, PackageManagerService.Injector injector) {
            mPmInternal = pmInternal;
@@ -192,39 +207,65 @@ public class AppsFilter {
            }
        }

        private boolean fetchPackageIsEnabled(AndroidPackage pkg) {
        @Override
        public boolean isLoggingEnabled(int uid) {
            return mLoggingEnabled != null && mLoggingEnabled.indexOfKey(uid) >= 0;
        }

        @Override
        public void enableLogging(int appId, boolean enable) {
            if (enable) {
                if (mLoggingEnabled == null) {
                    mLoggingEnabled = new SparseBooleanArray();
                }
                mLoggingEnabled.put(appId, true);
            } else {
                if (mLoggingEnabled != null) {
                    final int index = mLoggingEnabled.indexOfKey(appId);
                    if (index >= 0) {
                        mLoggingEnabled.removeAt(index);
                        if (mLoggingEnabled.size() == 0) {
                            mLoggingEnabled = null;
                        }
                    }
                }
            }
        }

        @Override
        public void onCompatChange(String packageName) {
            updateEnabledState(mPmInternal.getPackage(packageName));
        }

        private void updateEnabledState(AndroidPackage pkg) {
            final long token = Binder.clearCallingIdentity();
            try {
                // TODO(b/135203078): Do not use toAppInfo
                final boolean changeEnabled =
                final boolean enabled =
                        mInjector.getCompatibility().isChangeEnabled(
                                PackageManager.FILTER_APPLICATION_QUERY,
                                pkg.toAppInfoWithoutState());
                return changeEnabled;
                if (enabled) {
                    mDisabledPackages.remove(pkg.getPackageName());
                } else {
                    mDisabledPackages.add(pkg.getPackageName());
                }
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }

        @Override
        public void onCompatChange(String packageName) {
            final AndroidPackage pkg = mPmInternal.getPackage(packageName);
            if (pkg == null) {
                mDisabledPackages.remove(packageName);
                return;
            }
            boolean enabled = fetchPackageIsEnabled(pkg);
            if (enabled) {
                mDisabledPackages.remove(packageName);
        public void updatePackageState(PackageSetting setting, boolean removed) {
            final boolean enableLogging =
                    !removed && (setting.pkg.isTestOnly() || setting.pkg.isDebuggable());
            enableLogging(setting.appId, enableLogging);
            if (removed) {
                mDisabledPackages.remove(setting.pkg.getPackageName());
            } else {
                mDisabledPackages.add(packageName);
                updateEnabledState(setting.pkg);
            }
        }

        @Override
        public void initializePackageState(String packageName) {
            onCompatChange(packageName);
        }
    }

    /** Builder method for an AppsFilter */
@@ -250,6 +291,10 @@ public class AppsFilter {
                forceSystemAppsQueryable, null);
    }

    public FeatureConfig getFeatureConfig() {
        return mFeatureConfig;
    }

    /** Returns true if the querying package may query for the potential target package */
    private static boolean canQueryViaComponents(AndroidPackage querying,
            AndroidPackage potentialTarget) {
@@ -447,7 +492,7 @@ public class AppsFilter {
                }
            }
            mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs);
            mFeatureConfig.initializePackageState(newPkgSetting.pkg.getPackageName());
            mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/);
        } finally {
            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
        }
@@ -499,7 +544,7 @@ public class AppsFilter {
        }

        mOverlayReferenceMapper.removePkg(setting.name);
        mFeatureConfig.initializePackageState(setting.pkg.getPackageName());
        mFeatureConfig.updatePackageState(setting, true /*removed*/);
    }

    /**
@@ -516,13 +561,13 @@ public class AppsFilter {
            PackageSetting targetPkgSetting, int userId) {
        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication");
        try {
            if (!shouldFilterApplicationInternal(callingUid, callingSetting, targetPkgSetting,
                    userId)) {

            if (!shouldFilterApplicationInternal(
                    callingUid, callingSetting, targetPkgSetting, userId)) {
                return false;
            }
            if (DEBUG_LOGGING) {
                log(callingSetting, targetPkgSetting,
                        DEBUG_ALLOW_ALL ? "ALLOWED" : "BLOCKED", new RuntimeException());
            if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) {
                log(callingSetting, targetPkgSetting, "BLOCKED");
            }
            return !DEBUG_ALLOW_ALL;
        } finally {
@@ -737,17 +782,11 @@ public class AppsFilter {
        }
    }

    private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting,
    private static void log(SettingBase callingSetting, PackageSetting targetPkgSetting,
            String description) {
        log(callingPkgSetting, targetPkgSetting, description, null);
    }

    private static void log(SettingBase callingPkgSetting, PackageSetting targetPkgSetting,
            String description, Throwable throwable) {
        Slog.wtf(TAG,
                "interaction: " + callingPkgSetting
                        + " -> " + targetPkgSetting + " "
                        + description, throwable);
        Slog.i(TAG,
                "interaction: " + (callingSetting == null ? "system" : callingSetting) + " -> "
                        + targetPkgSetting + " " + description);
    }

    public void dumpQueries(
+12 −0
Original line number Diff line number Diff line
@@ -24152,6 +24152,18 @@ public class PackageManagerService extends IPackageManager.Stub
        public List<String> getMimeGroup(String packageName, String mimeGroup) {
            return PackageManagerService.this.getMimeGroup(packageName, mimeGroup);
        }
        @Override
        public void setVisibilityLogging(String packageName, boolean enable) {
            final PackageSetting pkg;
            synchronized (mLock) {
                pkg = mSettings.getPackageLPr(packageName);
            }
            if (pkg == null) {
                throw new IllegalStateException("No package found for " + packageName);
            }
            mAppsFilter.getFeatureConfig().enableLogging(pkg.appId, enable);
        }
    }
    @GuardedBy("mLock")
+37 −0
Original line number Diff line number Diff line
@@ -295,6 +295,8 @@ class PackageManagerShellCommand extends ShellCommand {
                    return runRollbackApp();
                case "get-moduleinfo":
                    return runGetModuleInfo();
                case "log-visibility":
                    return runLogVisibility();
                default: {
                    String nextArg = getNextArg();
                    if (nextArg == null) {
@@ -360,6 +362,36 @@ class PackageManagerShellCommand extends ShellCommand {
        return 1;
    }

    private int runLogVisibility() {
        final PrintWriter pw = getOutPrintWriter();
        boolean enable = true;

        String opt;
        while ((opt = getNextOption()) != null) {
            switch (opt) {
                case "--disable":
                    enable = false;
                    break;
                case "--enable":
                    enable = true;
                    break;
                default:
                    pw.println("Error: Unknown option: " + opt);
                    return -1;
            }
        }

        String packageName = getNextArg();
        if (packageName != null) {
            LocalServices.getService(PackageManagerInternal.class)
                    .setVisibilityLogging(packageName, enable);
        } else {
            getErrPrintWriter().println("Error: no package specified");
            return -1;
        }
        return 1;
    }

    private int uninstallSystemUpdates() {
        final PrintWriter pw = getOutPrintWriter();
        List<String> failedUninstalls = new LinkedList<>();
@@ -3715,6 +3747,11 @@ class PackageManagerShellCommand extends ShellCommand {
        pw.println("      --all: show all module info");
        pw.println("      --installed: show only installed modules");
        pw.println("");
        pw.println("  log-visibility [--enable|--disable] <PACKAGE>");
        pw.println("    Turns on debug logging when visibility is blocked for the given package.");
        pw.println("      --enable: turn on debug logging (default)");
        pw.println("      --disable: turn off debug logging");
        pw.println("");
        Intent.printIntentArgsHelp(pw , "");
    }