diff --git a/TEST_MAPPING b/TEST_MAPPING
index 1e0b58ef973c..55fa5ed13d79 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -8,5 +8,10 @@
}
]
}
+ ],
+ "postsubmit-managedprofile-stress": [
+ {
+ "name": "ManagedProfileLifecycleStressTest"
+ }
]
}
diff --git a/tests/ManagedProfileLifecycleStressTest/Android.bp b/tests/ManagedProfileLifecycleStressTest/Android.bp
new file mode 100644
index 000000000000..639ce3cfe935
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/Android.bp
@@ -0,0 +1,23 @@
+// 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.
+
+java_test_host {
+ name: "ManagedProfileLifecycleStressTest",
+ srcs: ["src/**/*.java"],
+ libs: ["tradefed"],
+ test_suites: ["device-tests"],
+ target_required: [
+ "DummyDPC",
+ ],
+}
diff --git a/tests/ManagedProfileLifecycleStressTest/AndroidTest.xml b/tests/ManagedProfileLifecycleStressTest/AndroidTest.xml
new file mode 100644
index 000000000000..e7dbc5118457
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/AndroidTest.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
new file mode 100644
index 000000000000..d95af340337e
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/Android.bp
@@ -0,0 +1,20 @@
+// 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.
+
+android_test {
+ name: "DummyDPC",
+ defaults: ["cts_defaults"],
+ srcs: ["src/**/*.java"],
+ sdk_version: "current",
+}
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
new file mode 100644
index 000000000000..860940d4e025
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/AndroidManifest.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/res/xml/device_admin.xml b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/res/xml/device_admin.xml
new file mode 100644
index 000000000000..4b3581e3e8da
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/res/xml/device_admin.xml
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/src/com/android/dummydpc/DummyDeviceAdminReceiver.java b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/src/com/android/dummydpc/DummyDeviceAdminReceiver.java
new file mode 100644
index 000000000000..92190b73b0ff
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/app/DummyDPC/src/com/android/dummydpc/DummyDeviceAdminReceiver.java
@@ -0,0 +1,25 @@
+/*
+ * 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.dummydpc;
+
+import android.app.admin.DeviceAdminReceiver;
+
+/**
+ * Empty admin to use as a managed profile owner.
+ */
+public class DummyDeviceAdminReceiver extends DeviceAdminReceiver {
+}
+
diff --git a/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
new file mode 100644
index 000000000000..e323592d40ca
--- /dev/null
+++ b/tests/ManagedProfileLifecycleStressTest/src/com/android/test/stress/ManagedProfileLifecycleStressTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.test.stress;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.TimeUnit;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A test to exercise Android Framework parts related to creating, starting, stopping, and deleting
+ * a managed profile as much as possible. The aim is to catch any issues in this code before it
+ * affects managed profile CTS tests.
+ */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class ManagedProfileLifecycleStressTest extends BaseHostJUnit4Test {
+ // Stop the test once this time limit has been reached. 25 minutes used as a limit to make total
+ // test time less than 30 minutes, so that it can be put into presubmit.
+ private static final int TIME_LIMIT_MINUTES = 25;
+
+ private static final String DUMMY_DPC_APK = "DummyDPC.apk";
+ private static final String DUMMY_DPC_COMPONENT =
+ "com.android.dummydpc/com.android.dummydpc.DummyDeviceAdminReceiver";
+ private static final Pattern CREATE_USER_OUTPUT_REGEX =
+ Pattern.compile("Success: created user id (\\d+)");
+
+ /**
+ * Create, start, and kill managed profiles in a loop.
+ */
+ @Test
+ public void testCreateStartDelete() throws Exception {
+ int iteration = 0;
+ final long deadline = System.nanoTime() + TimeUnit.MINUTES.toNanos(TIME_LIMIT_MINUTES);
+ while (System.nanoTime() < deadline) {
+ iteration++;
+ CLog.w("Iteration N" + iteration);
+ final int userId = createManagedProfile();
+ startUser(userId);
+ installPackageAsUser(DUMMY_DPC_APK, true /* grantPermissions */, userId, "-t");
+ setProfileOwner(DUMMY_DPC_COMPONENT, userId);
+ removeUser(userId);
+ }
+ CLog.w("Completed " + iteration + " iterations.");
+ }
+
+ private int createManagedProfile() throws Exception {
+ final String output = getDevice().executeShellCommand(
+ "pm create-user --profileOf 0 --managed TestProfile");
+ final Matcher matcher = CREATE_USER_OUTPUT_REGEX.matcher(output.trim());
+ if (!matcher.matches() || matcher.groupCount() != 1) {
+ fail("user creation failed, output: " + output);
+ }
+ return Integer.parseInt(matcher.group(1));
+ }
+
+ private void setProfileOwner(String componentName, int userId) throws Exception {
+ String command = "dpm set-profile-owner --user " + userId + " '" + componentName + "'";
+ String commandOutput = getDevice().executeShellCommand(command);
+ assertTrue("Unexpected dpm output: " + commandOutput, commandOutput.startsWith("Success:"));
+ }
+
+ private void removeUser(int userId) throws Exception {
+ final String output = getDevice().executeShellCommand("pm remove-user " + userId).trim();
+ assertEquals("Unexpected pm output: " + output, "Success: removed user", output);
+ }
+
+ private void startUser(int userId) throws Exception {
+ final String output = getDevice().executeShellCommand("am start-user -w " + userId).trim();
+ assertEquals("Unexpected am output: " + output, "Success: user started", output);
+ }
+}