Merge "[Garage Mode] List the jobs that prevent GM from terminating" into qt-dev
diff --git a/service/src/com/android/car/ICarImpl.java b/service/src/com/android/car/ICarImpl.java
index 3530ae3..244ee8b 100644
--- a/service/src/com/android/car/ICarImpl.java
+++ b/service/src/com/android/car/ICarImpl.java
@@ -702,19 +702,19 @@
             switch (arg) {
                 case PARAM_ON_MODE:
                     mGarageModeService.forceStartGarageMode();
+                    writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
                     break;
                 case PARAM_OFF_MODE:
                     mGarageModeService.stopAndResetGarageMode();
+                    writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
                     break;
                 case PARAM_QUERY_MODE:
-                    // Nothing to do. Always query at the end anyway.
+                    mGarageModeService.dump(writer);
                     break;
                 default:
                     writer.println("Unknown value. Valid argument: " + PARAM_ON_MODE + "|"
                             + PARAM_OFF_MODE + "|" + PARAM_QUERY_MODE);
-                    return;
             }
-            writer.println("Garage mode: " + mGarageModeService.isGarageModeActive());
         }
 
         /**
diff --git a/service/src/com/android/car/garagemode/Controller.java b/service/src/com/android/car/garagemode/Controller.java
index 347ba73..d7235dd 100644
--- a/service/src/com/android/car/garagemode/Controller.java
+++ b/service/src/com/android/car/garagemode/Controller.java
@@ -28,6 +28,7 @@
 import com.android.car.CarLocalServices;
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.List;
 import java.util.concurrent.CompletableFuture;
 
 /**
@@ -105,6 +106,13 @@
     }
 
     /**
+     * @return The names of the jobs that Garage Mode is waiting for
+     */
+    List<String> pendingGarageModeJobs() {
+        return mGarageMode.pendingJobs();
+    }
+
+    /**
      * Wrapper method to send a broadcast
      *
      * @param i intent that contains broadcast data
diff --git a/service/src/com/android/car/garagemode/GarageMode.java b/service/src/com/android/car/garagemode/GarageMode.java
index b13045e..1165de5 100644
--- a/service/src/com/android/car/garagemode/GarageMode.java
+++ b/service/src/com/android/car/garagemode/GarageMode.java
@@ -63,6 +63,7 @@
 
     private boolean mGarageModeActive;
     private JobScheduler mJobScheduler;
+    private List<String> mPendingJobs = new ArrayList<>();
     private Handler mHandler;
     private Runnable mRunnable = new Runnable() {
         @Override
@@ -129,6 +130,10 @@
         return mGarageModeActive;
     }
 
+    synchronized List<String> pendingJobs() {
+        return mPendingJobs;
+    }
+
     void enterGarageMode(CompletableFuture<Void> future) {
         LOG.d("Entering GarageMode");
         synchronized (this) {
@@ -141,9 +146,7 @@
         ArrayList<Integer> startedUsers =
                 CarLocalServices.getService(CarUserService.class).startAllBackgroundUsers();
         synchronized (this) {
-            for (Integer user : startedUsers) {
-                mStartedBackgroundUsers.add(user);
-            }
+            mStartedBackgroundUsers.addAll(startedUsers);
         }
     }
 
@@ -224,15 +227,22 @@
         mHandler.removeCallbacks(mRunnable);
     }
 
-    private int numberOfJobsRunning() {
+    private synchronized int numberOfJobsRunning() {
         List<JobInfo> startedJobs = mJobScheduler.getStartedJobs();
         int count = 0;
+        List<String> currentPendingJobs = new ArrayList<>();
         for (JobSnapshot snap : mJobScheduler.getAllJobSnapshots()) {
             if (startedJobs.contains(snap.getJobInfo())
                     && snap.getJobInfo().isRequireDeviceIdle()) {
+                currentPendingJobs.add(snap.getJobInfo().toString());
                 count++;
             }
         }
+        if (count > 0) {
+            // We have something pending, so update the list.
+            // (Otherwise, keep the old list.)
+            mPendingJobs = currentPendingJobs;
+        }
         return count;
     }
 }
diff --git a/service/src/com/android/car/garagemode/GarageModeService.java b/service/src/com/android/car/garagemode/GarageModeService.java
index f28bb35..8527bc7 100644
--- a/service/src/com/android/car/garagemode/GarageModeService.java
+++ b/service/src/com/android/car/garagemode/GarageModeService.java
@@ -23,6 +23,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.PrintWriter;
+import java.util.List;
 
 /**
  * Main service container for car Garage Mode.
@@ -63,11 +64,24 @@
 
     /**
      * Dumps useful information about GarageMode
-     * @param writer
+     * @param writer Where to dump the information
      */
     @Override
     public void dump(PrintWriter writer) {
-        writer.println("GarageModeInProgress " + mController.isGarageModeActive());
+        boolean isActive = mController.isGarageModeActive();
+        writer.println("GarageModeInProgress " + isActive);
+        List<String> jobs = mController.pendingGarageModeJobs();
+        if (isActive) {
+            writer.println("GarageMode is currently waiting for " + jobs.size() + " jobs:");
+        } else {
+            writer.println("GarageMode was last waiting for " + jobs.size() + " jobs:");
+        }
+        // Dump the names of the jobs that GM is/was waiting for
+        int jobNumber = 1;
+        for (String job : jobs) {
+            writer.println("   " + jobNumber + ": " + job);
+            jobNumber++;
+        }
     }
 
     /**