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

Commit c7cfa69f authored by Ned Burns's avatar Ned Burns
Browse files

Introduce DumpManager

Introduces DumpManager, a unified dumping system that supports dumping
at different priority levels.

Currently, when a bug report gets taken, SystemUI is only dumped during
the CRITICAL section. This has its advantages (we get to go first!) but
also imposes a strict limit on how much we can dump. To get around this
restriction, we need to *also* dump SystemUI during the NORMAL section,
which has much more forgiving constraints.

This CL simply creates the mechanism for systemUI to dump at different
priority levels, but doesn't actually cause us to participate in the
NORMAL section (yet, see later CLs).

It introduces the DumpManager, unified replacement for DumpController &
various logic in SystemUIService and Dependency.java. See kdoc in
DumpManager for usage notes.

Migration of current users of DumpController coming in a later CL.

Test: atest, manual
Change-Id: If4f41ed496c0c64024a83aad812b77f60fe27555
parent b9095577
Loading
Loading
Loading
Loading
+22 −30
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.dock.DockManager;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.fragments.FragmentService;
import com.android.systemui.keyguard.ScreenLifecycle;
import com.android.systemui.keyguard.WakefulnessLifecycle;
@@ -128,8 +129,6 @@ import com.android.systemui.wm.DisplayController;
import com.android.systemui.wm.DisplayImeController;
import com.android.systemui.wm.SystemWindows;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.function.Consumer;

import javax.inject.Inject;
@@ -211,6 +210,8 @@ public class Dependency {
    private final ArrayMap<Object, Object> mDependencies = new ArrayMap<>();
    private final ArrayMap<Object, LazyDependencyCreator> mProviders = new ArrayMap<>();

    @Inject DumpManager mDumpManager;

    @Inject Lazy<ActivityStarter> mActivityStarter;
    @Inject Lazy<BroadcastDispatcher> mBroadcastDispatcher;
    @Inject Lazy<AsyncSensorManager> mAsyncSensorManager;
@@ -534,34 +535,6 @@ public class Dependency {
        sDependency = this;
    }

    static void staticDump(FileDescriptor fd, PrintWriter pw, String[] args) {
        sDependency.dump(fd, pw, args);
    }

    /**
     * {@see SystemUI.dump}
     */
    public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        // Make sure that the DumpController gets added to mDependencies, as they are only added
        // with Dependency#get.
        getDependency(DumpController.class);
        getDependency(BroadcastDispatcher.class);

        // If an arg is specified, try to dump the dependency
        String controller = args != null && args.length > 1
                ? args[1].toLowerCase()
                : null;
        if (controller != null) {
            pw.println("Dumping controller=" + controller + ":");
        } else {
            pw.println("Dumping existing controllers:");
        }
        mDependencies.values().stream()
                .filter(obj -> obj instanceof Dumpable && (controller == null
                        || obj.getClass().getName().toLowerCase().endsWith(controller)))
                .forEach(o -> ((Dumpable) o).dump(fd, pw, args));
    }

    protected final <T> T getDependency(Class<T> cls) {
        return getDependencyInner(cls);
    }
@@ -576,6 +549,11 @@ public class Dependency {
        if (obj == null) {
            obj = createDependency(key);
            mDependencies.put(key, obj);

            // TODO: Get dependencies to register themselves instead
            if (autoRegisterModulesForDump() && obj instanceof Dumpable) {
                mDumpManager.registerDumpable(obj.getClass().getName(), (Dumpable) obj);
            }
        }
        return obj;
    }
@@ -593,6 +571,17 @@ public class Dependency {
        return provider.createDependency();
    }

    // Currently, there are situations in tests where we might create more than one instance of a
    // thing that should be a singleton: the "real" one (created by Dagger, usually as a result of
    // inflating a view), and a mocked one (injected into Dependency). If we register the mocked
    // one, the DumpManager will throw an exception complaining (rightly) that we have too many
    // things registered with that name. So in tests, we disable the auto-registration until the
    // root cause is fixed, i.e. inflated views in tests with Dagger dependencies.
    @VisibleForTesting
    protected boolean autoRegisterModulesForDump() {
        return true;
    }

    private static Dependency sDependency;

    /**
@@ -605,6 +594,9 @@ public class Dependency {

    private <T> void destroyDependency(Class<T> cls, Consumer<T> destroy) {
        T dep = (T) mDependencies.remove(cls);
        if (dep instanceof Dumpable) {
            mDumpManager.unregisterDumpable(dep.getClass().getName());
        }
        if (dep != null && destroy != null) {
            destroy.accept(dep);
        }
+11 −2
Original line number Diff line number Diff line
@@ -21,10 +21,18 @@ import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;

import androidx.annotation.NonNull;

import java.io.FileDescriptor;
import java.io.PrintWriter;

public abstract class SystemUI {
/**
 * A top-level module of system UI code (sometimes called "system UI services" elsewhere in code).
 * Which SystemUI modules are loaded can be controlled via a config resource.
 *
 * @see SystemUIApplication#startServicesIfNeeded()
 */
public abstract class SystemUI implements Dumpable {
    protected final Context mContext;

