Make storage and StrictMode tests more robust.

Many of the AppSecurity tests verify cross-user interactions by
creating and starting temporary users on multi-user devices.  Since
user creation adds significant overhead, this change creates a
secondary and tertiary user only once for the entire module, which
individual tests can then efficiently reuse.

Quietly skip testFullDisk() when we're unable to free up more than
90% of disk space, since that's a prerequisite for that test.

Rewrite StrictModeTest to use explicit listener for observing
violations, since reading back raw logcat data recently became
very flaky.

Test: cts-tradefed run commandAndExit cts-dev -m CtsOsTestCases -t android.os.cts.StrictModeTest
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.StorageHostTest
Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.ExternalStorageHostTest
Bug: 38234598, 37486230, 37915178, 62018992
Change-Id: I97182aaa8c82cdc0a1169d5b4adac053c84a1b11
diff --git a/hostsidetests/appsecurity/AndroidTest.xml b/hostsidetests/appsecurity/AndroidTest.xml
index d1989e6..418d363 100644
--- a/hostsidetests/appsecurity/AndroidTest.xml
+++ b/hostsidetests/appsecurity/AndroidTest.xml
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 <configuration description="Config for the CTS App Security host tests">
+    <target_preparer class="android.appsecurity.cts.AppSecurityPreparer" />
     <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
         <option name="jar" value="CtsAppSecurityHostTestCases.jar" />
         <option name="runtime-hint" value="20m" />
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index 16e2765..a1bcc30 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -55,6 +55,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityPreparer.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityPreparer.java
new file mode 100644
index 0000000..b1ac744
--- /dev/null
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityPreparer.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2017 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 android.appsecurity.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetCleaner;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * Creates secondary and tertiary users for use during a test suite.
+ */
+public class AppSecurityPreparer implements ITargetPreparer, ITargetCleaner {
+    @Override
+    public void setUp(ITestDevice device, IBuildInfo buildInfo)
+            throws TargetSetupError, BuildError, DeviceNotAvailableException {
+        // Clean up any lingering users from other tests to ensure that we have
+        // best shot at creating the users we need below.
+        removeSecondaryUsers(device);
+
+        final int maxUsers = device.getMaxNumberOfUsersSupported();
+        if (maxUsers > 1) {
+            CLog.logAndDisplay(LogLevel.INFO,
+                    "Created secondary user " + device.createUser("CTS_" + System.nanoTime()));
+        }
+        if (maxUsers > 2) {
+            CLog.logAndDisplay(LogLevel.INFO,
+                    "Created secondary user " + device.createUser("CTS_" + System.nanoTime()));
+        }
+    }
+
+    @Override
+    public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable throwable)
+            throws DeviceNotAvailableException {
+        removeSecondaryUsers(device);
+    }
+
+    private void removeSecondaryUsers(ITestDevice device) throws DeviceNotAvailableException {
+        final int[] userIds = Utils.getAllUsers(device);
+        for (int i = 1; i < userIds.length; i++) {
+            device.removeUser(userIds[i]);
+            CLog.logAndDisplay(LogLevel.INFO, "Destroyed secondary user " + userIds[i]);
+        }
+    }
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index 36b0921..390064d 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -110,7 +110,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        // ensure build has been set before test is run
+
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mCtsBuild);
     }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
index 69ff55e..920e0a5 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/BaseAppSecurityTest.java
@@ -17,29 +17,17 @@
 package android.appsecurity.cts;
 
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.ddmlib.testrunner.TestResult;
-import com.android.ddmlib.testrunner.TestRunResult;
-import com.android.ddmlib.testrunner.TestResult.TestStatus;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.result.CollectingTestListener;
 import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.testtype.IBuildReceiver;
 
 import java.util.ArrayList;
