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
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 69bc259..362a9e8 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -42,6 +42,7 @@
 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.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 @@
     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 @@
         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 @@
         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 @@
         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 @@
 
     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);
         }