diff --git a/core/java/android/os/TEST_MAPPING b/core/java/android/os/TEST_MAPPING
new file mode 100644
index 0000000000000..39c196d1a06c6
--- /dev/null
+++ b/core/java/android/os/TEST_MAPPING
@@ -0,0 +1,48 @@
+{
+ "presubmit": [
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "CtsBugreportTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "ShellTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases"
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "CtsBugreportTestCases"
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "ShellTests"
+ }
+ ]
+}
diff --git a/core/tests/bugreports/Android.bp b/core/tests/bugreports/Android.bp
index e9d5bb135e02c..e42b4b4ae2bf1 100644
--- a/core/tests/bugreports/Android.bp
+++ b/core/tests/bugreports/Android.bp
@@ -15,12 +15,22 @@
android_test {
name: "BugreportManagerTestCases",
srcs: ["src/**/*.java"],
+ data: [":bugreport_artifacts"],
libs: [
"android.test.runner",
"android.test.base",
],
- static_libs: ["androidx.test.rules", "truth-prebuilt"],
+ static_libs: [
+ "androidx.test.rules",
+ "androidx.test.uiautomator_uiautomator",
+ "truth-prebuilt",
+ ],
+ test_suites: ["general-tests"],
sdk_version: "test_current",
platform_apis: true,
}
+filegroup {
+ name: "bugreport_artifacts",
+ srcs: ["config/test-sysconfig.xml"],
+}
diff --git a/core/tests/bugreports/AndroidTest.xml b/core/tests/bugreports/AndroidTest.xml
index 410ca60435838..2c2f0d69e3474 100644
--- a/core/tests/bugreports/AndroidTest.xml
+++ b/core/tests/bugreports/AndroidTest.xml
@@ -21,11 +21,16 @@
-
-
-
+
+
+
+
+
+
+
-
+
+
diff --git a/core/tests/bugreports/run.sh b/core/tests/bugreports/run.sh
deleted file mode 100755
index 0103398365389..0000000000000
--- a/core/tests/bugreports/run.sh
+++ /dev/null
@@ -1,61 +0,0 @@
-#!/bin/bash
-
-# 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.
-
-# Script to run bugreport unitests
-# Must run on a rooted device.
-# Must run lunch before running the script
-# Usage: ${ANDROID_BUILD_TOP}/frameworks/base/core/tests/bugreports/run.sh
-
-# NOTE: This script replaces the framework-sysconfig.xml on your device, so use with caution.
-# It tries to replace it when done, but if the script does not finish cleanly
-# (for e.g. force stopped mid-way) your device will be left in an inconsistent state.
-# Reflashing will restore the right config.
-
-TMP_SYS_CONFIG=/var/tmp/framework-sysconfig.xml
-
-if [[ -z $ANDROID_PRODUCT_OUT ]]; then
- echo "Please lunch before running this test."
- exit 0
-fi
-
-# Print every command to console.
-set -x
-
-make -j BugreportManagerTestCases &&
- adb root &&
- adb remount &&
- adb wait-for-device &&
- # Save the sysconfig file in a tmp location and push the test config in
- adb pull /system/etc/sysconfig/framework-sysconfig.xml "${TMP_SYS_CONFIG}" &&
- adb push $ANDROID_BUILD_TOP/frameworks/base/core/tests/bugreports/config/test-sysconfig.xml /system/etc/sysconfig/framework-sysconfig.xml &&
- # The test app needs to be a priv-app.
- adb push $OUT/testcases/BugreportManagerTestCases/*/BugreportManagerTestCases.apk /system/priv-app ||
- exit 1
-
-adb reboot &&
-adb wait-for-device &&
-atest BugreportManagerTest || echo "Tests FAILED!"
-
-# Restore the saved config file
-if [ -f "${TMP_SYS_CONFIG}" ]; then
- SIZE=$(stat --printf="%s" "${TMP_SYS_CONFIG}")
- if [ SIZE > 0 ]; then
- adb remount &&
- adb wait-for-device &&
- adb push "${TMP_SYS_CONFIG}" /system/etc/sysconfig/framework-sysconfig.xml &&
- rm "${TMP_SYS_CONFIG}"
- fi
-fi
diff --git a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
similarity index 72%
rename from core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
rename to core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
index 153337727e967..9246a2335050e 100644
--- a/core/tests/bugreports/src/android/server/bugreports/BugreportManagerTest.java
+++ b/core/tests/bugreports/src/com/android/os/bugreports/tests/BugreportManagerTest.java
@@ -18,6 +18,8 @@ package com.android.os.bugreports.tests;
import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import android.Manifest;
@@ -25,17 +27,27 @@ import android.content.Context;
import android.os.BugreportManager;
import android.os.BugreportManager.BugreportCallback;
import android.os.BugreportParams;
+import android.os.FileUtils;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.ParcelFileDescriptor;
+import android.os.StrictMode;
import android.util.Log;
+import androidx.annotation.NonNull;
import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.UiDevice;
+import androidx.test.uiautomator.UiObject2;
+import androidx.test.uiautomator.Until;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExternalResource;
import org.junit.rules.TestName;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -51,9 +63,11 @@ import java.util.concurrent.TimeUnit;
@RunWith(JUnit4.class)
public class BugreportManagerTest {
@Rule public TestName name = new TestName();
+ @Rule public ExtendedStrictModeVmPolicy mTemporaryVmPolicy = new ExtendedStrictModeVmPolicy();
private static final String TAG = "BugreportManagerTest";
private static final long BUGREPORT_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(10);
+ private static final long UIAUTOMATOR_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(10);
private Handler mHandler;
private Executor mExecutor;
@@ -86,6 +100,8 @@ public class BugreportManagerTest {
@After
public void teardown() throws Exception {
dropPermissions();
+ FileUtils.closeQuietly(mBugreportFd);
+ FileUtils.closeQuietly(mScreenshotFd);
}
@@ -95,47 +111,45 @@ public class BugreportManagerTest {
// wifi bugreport does not take screenshot
mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, wifi(),
mExecutor, callback);
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
assertThat(callback.isDone()).isTrue();
// Wifi bugreports should not receive any progress.
assertThat(callback.hasReceivedProgress()).isFalse();
- // TODO: Because of b/130234145, consent dialog is not shown; so we get a timeout error.
- // When the bug is fixed, accept consent via UIAutomator and verify contents
- // of mBugreportFd.
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd);
}
+ @LargeTest
@Test
public void normalFlow_interactive() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
// interactive bugreport does not take screenshot
mBrm.startBugreport(mBugreportFd, null /*screenshotFd = null*/, interactive(),
mExecutor, callback);
-
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
+
assertThat(callback.isDone()).isTrue();
// Interactive bugreports show progress updates.
assertThat(callback.hasReceivedProgress()).isTrue();
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd);
}
+ @LargeTest
@Test
public void normalFlow_full() throws Exception {
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, mScreenshotFd, full(), mExecutor, callback);
-
+ shareConsentDialog(ConsentReply.ALLOW);
waitTillDoneOrTimeout(callback);
+
assertThat(callback.isDone()).isTrue();
- assertThat(callback.getErrorCode()).isEqualTo(
- BugreportCallback.BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT);
- // bugreport and screenshot files should be empty when user consent timed out.
- assertThat(mBugreportFile.length()).isEqualTo(0);
- assertThat(mScreenshotFile.length()).isEqualTo(0);
+ // bugreport and screenshot files shouldn't be empty when user consents.
+ assertThat(mBugreportFile.length()).isGreaterThan(0L);
+ assertThat(mScreenshotFile.length()).isGreaterThan(0L);
assertFdsAreClosed(mBugreportFd, mScreenshotFd);
}
@@ -144,6 +158,8 @@ public class BugreportManagerTest {
// Start bugreport #1
BugreportCallbackImpl callback = new BugreportCallbackImpl();
mBrm.startBugreport(mBugreportFd, mScreenshotFd, wifi(), mExecutor, callback);
+ // TODO(b/162389762) Make sure the wait time is reasonable
+ shareConsentDialog(ConsentReply.ALLOW);
// Before #1 is done, try to start #2.
assertThat(callback.isDone()).isFalse();
@@ -375,4 +391,88 @@ public class BugreportManagerTest {
private static BugreportParams full() {
return new BugreportParams(BugreportParams.BUGREPORT_MODE_FULL);
}
+
+ /* Allow/deny the consent dialog to sharing bugreport data or check existence only. */
+ private enum ConsentReply {
+ ALLOW,
+ DENY,
+ TIMEOUT
+ }
+
+ /*
+ * Ensure the consent dialog is shown and take action according to consentReply.
+ * It will fail if the dialog is not shown when ignoreNotFound is false.
+ */
+ private void shareConsentDialog(@NonNull ConsentReply consentReply) throws Exception {
+ mTemporaryVmPolicy.permitIncorrectContextUse();
+ final UiDevice device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+
+ // Unlock before finding/clicking an object.
+ device.wakeUp();
+ device.executeShellCommand("wm dismiss-keyguard");
+
+ final BySelector consentTitleObj = By.res("android", "alertTitle");
+ if (!device.wait(Until.hasObject(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS)) {
+ fail("The consent dialog is not found");
+ }
+ if (consentReply.equals(ConsentReply.TIMEOUT)) {
+ return;
+ }
+ final BySelector selector;
+ if (consentReply.equals(ConsentReply.ALLOW)) {
+ selector = By.res("android", "button1");
+ Log.d(TAG, "Allow the consent dialog");
+ } else { // ConsentReply.DENY
+ selector = By.res("android", "button2");
+ Log.d(TAG, "Deny the consent dialog");
+ }
+ final UiObject2 btnObj = device.findObject(selector);
+ assertNotNull("The button of consent dialog is not found", btnObj);
+ btnObj.click();
+
+ Log.d(TAG, "Wait for the dialog to be dismissed");
+ assertTrue(device.wait(Until.gone(consentTitleObj), UIAUTOMATOR_TIMEOUT_MS));
+ }
+
+ /**
+ * A rule to change strict mode vm policy temporarily till test method finished.
+ *
+ * To permit the non-visual context usage in tests while taking bugreports need user consent,
+ * or UiAutomator/BugreportManager.DumpstateListener would run into error.
+ * UiDevice#findObject creates UiObject2, its Gesture object and ViewConfiguration and
+ * UiObject2#click need to know bounds. Both of them access to WindowManager internally without
+ * visual context comes from InstrumentationRegistry and violate the policy.
+ * Also DumpstateListener violate the policy when onScreenshotTaken is called.
+ *
+ * TODO(b/161201609) Remove this class once violations fixed.
+ */
+ static class ExtendedStrictModeVmPolicy extends ExternalResource {
+ private boolean mWasVmPolicyChanged = false;
+ private StrictMode.VmPolicy mOldVmPolicy;
+
+ @Override
+ protected void after() {
+ restoreVmPolicyIfNeeded();
+ }
+
+ public void permitIncorrectContextUse() {
+ // Allow to call multiple times without losing old policy.
+ if (mOldVmPolicy == null) {
+ mOldVmPolicy = StrictMode.getVmPolicy();
+ }
+ StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
+ .detectAll()
+ .permitIncorrectContextUse()
+ .penaltyLog()
+ .build());
+ mWasVmPolicyChanged = true;
+ }
+
+ private void restoreVmPolicyIfNeeded() {
+ if (mWasVmPolicyChanged && mOldVmPolicy != null) {
+ StrictMode.setVmPolicy(mOldVmPolicy);
+ mOldVmPolicy = null;
+ }
+ }
+ }
}
diff --git a/packages/Shell/TEST_MAPPING b/packages/Shell/TEST_MAPPING
new file mode 100644
index 0000000000000..a149b5cda3eac
--- /dev/null
+++ b/packages/Shell/TEST_MAPPING
@@ -0,0 +1,31 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsBugreportTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "name": "ShellTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "name": "CtsBugreportTestCases"
+ },
+ {
+ "name": "ShellTests"
+ }
+ ]
+}
diff --git a/services/core/java/com/android/server/os/TEST_MAPPING b/services/core/java/com/android/server/os/TEST_MAPPING
index 502f1e852e086..d937af1e3fdb5 100644
--- a/services/core/java/com/android/server/os/TEST_MAPPING
+++ b/services/core/java/com/android/server/os/TEST_MAPPING
@@ -1,7 +1,51 @@
{
"presubmit": [
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "CtsBugreportTestCases",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
+ },
{
"name": "CtsUsbTests"
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "ShellTests",
+ "options": [
+ {
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ],
+ "postsubmit": [
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "BugreportManagerTestCases"
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "CtsBugreportTestCases"
+ },
+ {
+ "file_patterns": ["Bugreport[^/]*\\.java"],
+ "name": "ShellTests"
}
]
}