-import java.util.Map;
 
 /**
  * Base class.
  */
 public class BaseAppSecurityTest extends DeviceTestCase implements IBuildReceiver {
-    protected static final int USER_SYSTEM = 0; // From the UserHandle class.
-
-    private static final String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
-
     protected IBuildInfo mBuildInfo;
 
     /** Whether multi-user is supported. */
@@ -62,49 +50,12 @@
         mSupportsMultiUser = getDevice().getMaxNumberOfUsersSupported() > 1;
         mIsSplitSystemUser = checkIfSplitSystemUser();
         mPrimaryUserId = getDevice().getPrimaryUserId();
-        mFixedUsers = new ArrayList();
+        mFixedUsers = new ArrayList<>();
         mFixedUsers.add(mPrimaryUserId);
-        if (mPrimaryUserId != USER_SYSTEM) {
-            mFixedUsers.add(USER_SYSTEM);
+        if (mPrimaryUserId != Utils.USER_SYSTEM) {
+            mFixedUsers.add(Utils.USER_SYSTEM);
         }
         getDevice().switchUser(mPrimaryUserId);
-        removeTestUsers();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        removeTestUsers();
-        super.tearDown();
-    }
-
-    /**
-     * @return the userid of the created user
-     */
-    protected int createUser() throws DeviceNotAvailableException, IllegalStateException {
-        final String command = "pm create-user "
-                + "TestUser_" + System.currentTimeMillis();
-        CLog.d("Starting command: " + command);
-        final String output = getDevice().executeShellCommand(command);
-        CLog.d("Output for command " + command + ": " + output);
-
-        if (output.startsWith("Success")) {
-            try {
-                return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim());
-            } catch (NumberFormatException e) {
-                CLog.e("Failed to parse result: %s", output);
-            }
-        } else {
-            CLog.e("Failed to create user: %s", output);
-        }
-        throw new IllegalStateException();
-    }
-
-    private void removeTestUsers() throws Exception {
-        for (int userId : getDevice().listUsers()) {
-            if (!mFixedUsers.contains(userId)) {
-                getDevice().removeUser(userId);
-            }
-        }
     }
 
     private boolean checkIfSplitSystemUser() throws DeviceNotAvailableException {
@@ -131,37 +82,4 @@
         String output = getDevice().executeShellCommand(command);
         return output.contains(packageName);
     }
-
-    private void printTestResult(TestRunResult runResult) {
-        for (Map.Entry<TestIdentifier, TestResult> testEntry :
-                runResult.getTestResults().entrySet()) {
-            TestResult testResult = testEntry.getValue();
-            CLog.d("Test " + testEntry.getKey() + ": " + testResult.getStatus());
-            if (testResult.getStatus() != TestStatus.PASSED) {
-                CLog.d(testResult.getStackTrace());
-            }
-        }
-    }
-
-    protected boolean runDeviceTestsAsUser(String packageName,
-            String testClassName, String testMethodName, int userId) throws Exception {
-        if (testClassName != null && testClassName.startsWith(".")) {
-            testClassName = packageName + testClassName;
-        }
-
-        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
-                packageName, RUNNER, getDevice().getIDevice());
-        if (testClassName != null && testMethodName != null) {
-            testRunner.setMethodName(testClassName, testMethodName);
-        } else if (testClassName != null) {
-            testRunner.setClassName(testClassName);
-        }
-
-        CollectingTestListener listener = new CollectingTestListener();
-        assertTrue(getDevice().runInstrumentationTestsAsUser(testRunner, userId, listener));
-
-        TestRunResult runResult = listener.getCurrentRunResults();
-        printTestResult(runResult);
-        return !runResult.hasFailedTests() && runResult.getNumTestsInState(TestStatus.PASSED) > 0;
-    }
-}
\ No newline at end of file
+}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 6a6c27d..2174fa0 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -54,6 +54,7 @@
 
     private String mFeatureList = null;
 
+    private int[] mUsers;
     private IAbi mAbi;
     private IBuildInfo mCtsBuild;
 
@@ -71,6 +72,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        mUsers = Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
@@ -148,11 +150,8 @@
     }
 
     public void doDirectBootTest(String mode) throws Exception {
-        int[] users = {};
         boolean doTest = true;
         try {
-            users = createUsersForTest();
-
             // Set up test app and secure lock screens
             new InstallMultiple().addApk(APK).run();
             new InstallMultiple().addApk(OTHER_APK).run();
@@ -164,7 +163,7 @@
             // Give enough time for PackageManager to persist stopped state
             Thread.sleep(15000);
 
-            runDeviceTests(PKG, CLASS, "testSetUp", users);
+            runDeviceTests(PKG, CLASS, "testSetUp", mUsers);
 
             // Give enough time for vold to update keys
             Thread.sleep(15000);
@@ -184,19 +183,18 @@
 
             if (doTest) {
                 if (MODE_NONE.equals(mode)) {
-                    runDeviceTests(PKG, CLASS, "testVerifyUnlockedAndDismiss", users);
+                    runDeviceTests(PKG, CLASS, "testVerifyUnlockedAndDismiss", mUsers);
                 } else {
-                    runDeviceTests(PKG, CLASS, "testVerifyLockedAndDismiss", users);
+                    runDeviceTests(PKG, CLASS, "testVerifyLockedAndDismiss", mUsers);
                 }
             }
 
         } finally {
             try {
                 // Remove secure lock screens and tear down test app
-                runDeviceTests(PKG, CLASS, "testTearDown", users);
+                runDeviceTests(PKG, CLASS, "testTearDown", mUsers);
             } finally {
                 getDevice().uninstallPackage(PKG);
-                removeUsersForTest(users);
 
                 // Get ourselves back into a known-good state
                 if (MODE_EMULATED.equals(mode)) {
@@ -211,16 +209,6 @@
         }
     }
 
-    private int[] createUsersForTest() throws DeviceNotAvailableException {
-        // TODO: enable test for multiple users
-        return new int[] { 0 };
-//        return Utils.createUsersForTest(getDevice());
-    }
-
-    private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
-        Utils.removeUsersForTest(getDevice(), users);
-    }
-
     private void runDeviceTests(String packageName, String testClassName, String testMethodName,
             int... users) throws DeviceNotAvailableException {
         for (int user : users) {
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
index ceb7539..7bdd128 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -48,6 +48,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
index 915f147..8397f54 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/EphemeralTest.java
@@ -70,6 +70,7 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mBuildInfo);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index e8dca57..87d8bd6 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -52,6 +52,7 @@
     private static final String MULTIUSER_PKG = "com.android.cts.multiuserstorageapp";
     private static final String MULTIUSER_CLASS = ".MultiUserStorageTest";
 
+    private int[] mUsers;
     private IAbi mAbi;
     private IBuildInfo mCtsBuild;
 
@@ -74,6 +75,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        mUsers = Utils.prepareMultipleUsers(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
     }
@@ -87,7 +89,6 @@
      * Verify that app with no external storage permissions works correctly.
      */
     public void testExternalStorageNone() throws Exception {
-        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage();
 
@@ -95,13 +96,12 @@
             String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(NONE_PKG, COMMON_CLASS, user);
                 runDeviceTests(NONE_PKG, NONE_CLASS, user);
             }
         } finally {
             getDevice().uninstallPackage(NONE_PKG);
-            removeUsersForTest(users);
         }
     }
 
