Make CTS tests use JobScheduler proto dump.
The proto dump will be more reliable in the long run than the text dump,
so we're switching CTS tests to use JobScheduler's proto dump instead.
The ProtoUtils classes have been created to make it easier to use other
service dumps as well.
Bug: 137550055
Test: atest BatterySavingTestBase
Test: atest CtsAssistTestCases
Test: atest CtsBackgroundRestrictionsTestCases
Test: atest CtsContentCaptureServiceTestCases
Test: atest CtsDatabaseTestCases
Test: atest CtsIncidentHostTestCases
Test: atest CtsMultiUserTestCases
Test: atest CtsSyncAccountAccessOtherCertTestCases
Test: atest LocationAccessCheckTest
Test: atest ProfileScheduledJobHostSideTest
Change-Id: I08693e820e029ee24464c7d463a3e1af4ab22b13
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/FileUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/FileUtils.java
index ceada01..5530ff3 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/FileUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/FileUtils.java
@@ -53,10 +53,6 @@
public static final int S_IWOTH = 00002;
public static final int S_IXOTH = 00001;
- static {
- System.loadLibrary("cts_jni");
- }
-
public static class FileStatus {
public int dev;
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/ProtoUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/ProtoUtils.java
new file mode 100644
index 0000000..ac99446
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/ProtoUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.util;
+
+import android.app.UiAutomation;
+
+/**
+ * Utility class for proto dumps.
+ */
+public class ProtoUtils {
+ public static final String DUMPSYS_JOB_SCHEDULER = "dumpsys jobscheduler --proto";
+
+ /**
+ * Call onto the device with an adb shell command and get the results of
+ * that as a proto of the given type.
+ *
+ * @param clazz A protobuf message class. e.g. MyProto
+ * @param command The adb shell command to run. e.g. "dumpsys jobscheduler --proto"
+ */
+ public static <T> T getProto(UiAutomation automation, Class<T> clazz, String command)
+ throws Exception {
+ return clazz.cast(clazz.getDeclaredMethod("parseFrom", byte[].class)
+ .invoke(null, SystemUtil.runShellCommandByteOutput(automation, command)));
+ }
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/SystemUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/SystemUtil.java
index 16fce10..d63b745 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/SystemUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/SystemUtil.java
@@ -31,6 +31,7 @@
import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
+import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.concurrent.Callable;
@@ -81,21 +82,30 @@
*/
public static String runShellCommand(UiAutomation automation, String cmd)
throws IOException {
+ return new String(runShellCommandByteOutput(automation, cmd));
+ }
+
+ /**
+ * Executes a shell command using shell user identity, and return the standard output as a byte
+ * array
+ * <p>Note: calling this function requires API level 21 or above
+ *
+ * @param automation {@link UiAutomation} instance, obtained from a test running in
+ * instrumentation framework
+ * @param cmd the command to run
+ * @return the standard output of the command as a byte array
+ */
+ static byte[] runShellCommandByteOutput(UiAutomation automation, String cmd)
+ throws IOException {
Log.v(TAG, "Running command: " + cmd);
if (cmd.startsWith("pm grant ") || cmd.startsWith("pm revoke ")) {
throw new UnsupportedOperationException("Use UiAutomation.grantRuntimePermission() "
+ "or revokeRuntimePermission() directly, which are more robust.");
}
ParcelFileDescriptor pfd = automation.executeShellCommand(cmd);
- byte[] buf = new byte[512];
- int bytesRead;
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- StringBuffer stdout = new StringBuffer();
- while ((bytesRead = fis.read(buf)) != -1) {
- stdout.append(new String(buf, 0, bytesRead));
+ try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
+ return FileUtils.readInputStreamFully(fis);
}
- fis.close();
- return stdout.toString();
}
/**
diff --git a/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java b/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java
index 7eff018..874282b 100644
--- a/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java
+++ b/hostsidetests/backup/src/android/cts/backup/ProfileScheduledJobHostSideTest.java
@@ -21,6 +21,9 @@
import android.platform.test.annotations.AppModeFull;
import com.android.compatibility.common.util.BackupUtils;
+import com.android.compatibility.common.util.ProtoUtils;
+import com.android.server.job.JobSchedulerServiceDumpProto;
+import com.android.server.job.JobStatusShortInfoProto;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -29,10 +32,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.IOException;
import java.util.Optional;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
/** Test that key-value and full backup jobs are scheduled in a profile. */
@RunWith(DeviceJUnit4ClassRunner.class)
@@ -60,7 +60,6 @@
private static final int TIMEOUT_FOR_KEY_VALUE_SECONDS = 5 * 60; // 5 minutes.
private static final int TIMEOUT_FOR_FULL_BACKUP_SECONDS = 5 * 60; // 5 minutes.
- private static final String DUMPSYS_JOB_SCHEDULER = "dumpsys jobscheduler";
private static final String JOB_SCHEDULER_RUN_COMMAND = "cmd jobscheduler run -f android";
private final BackupUtils mBackupUtils = getBackupUtils();
@@ -196,10 +195,19 @@
}
/** Returns {@code true} if there is a system job scheduled with the specified parameters. */
- private boolean isSystemJobScheduled(int jobId, String jobName) throws IOException {
- String output = mBackupUtils.executeShellCommandAndReturnOutput(DUMPSYS_JOB_SCHEDULER);
- String jobRegex = String.format("JOB #1000/%d.*%s", jobId, jobName);
- Matcher matcher = Pattern.compile(jobRegex).matcher(output.trim());
- return matcher.find();
+ private boolean isSystemJobScheduled(int jobId, String jobName) throws Exception {
+ // TODO: Look into making a higher level adb command or a system API for this instead.
+ // (e.g. "adb shell cmd jobscheduler is-job-scheduled system JOB-ID JOB-NAME")
+ final JobSchedulerServiceDumpProto dump =
+ ProtoUtils.getProto(mDevice, JobSchedulerServiceDumpProto.parser(),
+ ProtoUtils.DUMPSYS_JOB_SCHEDULER);
+ for (JobSchedulerServiceDumpProto.RegisteredJob job : dump.getRegisteredJobsList()) {
+ final JobStatusShortInfoProto info = job.getInfo();
+ if (info.getCallingUid() == 1000 && info.getJobId() == jobId
+ && jobName.equals(info.getBatteryName())) {
+ return true;
+ }
+ }
+ return false;
}
}
diff --git a/tests/tests/batterysaving/Android.bp b/tests/tests/batterysaving/Android.bp
index 032d2bf..b0007e2 100644
--- a/tests/tests/batterysaving/Android.bp
+++ b/tests/tests/batterysaving/Android.bp
@@ -22,6 +22,7 @@
"mockito-target-minus-junit4",
"compatibility-device-util-axt",
"ctstestrunner-axt",
+ "platformprotosnano",
"truth-prebuilt",
"ub-uiautomator",
],
diff --git a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java
index e2cf479..3db9dbb 100644
--- a/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java
+++ b/tests/tests/batterysaving/src/android/os/cts/batterysaving/BatterySavingTestBase.java
@@ -34,6 +34,9 @@
import com.android.compatibility.common.util.BatteryUtils;
import com.android.compatibility.common.util.BeforeAfterRule;
import com.android.compatibility.common.util.OnFailureRule;
+import com.android.compatibility.common.util.ProtoUtils;
+import com.android.server.job.nano.JobSchedulerServiceDumpProto;
+import com.android.server.job.nano.StateControllerProto;
import org.junit.Rule;
import org.junit.rules.RuleChain;
@@ -96,9 +99,19 @@
}
public void waitUntilJobForceAppStandby(boolean expected) throws Exception {
- waitUntil("Force all apps standby still " + !expected + " (job)", () ->
- runShellCommand("dumpsys jobscheduler")
- .contains("Force all apps standby: " + expected));
+ waitUntil("Force all apps standby still " + !expected + " (job)", () -> {
+ JobSchedulerServiceDumpProto proto = ProtoUtils.getProto(
+ InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+ JobSchedulerServiceDumpProto.class,
+ ProtoUtils.DUMPSYS_JOB_SCHEDULER);
+ for (StateControllerProto controllerProto : proto.controllers) {
+ if (controllerProto.hasBackground()) {
+ return controllerProto.getBackground().appStateTracker.forceAllAppsStandby
+ == expected;
+ }
+ }
+ return false;
+ });
}
public void waitUntilForceBackgroundCheck(boolean expected) throws Exception {
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index e9b639f..d7acb9c 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -54,7 +54,6 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
-import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -67,6 +66,7 @@
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.ProtoUtils;
import com.android.server.job.nano.JobSchedulerServiceDumpProto;
import com.android.server.job.nano.JobSchedulerServiceDumpProto.RegisteredJob;
@@ -77,8 +77,6 @@
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.io.ByteArrayOutputStream;
-import java.io.FileInputStream;
import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
@@ -213,26 +211,8 @@
* Get the state of the job scheduler
*/
public static JobSchedulerServiceDumpProto getJobSchedulerDump() throws Exception {
- ParcelFileDescriptor pfd = sUiAutomation.executeShellCommand("dumpsys jobscheduler --proto");
-
- try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
- // Copy data from 'is' into 'os'
- try (FileInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
- byte[] buffer = new byte[16384];
-
- while (true) {
- int numRead = is.read(buffer);
-
- if (numRead == -1) {
- break;
- } else {
- os.write(buffer, 0, numRead);
- }
- }
- }
-
- return JobSchedulerServiceDumpProto.parseFrom(os.toByteArray());
- }
+ return ProtoUtils.getProto(sUiAutomation, JobSchedulerServiceDumpProto.class,
+ ProtoUtils.DUMPSYS_JOB_SCHEDULER);
}
/**