Improvements on CarService dump():

- Added --help option
- Added --hal option do dump halls (all or specific ones)
- Fixed UserHalService dump

Examples:

$ adb shell dumpsys car_service --help
Car service dump usage:
[NO ARG]
	  dumps everything (all services and HALs)
--help
	  shows this help
--list
	  lists the name of all services
--list
	  lists the name of all HAls
--services <SVC1> [SVC2] [SVCN]
	  dumps just the specific services, where SVC is just the service class
	  name (like CarUserService)
--vms-hal
	  dumps the VMS HAL metrics
--hal [HAL1] [HAL2] [HALN]
	  dumps just the specified HALs (or all of them if none specified),
	  where HAL is just the class name (like UserHalService)
-h
	  shows commands usage (NOTE: commands are not available on USER builds
[ANYTHING ELSE]
	  runs the given command (use --h to see the available commands)

$ adb shell dumpsys car_service --list-hals
com.android.car.hal.PowerHalService
com.android.car.hal.InputHalService
com.android.car.hal.PropertyHalService
com.android.car.hal.DiagnosticHalService
com.android.car.hal.VmsHalService
com.android.car.hal.UserHalService

$ adb shell dumpsys car_service --hal UserHalService
*User HAL*
next request id: 1
no pending callbacks

$ adb shell dumpsys car_service --hal 9000
No HAL named 9000. Valid options are: [VmsHalService, UserHalService, PropertyHalService, PowerHalService, InputHalService, DiagnosticHalService]

Bug: 146207078
Test: see above

Change-Id: I7063128df3749645d7fa9453968076ebe68a506b
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index e5e1e1a..4d53ead 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -617,19 +617,8 @@
 
         if (args == null || args.length == 0 || (args.length > 0 && "-a".equals(args[0]))) {
             writer.println("*Dump car service*");
-            writer.println("*Dump all services*");
-
             dumpAllServices(writer);
-
-            writer.println("*Dump Vehicle HAL*");
-            writer.println("Vehicle HAL Interface: " + mVehicleInterfaceName);
-            try {
-                // TODO dump all feature flags by creating a dumpable interface
-                mHal.dump(writer);
-            } catch (Exception e) {
-                writer.println("Failed dumping: " + mHal.getClass().getName());
-                e.printStackTrace(writer);
-            }
+            dumpAllHals(writer);
         } else if ("--list".equals(args[0])) {
             dumpListOfServices(writer);
             return;
@@ -649,6 +638,21 @@
             mCarStatsService.dump(fd, writer, Arrays.copyOfRange(args, 1, args.length));
         } else if ("--vms-hal".equals(args[0])) {
             mHal.getVmsHal().dumpMetrics(fd);
+        } else if ("--hal".equals(args[0])) {
+            if (args.length == 1) {
+                dumpAllHals(writer);
+                return;
+            }
+            int length = args.length - 1;
+            String[] halNames = new String[length];
+            System.arraycopy(args, 1, halNames, 0, length);
+            mHal.dumpSpecificHals(writer, halNames);
+
+        } else if ("--list-hals".equals(args[0])) {
+            mHal.dumpListHals(writer);
+            return;
+        } else if ("--help".equals(args[0])) {
+            showDumpHelp(writer);
         } else if (Build.IS_USERDEBUG || Build.IS_ENG) {
             execShellCmd(args, writer);
         } else {
@@ -656,6 +660,42 @@
         }
     }
 