@@ -111,7 +111,6 @@
      * correctly.
      */
     public void testExternalStorageRead() throws Exception {
-        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage();
 
@@ -119,13 +118,12 @@
             String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, COMMON_CLASS, user);
                 runDeviceTests(READ_PKG, READ_CLASS, user);
             }
         } finally {
             getDevice().uninstallPackage(READ_PKG);
-            removeUsersForTest(users);
         }
     }
 
@@ -135,7 +133,6 @@
      * correctly.
      */
     public void testExternalStorageWrite() throws Exception {
-        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage();
 
@@ -143,13 +140,12 @@
             String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(WRITE_PKG, COMMON_CLASS, user);
                 runDeviceTests(WRITE_PKG, WRITE_CLASS, user);
             }
         } finally {
             getDevice().uninstallPackage(WRITE_PKG);
-            removeUsersForTest(users);
         }
     }
 
@@ -158,7 +154,6 @@
      * directories belonging to other apps, and those apps can read.
      */
     public void testExternalStorageGifts() throws Exception {
-        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage();
 
@@ -170,13 +165,13 @@
             // We purposefully delay the installation of the reading apps to
             // verify that the daemon correctly invalidates any caches.
             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(WRITE_PKG, ".WriteGiftTest", user);
             }
 
             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, ".ReadGiftTest", user);
                 runDeviceTests(NONE_PKG, ".GiftTest", user);
             }
@@ -184,7 +179,6 @@
             getDevice().uninstallPackage(NONE_PKG);
             getDevice().uninstallPackage(READ_PKG);
             getDevice().uninstallPackage(WRITE_PKG);
-            removeUsersForTest(users);
         }
     }
 
