Batterystats CTS test: background job scheduling

Schedules a job when the app is in the foreground and background
and ensures that the counts are incremented correctly.

Fixes: 35669746
Test: run cts-dev -m CtsIncidentHostTestCases -t com.android.server.cts.BatteryStatsValidationTest
Change-Id: Ic78dc670f691d1970671b02aff9ee81188131231
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
index f4360f5..7528cac 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsBgVsFgActions.java
@@ -18,10 +18,14 @@
 
 import android.app.ActivityManager;
 import android.content.BroadcastReceiver;
+import android.app.job.JobInfo;
+import android.app.job.JobScheduler;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.wifi.WifiManager;
+import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -35,6 +39,7 @@
     private static final String TAG = BatteryStatsBgVsFgActions.class.getSimpleName();
 
     public static final String KEY_ACTION = "action";
+    public static final String ACTION_JOB_SCHEDULE = "action.jobs";
     public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
 
     /** Perform the action specified by the given action code (see constants above). */
@@ -45,6 +50,9 @@
         }
         sleep(100);
         switch(actionCode) {
+            case ACTION_JOB_SCHEDULE:
+                doScheduleJob(ctx);
+                break;
             case ACTION_WIFI_SCAN:
                 doWifi(ctx);
                 break;
@@ -54,6 +62,30 @@
         sleep(100);
     }
 
+    private static void doScheduleJob(Context ctx) {
+        final ComponentName JOB_COMPONENT_NAME =
+                new ComponentName("com.android.server.cts.device.batterystats",
+                        SimpleJobService.class.getName());
+        JobScheduler js = ctx.getSystemService(JobScheduler.class);
+        if (js == null) {
+            Log.e(TAG, "JobScheduler service not available");
+            return;
+        }
+        final JobInfo job = (new JobInfo.Builder(1, JOB_COMPONENT_NAME))
+                .setOverrideDeadline(0)
+                .build();
+        CountDownLatch latch = SimpleJobService.resetCountDownLatch();
+        js.schedule(job);
+        // Job starts in main thread so wait in another thread to see if job finishes.
+        new AsyncTask<Void, Void, Void>() {
+            @Override
+            protected Void doInBackground(Void... params) {
+                waitForReceiver(null, 3_000, latch, null);
+                return null;
+            }
+        }.execute();
+    }
+
     private static void doWifi(Context ctx) {
         IntentFilter intentFilter = new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
         CountDownLatch onReceiveLatch = new CountDownLatch(1);
@@ -80,11 +112,14 @@
         return receiver;
     }
 
-    /** Uses the receiver to wait until the action is complete. */
+    /**
+     * Uses the receiver to wait until the action is complete. ctx and receiver may be null if no
+     * receiver is needed to be unregistered.
+     */
     private static void waitForReceiver(Context ctx,
-            int maxWaitTimeMs, CountDownLatch onReceiveLatch, BroadcastReceiver receiver) {
+            int maxWaitTimeMs, CountDownLatch latch, BroadcastReceiver receiver) {
         try {
-            boolean didFinish = onReceiveLatch.await(maxWaitTimeMs, TimeUnit.MILLISECONDS);
+            boolean didFinish = latch.await(maxWaitTimeMs, TimeUnit.MILLISECONDS);
             if (didFinish) {
                 Log.v(TAG, "Finished performing action");
             } else {
@@ -95,7 +130,9 @@
         } catch (InterruptedException e) {
             Log.e(TAG, "Interrupted exception while awaiting action to finish", e);
         }
-        ctx.unregisterReceiver(receiver);
+        if (ctx != null && receiver != null) {
+            ctx.unregisterReceiver(receiver);
+        }
     }
 
     /** Determines whether the package is running as a background process. */
diff --git a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
index 9dab07f..d6869a1 100644
--- a/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
+++ b/hostsidetests/incident/apps/batterystatsapp/src/com/android/server/cts/device/batterystats/BatteryStatsForegroundActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.server.cts.device.batterystats;
 
+import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions
+        .ACTION_JOB_SCHEDULE;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.KEY_ACTION;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.doAction;
 import static com.android.server.cts.device.batterystats.BatteryStatsBgVsFgActions.isAppInBackground;
diff --git a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
index 15f1cff..f926665 100644
--- a/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/BatteryStatsValidationTest.java
@@ -41,6 +41,7 @@
 
     // Constants from BatteryStatsBgVsFgActions.java (not directly accessible here).
     public static final String KEY_ACTION = "action";
+    public static final String ACTION_JOB_SCHEDULE = "action.jobs";
     public static final String ACTION_WIFI_SCAN = "action.wifi_scan";
 
     @Override
@@ -116,6 +117,25 @@
         batteryOffScreenOn();
     }
 
+    public void testJobBgVsFg() throws Exception {
+        batteryOnScreenOff();
+        installPackage(DEVICE_SIDE_TEST_APK, true);
+
+        // Foreground test.
+        executeForeground(ACTION_JOB_SCHEDULE);
+        Thread.sleep(4_000);
+        assertValueRange("jb", "", 6, 1, 1); // count
+        assertValueRange("jb", "", 8, 0, 0); // background_count
+
+        // Background test.
+        executeBackground(ACTION_JOB_SCHEDULE);
+        Thread.sleep(4_000);
+        assertValueRange("jb", "", 6, 2, 2); // count
+        assertValueRange("jb", "", 8, 1, 1); // background_count
+
+        batteryOffScreenOn();
+    }
+
     public void testWifiScans() throws Exception {
         batteryOnScreenOff();
         installPackage(DEVICE_SIDE_TEST_APK, true);