    public SystemUI(Context context) {
@@ -36,7 +44,8 @@ public abstract class SystemUI {
    protected void onConfigurationChanged(Configuration newConfig) {
    }

    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    @Override
    public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter pw, @NonNull String[] args) {
    }

    protected void onBootCompleted() {
+5 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import android.util.TimingsTraceLog;

import com.android.systemui.dagger.ContextComponentHelper;
import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.NotificationChannels;

import java.lang.reflect.Constructor;
@@ -171,6 +172,8 @@ public class SystemUIApplication extends Application implements
            }
        }

        final DumpManager dumpManager = mRootComponent.createDumpManager();

        Log.v(TAG, "Starting SystemUI services for user " +
                Process.myUserHandle().getIdentifier() + ".");
        TimingsTraceLog log = new TimingsTraceLog("SystemUIBootTiming",
@@ -209,6 +212,8 @@ public class SystemUIApplication extends Application implements
            if (mBootCompleteCache.isBootComplete()) {
                mServices[i].onBootCompleted();
            }

            dumpManager.registerDumpable(mServices[i].getClass().getName(), mServices[i]);
        }
        mRootComponent.getInitController().executePostInitTasks();
        log.traceEnd();
+0 −10
Original line number Diff line number Diff line
@@ -20,9 +20,6 @@ import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

import java.io.FileDescriptor;
import java.io.PrintWriter;

public class SystemUISecondaryUserService extends Service {

    @Override
@@ -35,11 +32,4 @@ public class SystemUISecondaryUserService extends Service {
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        SystemUIService.dumpServices(
                ((SystemUIApplication) getApplication()).getServices(), fd, pw, args);
}
}
+15 −59
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui;

import android.annotation.NonNull;
import android.app.Service;
import android.content.Intent;
import android.os.Build;
@@ -28,8 +27,7 @@ import android.util.Slog;

import com.android.internal.os.BinderInternal;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.dump.DumpManager;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -39,11 +37,15 @@ import javax.inject.Inject;
public class SystemUIService extends Service {

    private final Handler mMainHandler;
    private final DumpManager mDumpManager;

    @Inject
    public SystemUIService(@Main Handler mainHandler) {
    public SystemUIService(
            @Main Handler mainHandler,
            DumpManager dumpManager) {
        super();
        mMainHandler = mainHandler;
        mDumpManager = dumpManager;
    }

    @Override
@@ -79,62 +81,16 @@ public class SystemUIService extends Service {

    @Override
    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
        dumpServices(((SystemUIApplication) getApplication()).getServices(), fd, pw, args);

        if (args == null || args.length == 0 || args[0].equals("--config")) {
            dumpConfig(pw);
        }
    }

    static void dumpServices(
            SystemUI[] services, FileDescriptor fd, PrintWriter pw, String[] args) {
        if (args == null || args.length == 0) {
            pw.println("dumping service: " + Dependency.class.getName());
            Dependency.staticDump(fd, pw, args);
            for (SystemUI ui: services) {
                pw.println("dumping service: " + ui.getClass().getName());
                ui.dump(fd, pw, args);
            }
            if (Build.IS_DEBUGGABLE) {
                pw.println("dumping plugins:");
                ((PluginManagerImpl) Dependency.get(PluginManager.class)).dump(fd, pw, args);
            }
        } else {
            String svc = args[0].toLowerCase();
            if (Dependency.class.getName().toLowerCase().endsWith(svc)) {
                Dependency.staticDump(fd, pw, args);
            }
            for (SystemUI ui: services) {
                String name = ui.getClass().getName().toLowerCase();
                if (name.endsWith(svc)) {
                    ui.dump(fd, pw, args);
                }
        // If no args are passed, assume we're being dumped as part of a bug report (sadly, we have
        // no better way to guess whether this is taking place). Set the appropriate dump priority
        // (CRITICAL) to reflect that this is taking place.
        String[] massagedArgs = args;
        if (args.length == 0) {
            massagedArgs = new String[] {
                    DumpManager.PRIORITY_ARG,
                    DumpManager.PRIORITY_ARG_CRITICAL};
        }
        }
    }

    private void dumpConfig(@NonNull PrintWriter pw) {
        pw.println("SystemUiServiceComponents configuration:");

        pw.print("vendor component: ");
        pw.println(getResources().getString(R.string.config_systemUIVendorServiceComponent));

        dumpConfig(pw, "global", R.array.config_systemUIServiceComponents);
        dumpConfig(pw, "per-user", R.array.config_systemUIServiceComponentsPerUser);
        mDumpManager.dump(fd, pw, massagedArgs);
    }

    private void dumpConfig(@NonNull PrintWriter pw, @NonNull String type, int resId) {
        final String[] services = getResources().getStringArray(resId);
        pw.print(type); pw.print(": ");
        if (services == null) {
            pw.println("N/A");
            return;
}
        pw.print(services.length);
        pw.println(" services");
        for (int i = 0; i < services.length; i++) {
            pw.print("  "); pw.print(i); pw.print(": "); pw.println(services[i]);
        }
    }
}
Loading