@@ -193,15 +187,14 @@
      * isolated storage.
      */
     public void testMultiUserStorageIsolated() throws Exception {
-        final int[] users = createUsersForTest();
         try {
-            if (users.length == 1) {
+            if (mUsers.length == 1) {
                 Log.d(TAG, "Single user device; skipping isolated storage tests");
                 return;
             }
 
-            final int owner = users[0];
-            final int secondary = users[1];
+            final int owner = mUsers[0];
+            final int secondary = mUsers[1];
 
             // Install our test app
             getDevice().uninstallPackage(MULTIUSER_PKG);
@@ -231,7 +224,6 @@
             runDeviceTests(MULTIUSER_PKG, MULTIUSER_CLASS, "testMediaProviderUserIsolation", secondary);
         } finally {
             getDevice().uninstallPackage(MULTIUSER_PKG);
-            removeUsersForTest(users);
         }
     }
 
@@ -240,7 +232,6 @@
      * when apps with r/w permission levels move around their files.
      */
     public void testMultiViewMoveConsistency() throws Exception {
-        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage();
 
@@ -252,37 +243,35 @@
             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testFolderSetup", user);
             }
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testRWAccess", user);
             }
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(WRITE_PKG, ".WriteMultiViewTest", "testMoveAway", user);
             }
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testROAccess", user);
             }
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(WRITE_PKG, ".WriteMultiViewTest", "testMoveBack", user);
             }
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, ".ReadMultiViewTest", "testRWAccess", user);
             }
         } finally {
             getDevice().uninstallPackage(NONE_PKG);
             getDevice().uninstallPackage(READ_PKG);
             getDevice().uninstallPackage(WRITE_PKG);
-            removeUsersForTest(users);
         }
     }
 
     /** Verify that app without READ_EXTERNAL can play default URIs in external storage. */
     public void testExternalStorageReadDefaultUris() throws Exception {
-        final int[] users = createUsersForTest();
         try {
             wipePrimaryExternalStorage();
 
@@ -293,7 +282,7 @@
             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
 
-            for (int user : users) {
+            for (int user : mUsers) {
                 enableWriteSettings(WRITE_PKG, user);
                 runDeviceTests(
                         WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testChangeDefaultUris", user);
@@ -303,13 +292,12 @@
             }
         } finally {
             // Make sure the provider and uris are reset on failure.
-            for (int user : users) {
+            for (int user : mUsers) {
                 runDeviceTests(
                         WRITE_PKG, WRITE_PKG + ".ChangeDefaultUris", "testResetDefaultUris", user);
             }
             getDevice().uninstallPackage(NONE_PKG);
             getDevice().uninstallPackage(WRITE_PKG);
-            removeUsersForTest(users);
         }
     }
 
@@ -334,14 +322,6 @@
         getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
     }
 
-    private int[] createUsersForTest() throws DeviceNotAvailableException {
-        return Utils.createUsersForTest(getDevice());
-    }
-
-    private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
-        Utils.removeUsersForTest(getDevice(), users);
-    }
-
     private void runDeviceTests(String packageName, String testClassName, int userId)
             throws DeviceNotAvailableException {
         Utils.runDeviceTests(getDevice(), packageName, testClassName, userId);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java
index fb5dffa..4609e8a 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantAppUserTest.java
@@ -19,8 +19,6 @@
 import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
 import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.log.LogUtil.CLog;
 import com.android.tradefed.testtype.DeviceTestCase;
 import com.android.tradefed.testtype.IAbi;
 import com.android.tradefed.testtype.IAbiReceiver;
@@ -73,8 +71,9 @@
         assertNotNull(mAbi);
         assertNotNull(mBuildInfo);
 
-        mSupportsMultiUser =
-                getDevice().getMaxNumberOfUsersSupported() - getDevice().listUsers().size() >= 2;
+        // This test only runs when we have at least 3 users to work with
+        final int[] users = Utils.prepareMultipleUsers(getDevice(), 3);
+        mSupportsMultiUser = (users.length == 3);
         if (mSupportsMultiUser) {
             mPrimaryUserId = getDevice().getPrimaryUserId();
             mFixedUsers = new ArrayList<>();
@@ -83,8 +82,9 @@
                 mFixedUsers.add(USER_SYSTEM);
             }
             getDevice().switchUser(mPrimaryUserId);
-            removeTestUsers();
-            createTestUsers();
+
+            mTestUser[0] = users[1];
+            mTestUser[1] = users[2];
 
             uninstallTestPackages();
             installTestPackages();
@@ -93,7 +93,6 @@
 
     public void tearDown() throws Exception {
         if (mSupportsMultiUser) {
-            removeTestUsers();
             uninstallTestPackages();
         }
         super.tearDown();
@@ -180,19 +179,6 @@
         getDevice().uninstallPackage(USER_PKG);
     }
 
-    private void createTestUsers() throws Exception {
-        mTestUser[0] = getDevice().createUser("TestUser_" + System.currentTimeMillis());
-        mTestUser[1] = getDevice().createUser("TestUser_" + System.currentTimeMillis());
-    }
-
-    private void removeTestUsers() throws Exception {
-        for (int userId : getDevice().listUsers()) {
-            if (!mFixedUsers.contains(userId)) {
-                getDevice().removeUser(userId);
-            }
-        }
-    }
-
     private void runDeviceTests(String packageName, String testClassName, String testMethodName)
             throws DeviceNotAvailableException {
         Utils.runDeviceTests(getDevice(), packageName, testClassName, testMethodName);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java
index e5a483c..fd599ea 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/InstantCookieHostTest.java
@@ -39,6 +39,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        Utils.prepareSingleUser(getDevice());
         uninstallPackage(INSTANT_COOKIE_APP_PKG);
         clearUserData(INSTANT_COOKIE_APP_PKG);
     }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
index ed05837..8795fe8 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/IsolatedSplitsTests.java
@@ -43,6 +43,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
+
+        Utils.prepareSingleUser(getDevice());
         getDevice().uninstallPackage(PKG);
     }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
index 1f7c6be..3574191 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -236,10 +236,13 @@
     }
 
     @Override
