Verify storage behavior for secondary users.
If the device claims to support multiple users, run storage tests
both under owner and secondary users.
Bug: 19905213
Change-Id: Id4c5dcaaf6b26dbec0e77827976d0df3b1984c20
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
index 4d9ef00..81a9608 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
@@ -20,7 +20,6 @@
import com.android.cts.util.AbiUtils;
import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.InstrumentationResultParser;
-import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult;
import com.android.ddmlib.testrunner.TestResult.TestStatus;
@@ -107,6 +106,8 @@
private static final String LOG_TAG = "AppSecurityTests";
+ private static final int USER_OWNER = 0;
+
private IAbi mAbi;
private CtsBuildHelper mCtsBuild;
@@ -224,6 +225,7 @@
* Verify that app with no external storage permissions works correctly.
*/
public void testExternalStorageNone() throws Exception {
+ final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage(getDevice());
@@ -231,10 +233,14 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice()
.installPackage(getTestAppFile(EXTERNAL_STORAGE_APP_APK), false, options));
- assertTrue("Failed external storage with no permissions",
- runDeviceTests(EXTERNAL_STORAGE_APP_PKG));
+
+ for (int user : users) {
+ assertTrue("Failed external storage with no permissions",
+ runDeviceTests(EXTERNAL_STORAGE_APP_PKG, user));
+ }
} finally {
getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ removeUsersForTest(users);
}
}
@@ -244,6 +250,7 @@
* correctly.
*/
public void testExternalStorageRead() throws Exception {
+ final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage(getDevice());
@@ -251,10 +258,14 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice()
.installPackage(getTestAppFile(READ_EXTERNAL_STORAGE_APP_APK), false, options));
- assertTrue("Failed external storage with read permissions",
- runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG));
+
+ for (int user : users) {
+ assertTrue("Failed external storage with read permissions",
+ runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG, user));
+ }
} finally {
getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
+ removeUsersForTest(users);
}
}
@@ -264,6 +275,7 @@
* correctly.
*/
public void testExternalStorageWrite() throws Exception {
+ final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage(getDevice());
@@ -271,10 +283,14 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
assertNull(getDevice()
.installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false, options));
- assertTrue("Failed external storage with write permissions",
- runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG));
+
+ for (int user : users) {
+ assertTrue("Failed external storage with write permissions",
+ runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG, user));
+ }
} finally {
getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+ removeUsersForTest(users);
}
}
@@ -283,6 +299,7 @@
* directories belonging to other apps, and those apps can read.
*/
public void testExternalStorageGifts() throws Exception {
+ final int[] users = createUsersForTest();
try {
wipePrimaryExternalStorage(getDevice());
@@ -297,18 +314,19 @@
assertNull(getDevice()
.installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false, options));
- assertTrue("Failed to write gifts", runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG,
- WRITE_EXTERNAL_STORAGE_APP_CLASS, "doWriteGifts"));
-
- assertTrue("Read failed to verify gifts", runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG,
- READ_EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts"));
- assertTrue("None failed to verify gifts", runDeviceTests(EXTERNAL_STORAGE_APP_PKG,
- EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts"));
-
+ for (int user : users) {
+ assertTrue("Failed to write gifts", runDeviceTests(WRITE_EXTERNAL_STORAGE_APP_PKG,
+ WRITE_EXTERNAL_STORAGE_APP_CLASS, "doWriteGifts", user));
+ assertTrue("Read failed to verify gifts", runDeviceTests(READ_EXTERNAL_STORAGE_APP_PKG,
+ READ_EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts", user));
+ assertTrue("None failed to verify gifts", runDeviceTests(EXTERNAL_STORAGE_APP_PKG,
+ EXTERNAL_STORAGE_APP_CLASS, "doVerifyGifts", user));
+ }
} finally {
getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
getDevice().uninstallPackage(READ_EXTERNAL_STORAGE_APP_PKG);
getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+ removeUsersForTest(users);
}
}
@@ -409,7 +427,7 @@
assertNull(String.format("failed to install permission app with diff cert. Reason: %s",
installResult), installResult);
// run PERMISSION_DIFF_CERT_PKG tests which try to access the permission
- TestRunResult result = doRunTests(PERMISSION_DIFF_CERT_PKG, null, null);
+ TestRunResult result = doRunTests(PERMISSION_DIFF_CERT_PKG, null, null, USER_OWNER);
assertDeviceTestsPass(result);
}
finally {
@@ -423,20 +441,19 @@
* Test multi-user emulated storage environment, ensuring that each user has
* isolated storage.
*/
- public void testMultiUserStorage() throws Exception {
+ public void testMultiUserStorageIsolated() throws Exception {
final String PACKAGE = MULTIUSER_STORAGE_PKG;
final String CLAZZ = MULTIUSER_STORAGE_CLASS;
- if (!isMultiUserSupportedOnDevice(getDevice())) {
- Log.d(LOG_TAG, "Single user device; skipping isolated storage tests");
- return;
- }
-
- int owner = 0;
- int secondary = -1;
+ final int[] users = createUsersForTest();
try {
- // Create secondary user
- secondary = createUserOnDevice(getDevice());
+ if (users.length == 1) {
+ Log.d(LOG_TAG, "Single user device; skipping isolated storage tests");
+ return;
+ }
+
+ final int owner = users[0];
+ final int secondary = users[1];
// Install our test app
getDevice().uninstallPackage(MULTIUSER_STORAGE_PKG);
@@ -447,26 +464,24 @@
// Clear data from previous tests
assertDeviceTestsPass(
- doRunTestsAsUser(PACKAGE, CLAZZ, "cleanIsolatedStorage", owner));
+ doRunTests(PACKAGE, CLAZZ, "cleanIsolatedStorage", owner));
assertDeviceTestsPass(
- doRunTestsAsUser(PACKAGE, CLAZZ, "cleanIsolatedStorage", secondary));
+ doRunTests(PACKAGE, CLAZZ, "cleanIsolatedStorage", secondary));
// Have both users try writing into isolated storage
assertDeviceTestsPass(
- doRunTestsAsUser(PACKAGE, CLAZZ, "writeIsolatedStorage", owner));
+ doRunTests(PACKAGE, CLAZZ, "writeIsolatedStorage", owner));
assertDeviceTestsPass(
- doRunTestsAsUser(PACKAGE, CLAZZ, "writeIsolatedStorage", secondary));
+ doRunTests(PACKAGE, CLAZZ, "writeIsolatedStorage", secondary));
// Verify they both have isolated view of storage
assertDeviceTestsPass(
- doRunTestsAsUser(PACKAGE, CLAZZ, "readIsolatedStorage", owner));
+ doRunTests(PACKAGE, CLAZZ, "readIsolatedStorage", owner));
assertDeviceTestsPass(
- doRunTestsAsUser(PACKAGE, CLAZZ, "readIsolatedStorage", secondary));
+ doRunTests(PACKAGE, CLAZZ, "readIsolatedStorage", secondary));
} finally {
getDevice().uninstallPackage(MULTIUSER_STORAGE_PKG);
- if (secondary != -1) {
- removeUserOnDevice(getDevice(), secondary);
- }
+ removeUsersForTest(users);
}
}
@@ -504,7 +519,11 @@
* @throws DeviceNotAvailableException if connection to device was lost.
*/
private boolean runDeviceTests(String pkgName) throws DeviceNotAvailableException {
- return runDeviceTests(pkgName, null, null);
+ return runDeviceTests(pkgName, null, null, USER_OWNER);
+ }
+
+ private boolean runDeviceTests(String pkgName, int userId) throws DeviceNotAvailableException {
+ return runDeviceTests(pkgName, null, null, userId);
}
/**
@@ -516,28 +535,14 @@
*/
private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName)
throws DeviceNotAvailableException {
- TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName);
- return !runResult.hasFailedTests();
+ return runDeviceTests(pkgName, testClassName, testMethodName, USER_OWNER);
}
- /**
- * Helper method to run tests and return the listener that collected the results.
- *
- * @param pkgName Android application package for tests
- * @return the {@link TestRunResult}
- * @throws DeviceNotAvailableException if connection to device was lost.
- */
- private TestRunResult doRunTests(String pkgName, String testClassName,
- String testMethodName) throws DeviceNotAvailableException {
-
- RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(pkgName,
- RUNNER, getDevice().getIDevice());
- if (testClassName != null && testMethodName != null) {
- testRunner.setMethodName(testClassName, testMethodName);
- }
- CollectingTestListener listener = new CollectingTestListener();
- getDevice().runInstrumentationTests(testRunner, listener);
- return listener.getCurrentRunResults();
+ private boolean runDeviceTests(String pkgName, String testClassName, String testMethodName,
+ int userId) throws DeviceNotAvailableException {
+ TestRunResult runResult = doRunTests(pkgName, testClassName, testMethodName,
+ userId);
+ return !runResult.hasFailedTests();
}
private static boolean isMultiUserSupportedOnDevice(ITestDevice device)
@@ -552,6 +557,28 @@
return false;
}
+ /**
+ * Return set of users that test should be run for, creating a secondary
+ * user if the device supports it. Always call
+ * {@link #removeUsersForTest(int[])} when finished.
+ */
+ private int[] createUsersForTest() throws DeviceNotAvailableException {
+ if (isMultiUserSupportedOnDevice(getDevice())) {
+ return new int[] { USER_OWNER, createUserOnDevice(getDevice()) };
+ } else {
+ Log.d(LOG_TAG, "Single user device; skipping isolated storage tests");
+ return new int[] { USER_OWNER };
+ }
+ }
+
+ private void removeUsersForTest(int[] users) throws DeviceNotAvailableException {
+ for (int user : users) {
+ if (user != USER_OWNER) {
+ removeUserOnDevice(getDevice(), user);
+ }
+ }
+ }
+
private static int createUserOnDevice(ITestDevice device) throws DeviceNotAvailableException {
// TODO: move this to ITestDevice once it supports users
final String name = "CTS_" + System.currentTimeMillis();
@@ -577,18 +604,24 @@
}
}
- private TestRunResult doRunTestsAsUser(
- String pkgName, String testClassName, String testMethodName, int userId)
- throws DeviceNotAvailableException {
+ private TestRunResult doRunTests(String pkgName, String testClassName, String testMethodName,
+ int userId) throws DeviceNotAvailableException {
// TODO: move this to RemoteAndroidTestRunner once it supports users
- final String cmd = "am instrument --user " + userId + " -w -r -e class " + testClassName
- + "#" + testMethodName + " " + pkgName + "/" + RUNNER;
+ final StringBuilder cmd = new StringBuilder("am instrument --user " + userId + " -w -r");
+ if (testClassName != null) {
+ cmd.append(" -e class " + testClassName);
+ if (testMethodName != null) {
+ cmd.append("#" + testMethodName);
+ }
+ }
+ cmd.append(" " + pkgName + "/" + RUNNER);
+
Log.i(LOG_TAG, "Running " + cmd + " on " + getDevice().getSerialNumber());
CollectingTestListener listener = new CollectingTestListener();
InstrumentationResultParser parser = new InstrumentationResultParser(pkgName, listener);
- getDevice().executeShellCommand(cmd, parser);
+ getDevice().executeShellCommand(cmd.toString(), parser);
return listener.getCurrentRunResults();
}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index 5b4d9f7..eac4405 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -21,13 +21,17 @@
import android.test.AndroidTestCase;
import android.util.Log;
+import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -43,6 +47,14 @@
public static final String PACKAGE_WRITE = "com.android.cts.writeexternalstorageapp";
/**
+ * Dump helpful debugging details.
+ */
+ public void testDumpDebug() throws Exception {
+ logCommand("/system/bin/id");
+ logCommand("/system/bin/cat", "/proc/self/mountinfo");
+ }
+
+ /**
* Primary storage must always be mounted.
*/
public void testExternalStorageMounted() {
@@ -336,4 +348,27 @@
is.close();
}
}
+
+ private static void logCommand(String... cmd) throws Exception {
+ final Process proc = new ProcessBuilder(cmd).redirectErrorStream(true).start();
+
+ final ByteArrayOutputStream buf = new ByteArrayOutputStream();
+ copy(proc.getInputStream(), buf);
+ final int res = proc.waitFor();
+
+ Log.d(TAG, Arrays.toString(cmd) + " result " + res + ":");
+ Log.d(TAG, buf.toString());
+ }
+
+ /** Shamelessly lifted from libcore.io.Streams */
+ public static int copy(InputStream in, OutputStream out) throws IOException {
+ int total = 0;
+ byte[] buffer = new byte[8192];
+ int c;
+ while ((c = in.read(buffer)) != -1) {
+ total += c;
+ out.write(buffer, 0, c);
+ }
+ return total;
+ }
}