+    private void dumpAllHals(PrintWriter writer) {
+        writer.println("*Dump Vehicle HAL*");
+        writer.println("Vehicle HAL Interface: " + mVehicleInterfaceName);
+        try {
+            // TODO dump all feature flags by creating a dumpable interface
+            mHal.dump(writer);
+        } catch (Exception e) {
+            writer.println("Failed dumping: " + mHal.getClass().getName());
+            e.printStackTrace(writer);
+        }
+    }
+
+    private void showDumpHelp(PrintWriter writer) {
+        writer.println("Car service dump usage:");
+        writer.println("[NO ARG]");
+        writer.println("\t  dumps everything (all services and HALs)");
+        writer.println("--help");
+        writer.println("\t  shows this help");
+        writer.println("--list");
+        writer.println("\t  lists the name of all services");
+        writer.println("--list");
+        writer.println("\t  lists the name of all HAls");
+        writer.println("--services <SVC1> [SVC2] [SVCN]");
+        writer.println("\t  dumps just the specific services, where SVC is just the service class");
+        writer.println("\t  name (like CarUserService)");
+        writer.println("--vms-hal");
+        writer.println("\t  dumps the VMS HAL metrics");
+        writer.println("--hal [HAL1] [HAL2] [HALN]");
+        writer.println("\t  dumps just the specified HALs (or all of them if none specified),");
+        writer.println("\t  where HAL is just the class name (like UserHalService)");
+        writer.println("-h");
+        writer.println("\t  shows commands usage (NOTE: commands are not available on USER builds");
+        writer.println("[ANYTHING ELSE]");
+        writer.println("\t  runs the given command (use --h to see the available commands)");
+    }
+
     @Override
     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
             String[] args, ShellCallback callback, ResultReceiver resultReceiver)
@@ -670,6 +710,7 @@
     }
 
     private void dumpAllServices(PrintWriter writer) {
+        writer.println("*Dump all services*");
         for (CarServiceBase service : mAllServices) {
             dumpService(service, writer);
         }
diff --git a/service/src/com/android/car/hal/UserHalService.java b/service/src/com/android/car/hal/UserHalService.java
index 396f353..7cfddf1 100644
--- a/service/src/com/android/car/hal/UserHalService.java
+++ b/service/src/com/android/car/hal/UserHalService.java
@@ -325,8 +325,12 @@
     public void dump(PrintWriter writer) {
         writer.printf("*User HAL*\n");
         synchronized (mLock) {
-            writer.printf("mNextRequestId: %d\n", mNextRequestId);
-            writer.printf("mPendingCallbacks: %d\n", mPendingCallbacks);
+            writer.printf("next request id: %d\n", mNextRequestId);
+            if (mPendingCallbacks.size() == 0) {
+                writer.println("no pending callbacks");
+            } else {
+                writer.printf("pending callbacks: %s\n", mPendingCallbacks);
+            }
         }
     }
 }
diff --git a/service/src/com/android/car/hal/VehicleHal.java b/service/src/com/android/car/hal/VehicleHal.java
index a8a7753..3015c0c 100644
--- a/service/src/com/android/car/hal/VehicleHal.java
+++ b/service/src/com/android/car/hal/VehicleHal.java
@@ -55,7 +55,9 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * Abstraction for vehicle HAL. This class handles interface with native HAL and do basic parsing
@@ -496,6 +498,31 @@
     }
 
     /**
+     * Dumps the list of HALs.
+     */
+    public void dumpListHals(PrintWriter writer) {
+        for (HalServiceBase service: mAllServices) {
+            writer.println(service.getClass().getName());
+        }
+    }
+
+    /**
+     * Dumps the given HALs.
+     */
+    public void dumpSpecificHals(PrintWriter writer, String... halNames) {
+        Map<String, HalServiceBase> byName = mAllServices.stream()
+                .collect(Collectors.toMap(s -> s.getClass().getSimpleName(), s -> s));
+        for (String halName : halNames) {
+            HalServiceBase service = byName.get(halName);
+            if (service == null) {
+                writer.printf("No HAL named %s. Valid options are: %s\n", halName, byName.keySet());
+                continue;
+            }
+            service.dump(writer);
+        }
+    }
+
+    /**
      * Dumps vehicle property values.
      * @param writer
      * @param propId property id, dump all properties' value if it is empty string.