-        protected void setUp() throws Exception {
+    protected void setUp() throws Exception {
         super.setUp();
-        mDevice = getDevice();
+
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mCtsBuild);
+
+        mDevice = getDevice();
     }
 
     /**
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
index 115ebf4..fde9f10 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PackageVisibilityTest.java
@@ -32,10 +32,13 @@
     private static final boolean MATCH_UNINSTALLED = true;
     private static final boolean MATCH_NORMAL = false;
 
+    private int[] mUsers;
     private String mOldVerifierValue;
 
     public void setUp() throws Exception {
         super.setUp();
+
+        mUsers = Utils.prepareMultipleUsers(getDevice());
         mOldVerifierValue =
                 getDevice().executeShellCommand("settings get global package_verifier_enable");
         getDevice().executeShellCommand("settings put global package_verifier_enable 0");
@@ -54,7 +57,7 @@
             return;
         }
 
-        int userId = createUser();
+        int userId = mUsers[1];
         assertTrue(userId > 0);
         getDevice().startUser(userId);
         installTestAppForUser(TEST_APK, userId);
@@ -67,23 +70,23 @@
         assertTrue(isAppVisibleForUser(TINY_PKG, mPrimaryUserId, MATCH_UNINSTALLED));
 
         // Try the same from an app
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_inUser", mPrimaryUserId));
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_inUserUninstalled", mPrimaryUserId));
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_inUser", mPrimaryUserId);
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_inUserUninstalled", mPrimaryUserId);
 
         // It is not visible for the other user using shell commands
         assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
         assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
 
         // Try the same from an app
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_notInOtherUser", userId));
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled", userId));
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_notInOtherUser", userId);
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled", userId);
 
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", userId));
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", userId);
 
         getDevice().uninstallPackage(TINY_PKG);
 
@@ -105,14 +108,14 @@
         assertFalse(isAppVisibleForUser(TINY_PKG, userId, MATCH_NORMAL));
         assertTrue(isAppVisibleForUser(TINY_PKG, userId, MATCH_UNINSTALLED));
 
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_getPackagesCanSeeTiny", userId));
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_getPackagesCanSeeTiny", userId);
 
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
                 ".PackageAccessTest", "testPackageAccess_notInOtherUserUninstalled",
-                mPrimaryUserId));
-        assertTrue(runDeviceTestsAsUser(TEST_PKG,
-                ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", mPrimaryUserId));
+                mPrimaryUserId);
+        Utils.runDeviceTests(getDevice(), TEST_PKG,
+                ".PackageAccessTest", "testPackageAccess_getPackagesCantSeeTiny", mPrimaryUserId);
 
         getDevice().uninstallPackage(TINY_PKG);
         getDevice().uninstallPackage(TEST_PKG);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index b7f7f88..9ba3c82 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -58,6 +58,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mBuildHelper);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
index 93d683f..e87c390 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PkgInstallSignatureVerificationTest.java
@@ -16,6 +16,11 @@
 
 package android.appsecurity.cts;
 
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.testtype.DeviceTestCase;
+import com.android.tradefed.testtype.IBuildReceiver;
+
 import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
@@ -24,12 +29,6 @@
 import java.io.OutputStream;
 import java.util.Locale;
 
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.device.ITestDevice;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
-
 /**
  * Tests for APK signature verification during installation.
  */
@@ -44,10 +43,6 @@
     private static final String[] RSA_KEY_NAMES_2048_AND_LARGER =
             {"2048", "3072", "4096", "8192", "16384"};
 
-
-    /** Device under test. */
-    private ITestDevice mDevice;
-
     private IBuildInfo mCtsBuild;
 
     @Override
@@ -58,7 +53,8 @@
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mDevice = getDevice();
+
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mCtsBuild);
         uninstallPackage();
     }
@@ -582,9 +578,9 @@
                 }
             }
             if (ephemeral) {
-                return mDevice.installPackage(apkFile, true, "--ephemeral");
+                return getDevice().installPackage(apkFile, true, "--ephemeral");
             } else {
-                return mDevice.installPackage(apkFile, true);
+                return getDevice().installPackage(apkFile, true);
             }
         } finally {
             apkFile.delete();
@@ -602,6 +598,6 @@
     }
 
     private String uninstallPackage() throws DeviceNotAvailableException {
-        return mDevice.uninstallPackage(TEST_PKG);
+        return getDevice().uninstallPackage(TEST_PKG);
     }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
index ca218ef..630f351 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -63,6 +63,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mBuildHelper);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index 21bfca1..9474ba8 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -96,6 +96,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mCtsBuild);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
index f679e83..f08e4fe 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/StorageHostTest.java
@@ -16,18 +16,22 @@
 
 package android.appsecurity.cts;
 
-import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
-import com.android.tradefed.build.IBuildInfo;
+import com.android.compatibility.common.tradefed.testtype.CompatibilityHostTestBase;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IAbi;
-import com.android.tradefed.testtype.IAbiReceiver;
-import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import junit.framework.AssertionFailedError;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Tests that exercise various storage APIs.
  */
-public class StorageHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class StorageHostTest extends CompatibilityHostTestBase {
     private static final String PKG_STATS = "com.android.cts.storagestatsapp";
     private static final String PKG_A = "com.android.cts.storageapp_a";
     private static final String PKG_B = "com.android.cts.storageapp_b";
@@ -37,49 +41,15 @@
     private static final String CLASS_STATS = "com.android.cts.storagestatsapp.StorageStatsTest";
     private static final String CLASS = "com.android.cts.storageapp.StorageTest";
 
-    private IAbi mAbi;
-    private IBuildInfo mCtsBuild;
-
     private int[] mUsers;
 
-    @Override
-    public void setAbi(IAbi abi) {
-        mAbi = abi;
-    }
+    @Before
+    public void setUp() throws Exception {
+        mUsers = Utils.prepareMultipleUsers(getDevice());
 
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-
-        mUsers = Utils.createUsersForTest(getDevice());
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        super.tearDown();
-
-        getDevice().uninstallPackage(PKG_STATS);
-        getDevice().uninstallPackage(PKG_A);
-        getDevice().uninstallPackage(PKG_B);
-
-        Utils.removeUsersForTest(getDevice(), mUsers);
-        mUsers = null;
-    }
-
-    private void prepareTestApps() throws Exception {
-        getDevice().uninstallPackage(PKG_STATS);
-        getDevice().uninstallPackage(PKG_A);
-        getDevice().uninstallPackage(PKG_B);
-
-        CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
-        assertNull(getDevice().installPackage(buildHelper.getTestFile(APK_STATS), false));
-        assertNull(getDevice().installPackage(buildHelper.getTestFile(APK_A), false));
-        assertNull(getDevice().installPackage(buildHelper.getTestFile(APK_B), false));
+        installPackage(APK_STATS);
+        installPackage(APK_A);
+        installPackage(APK_B);
 
         for (int user : mUsers) {
             getDevice().executeShellCommand("appops set --user " + user + " " + PKG_STATS
@@ -87,26 +57,20 @@
         }
     }
 
-    public void testEverything() throws Exception {
-        prepareTestApps(); doVerifyQuota();
-        prepareTestApps(); doVerifyAppStats();
-        prepareTestApps(); doVerifyAppQuota();
-        prepareTestApps(); doVerifyAppAllocate();
-        prepareTestApps(); doVerifySummary();
-        prepareTestApps(); doVerifyStats();
-        prepareTestApps(); doVerifyStatsMultiple();
-        prepareTestApps(); doVerifyStatsExternal();
-        prepareTestApps(); doVerifyStatsExternalConsistent();
-        prepareTestApps(); doVerifyCategory();
-        prepareTestApps(); doCache();
-        prepareTestApps(); doFullDisk();
+    @After
+    public void tearDown() throws Exception {
+        getDevice().uninstallPackage(PKG_STATS);
+        getDevice().uninstallPackage(PKG_A);
+        getDevice().uninstallPackage(PKG_B);
     }
 
-    public void doVerifyQuota() throws Exception {
-        runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyQuota", Utils.USER_OWNER);
+    @Test
+    public void testVerifyQuota() throws Exception {
+        Utils.runDeviceTests(getDevice(), PKG_STATS, CLASS_STATS, "testVerifyQuota");
     }
 
-    public void doVerifyAppStats() throws Exception {
+    @Test
+    public void testVerifyAppStats() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_A, CLASS, "testAllocate", user);
         }
@@ -120,31 +84,36 @@
         }
     }
 
-    public void doVerifyAppQuota() throws Exception {
+    @Test
+    public void testVerifyAppQuota() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_A, CLASS, "testVerifyQuotaApi", user);
         }
     }
 
-    public void doVerifyAppAllocate() throws Exception {
+    @Test
+    public void testVerifyAppAllocate() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_A, CLASS, "testVerifyAllocateApi", user);
         }
     }
 
-    public void doVerifySummary() throws Exception {
+    @Test
+    public void testVerifySummary() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifySummary", user);
         }
     }
 
-    public void doVerifyStats() throws Exception {
+    @Test
+    public void testVerifyStats() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyStats", user);
         }
     }
 
-    public void doVerifyStatsMultiple() throws Exception {
+    @Test
+    public void testVerifyStatsMultiple() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_A, CLASS, "testAllocate", user);
             runDeviceTests(PKG_A, CLASS, "testAllocate", user);
@@ -157,25 +126,29 @@
         }
     }
 
-    public void doVerifyStatsExternal() throws Exception {
+    @Test
+    public void testVerifyStatsExternal() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyStatsExternal", user);
         }
     }
 
-    public void doVerifyStatsExternalConsistent() throws Exception {
+    @Test
+    public void testVerifyStatsExternalConsistent() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyStatsExternalConsistent", user);
         }
     }
 
-    public void doVerifyCategory() throws Exception {
+    @Test
+    public void testVerifyCategory() throws Exception {
         for (int user : mUsers) {
             runDeviceTests(PKG_STATS, CLASS_STATS, "testVerifyCategory", user);
         }
     }
 
-    public void doCache() throws Exception {
+    @Test
+    public void testCache() throws Exception {
         // To make the cache clearing logic easier to verify, ignore any cache
         // and low space reserved space.
         getDevice().executeShellCommand("settings put global sys_storage_threshold_max_bytes 0");
@@ -197,7 +170,8 @@
         }
     }
 
-    public void doFullDisk() throws Exception {
+    @Test
+    public void testFullDisk() throws Exception {
         waitForIdle();
 
         // Clear all other cached and external storage data to give ourselves a
@@ -209,9 +183,18 @@
         final String lastEvent = getDevice().executeShellCommand("logcat -d -b events -t 1");
         final String sinceTime = lastEvent.trim().substring(0, 18);
 
-        // Try our hardest to fill up the entire disk
-        runDeviceTests(PKG_A, CLASS, "testFullDisk", Utils.USER_OWNER);
-        runDeviceTests(PKG_A, CLASS, "testTweakComponent", Utils.USER_OWNER);
+        try {
+            // Try our hardest to fill up the entire disk
+            Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testFullDisk");
+        } catch (Throwable t) {
+            // If we had trouble filling the disk, don't bother going any
+            // further; we failed because we either don't have quota support, or
+            // because disk was more than 10% full.
+            return;
+        }
+
+        // Tweak something that causes PackageManager to persist data
+        Utils.runDeviceTests(getDevice(), PKG_A, CLASS, "testTweakComponent");
 
         // Try poking around a couple of settings apps
         getDevice().executeShellCommand("input keyevent KEY_HOME");
@@ -234,7 +217,7 @@
         troubleLogs = troubleLogs.trim().replaceAll("\\-+ beginning of [a-z]+", "");
 
         if (troubleLogs.length() > 4) {
-            fail("Unexpected crashes while disk full: " + troubleLogs);
+            throw new AssertionFailedError("Unexpected crashes while disk full: " + troubleLogs);
         }
     }
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
index cf8a354..4afeb9bf 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -51,6 +51,7 @@
     protected void setUp() throws Exception {
         super.setUp();
 
+        Utils.prepareSingleUser(getDevice());
         assertNotNull(mAbi);
         assertNotNull(mBuildHelper);
 
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
index 37aaeaf..8e83c87 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -16,7 +16,6 @@
 
 package android.appsecurity.cts;
 
-import com.android.ddmlib.Log;
 import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.ddmlib.testrunner.TestIdentifier;
 import com.android.ddmlib.testrunner.TestResult;
@@ -26,16 +25,15 @@
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.result.CollectingTestListener;
 
+import java.util.Arrays;
 import java.util.Map;
 
 public class Utils {
-    private static final String TAG = "AppSecurity";
-
-    public static final int USER_OWNER = 0;
+    public static final int USER_SYSTEM = 0;
 
     public static void runDeviceTests(ITestDevice device, String packageName)
             throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, null, null, USER_OWNER);
+        runDeviceTests(device, packageName, null, null, USER_SYSTEM);
     }
 
     public static void runDeviceTests(ITestDevice device, String packageName, int userId)
@@ -45,7 +43,7 @@
 
     public static void runDeviceTests(ITestDevice device, String packageName, String testClassName)
             throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, testClassName, null, USER_OWNER);
+        runDeviceTests(device, packageName, testClassName, null, USER_SYSTEM);
     }
 
     public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
@@ -55,7 +53,7 @@
 
     public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
             String testMethodName) throws DeviceNotAvailableException {
-        runDeviceTests(device, packageName, testClassName, testMethodName, USER_OWNER);
+        runDeviceTests(device, packageName, testClassName, testMethodName, USER_SYSTEM);
     }
 
     public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
@@ -72,13 +70,8 @@
             testRunner.setClassName(testClassName);
         }
 
-        if (userId != USER_OWNER) {
-            // TODO: move this to RemoteAndroidTestRunner once it supports users
-            testRunner.addInstrumentationArg("hack_key", "hack_value --user " + userId);
-        }
-
         final CollectingTestListener listener = new CollectingTestListener();
-        device.runInstrumentationTests(testRunner, listener);
+        device.runInstrumentationTestsAsUser(testRunner, userId, listener);
 
         final TestRunResult result = listener.getCurrentRunResults();
         if (result.isRunFailure()) {
@@ -103,65 +96,55 @@
         }
     }
 
-    private static boolean isMultiUserSupportedOnDevice(ITestDevice device)
+    /**
+     * Prepare and return a single user relevant for testing.
+     */
+    public static int[] prepareSingleUser(ITestDevice device)
             throws DeviceNotAvailableException {
-        // TODO: move this to ITestDevice once it supports users
-        final String output = device.executeShellCommand("pm get-max-users");
-        try {
-            return Integer.parseInt(output.substring(output.lastIndexOf(" ")).trim()) > 1;
-        } catch (NumberFormatException e) {
-            throw new AssertionError("Failed to parse result: " + output);
-        }
+        return prepareMultipleUsers(device, 1);
     }
 
     /**
-     * Return set of users that test should be run for, creating a secondary
-     * user if the device supports it. Always call
-     * {@link #removeUsersForTest(ITestDevice, int[])} when finished.
+     * Prepare and return two users relevant for testing.
      */
-    public static int[] createUsersForTest(ITestDevice device) throws DeviceNotAvailableException {
-        if (isMultiUserSupportedOnDevice(device)) {
-            return new int[] { USER_OWNER, createUserOnDevice(device) };
-        } else {
-            Log.d(TAG, "Single user device; skipping isolated storage tests");
-            return new int[] { USER_OWNER };
-        }
+    public static int[] prepareMultipleUsers(ITestDevice device)
+            throws DeviceNotAvailableException {
+        return prepareMultipleUsers(device, 2);
     }
 
-    public static void removeUsersForTest(ITestDevice device, int[] users)
+    /**
+     * Prepare and return multiple users relevant for testing.
+     */
+    public static int[] prepareMultipleUsers(ITestDevice device, int maxUsers)
             throws DeviceNotAvailableException {
-        for (int user : users) {
-            if (user != USER_OWNER) {
-                removeUserOnDevice(device, user);
+        final int[] userIds = getAllUsers(device);
+        for (int i = 1; i < userIds.length; i++) {
+            if (i < maxUsers) {
+                device.startUser(userIds[i]);
+            } else {
+                device.stopUser(userIds[i]);
             }
         }
-    }
-
-    private static int createUserOnDevice(ITestDevice device) throws DeviceNotAvailableException {
-        // TODO: move this to ITestDevice once it supports users
-        final String name = "CTS_" + System.currentTimeMillis();
-        final String output = device.executeShellCommand("pm create-user " + name);
-        if (output.startsWith("Success")) {
-            try {
-                final int userId = Integer.parseInt(
-                        output.substring(output.lastIndexOf(" ")).trim());
-                device.executeShellCommand("am start-user " + userId);
-                return userId;
-            } catch (NumberFormatException e) {
-                throw new AssertionError("Failed to parse result: " + output);
-            }
+        if (userIds.length > maxUsers) {
+            return Arrays.copyOf(userIds, maxUsers);
         } else {
-            throw new AssertionError("Failed to create user: " + output);
+            return userIds;
         }
     }
 
-    private static void removeUserOnDevice(ITestDevice device, int userId)
+    public static int[] getAllUsers(ITestDevice device)
             throws DeviceNotAvailableException {
-        // TODO: move this to ITestDevice once it supports users
-        final String output = device.executeShellCommand("pm remove-user " + userId);
-        if (output.startsWith("Error")) {
-            throw new AssertionError("Failed to remove user: " + output);
+        Integer primary = device.getPrimaryUserId();
+        if (primary == null) {
+            primary = USER_SYSTEM;
         }
+        int[] users = new int[] { primary };
+        for (Integer user : device.listUsers()) {
+            if ((user != USER_SYSTEM) && (user != primary)) {
+                users = Arrays.copyOf(users, users.length + 1);
+                users[users.length - 1] = user;
+            }
+        }
+        return users;
     }
-
 }
diff --git a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
index 4a4eef1..9d0dec6 100644
--- a/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/StorageApp/src/com/android/cts/storageapp/StorageTest.java
@@ -23,7 +23,6 @@
 import static com.android.cts.storageapp.Utils.DATA_INT;
 import static com.android.cts.storageapp.Utils.MB_IN_BYTES;
 import static com.android.cts.storageapp.Utils.PKG_B;
-import static com.android.cts.storageapp.Utils.TAG;
 import static com.android.cts.storageapp.Utils.assertMostlyEquals;
 import static com.android.cts.storageapp.Utils.getSizeManual;
 import static com.android.cts.storageapp.Utils.makeUniqueFile;
@@ -42,7 +41,6 @@
 import android.os.storage.StorageManager;
 import android.system.Os;
 import android.test.InstrumentationTestCase;
-import android.util.Log;
 
 import java.io.File;
 import java.io.IOException;
@@ -62,9 +60,19 @@
 
     public void testFullDisk() throws Exception {
         if (shouldHaveQuota(Os.uname())) {
-            Hoarder.doBlocks(getContext().getDataDir(), true);
+            final File dataDir = getContext().getDataDir();
+
+            // Pre-flight to see if we have enough disk space to test with
+            final long total = dataDir.getTotalSpace();
+            final long free = dataDir.getFreeSpace();
+            final long required = ((total * 9) / 10) + MB_IN_BYTES;
+            if (free < required) {
+                fail("Skipping full disk test; only found " + free + " free out of " + total);
+            }
+
+            Hoarder.doBlocks(dataDir, true);
         } else {
-            Log.d(TAG, "Skipping full disk test due to missing quota support");
+            fail("Skipping full disk test due to missing quota support");
         }
     }