Tests for READ_EXTERNAL permission.
Verify that app with no permissions is allowed (and blocked) from
reading external storage. Verify that app with only WRITE_EXTERNAL
is always able to read/write.
Bug: 6315473
Change-Id: I53483110c2d296c53350b48d38967b0bf3f38148
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index 2feb76b..e525c7c 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -15,6 +15,7 @@
cts_security_apps_list := \
CtsAppAccessData \
CtsAppWithData \
+ CtsExternalStorageApp \
CtsInstrumentationAppDiffCert \
CtsPermissionDeclareApp \
CtsSharedUidInstall \
@@ -22,7 +23,8 @@
CtsSimpleAppInstall \
CtsSimpleAppInstallDiffCert \
CtsTargetInstrumentationApp \
- CtsUsePermissionDiffCert
+ CtsUsePermissionDiffCert \
+ CtsWriteExternalStorageApp
cts_support_packages := \
CtsAccelerationTestStubs \
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
index 7eb3a33..dc75e7d 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
@@ -21,6 +21,7 @@
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.result.TestRunResult;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -58,6 +59,17 @@
private static final String APP_ACCESS_DATA_APK = "CtsAppAccessData.apk";
private static final String APP_ACCESS_DATA_PKG = "com.android.cts.appaccessdata";
+ // External storage constants
+ private static final String EXTERNAL_STORAGE_APP_APK = "CtsExternalStorageApp.apk";
+ private static final String EXTERNAL_STORAGE_APP_PKG = "com.android.cts.externalstorageapp";
+ private static final String EXTERNAL_STORAGE_APP_CLASS = EXTERNAL_STORAGE_APP_PKG
+ + ".ExternalStorageTest";
+ private static final String WRITE_EXTERNAL_STORAGE_APP_APK = "CtsWriteExternalStorageApp.apk";
+ private static final String
+ WRITE_EXTERNAL_STORAGE_APP_PKG = "com.android.cts.writeexternalstorageapp";
+ private static final String WRITE_EXTERNAL_STORAGE_APP_CLASS = WRITE_EXTERNAL_STORAGE_APP_PKG
+ + ".WriteExternalStorageTest";
+
// testInstrumentationDiffCert constants
private static final String TARGET_INSTRUMENT_APK = "CtsTargetInstrumentationApp.apk";
private static final String TARGET_INSTRUMENT_PKG = "com.android.cts.targetinstrumentationapp";
@@ -72,6 +84,8 @@
private static final String PERMISSION_DIFF_CERT_PKG =
"com.android.cts.usespermissiondiffcertapp";
+ private static final String READ_EXTERNAL_STORAGE = "android.permission.READ_EXTERNAL_STORAGE";
+
private static final String LOG_TAG = "AppSecurityTests";
private CtsBuildHelper mCtsBuild;
@@ -179,6 +193,86 @@
}
/**
+ * Test behavior when
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} is unenforced.
+ */
+ public void testReadExternalStorageUnenforced() throws Exception {
+ try {
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+
+ // stage test file on external storage
+ getDevice().pushString("CAEK", "/sdcard/meow");
+
+ // mark permission as not enforced
+ setPermissionEnforced(getDevice(), READ_EXTERNAL_STORAGE, false);
+
+ // install apps and run test
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(EXTERNAL_STORAGE_APP_APK), false));
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false));
+
+ // normal app should be able to read
+ assertTrue("Normal app unable to read external storage", runDeviceTests(
+ EXTERNAL_STORAGE_APP_PKG, EXTERNAL_STORAGE_APP_CLASS,
+ "testReadExternalStorage"));
+
+ // WRITE_EXTERNAL app should be able to read and write
+ assertTrue("WRITE_EXTERNAL app unable to read external storage", runDeviceTests(
+ WRITE_EXTERNAL_STORAGE_APP_PKG, WRITE_EXTERNAL_STORAGE_APP_CLASS,
+ "testReadExternalStorage"));
+ assertTrue("WRITE_EXTERNAL app unable to write external storage", runDeviceTests(
+ WRITE_EXTERNAL_STORAGE_APP_PKG, WRITE_EXTERNAL_STORAGE_APP_CLASS,
+ "testWriteExternalStorage"));
+
+ } finally {
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+ }
+ }
+
+ /**
+ * Test behavior when
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} is enforced.
+ */
+ public void testReadExternalStorageEnforced() throws Exception {
+ try {
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+
+ // stage test file on external storage
+ getDevice().pushString("CAEK", "/sdcard/meow");
+
+ // mark permission as enforced
+ setPermissionEnforced(getDevice(), READ_EXTERNAL_STORAGE, true);
+
+ // install apps and run test
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(EXTERNAL_STORAGE_APP_APK), false));
+ assertNull(getDevice()
+ .installPackage(getTestAppFile(WRITE_EXTERNAL_STORAGE_APP_APK), false));
+
+ // normal app should not be able to read
+ assertTrue("Normal app able to read external storage", runDeviceTests(
+ EXTERNAL_STORAGE_APP_PKG, EXTERNAL_STORAGE_APP_CLASS,
+ "testFailReadExternalStorage"));
+
+ // WRITE_EXTERNAL app should be able to read and write
+ assertTrue("WRITE_EXTERNAL app unable to read external storage", runDeviceTests(
+ WRITE_EXTERNAL_STORAGE_APP_PKG, WRITE_EXTERNAL_STORAGE_APP_CLASS,
+ "testReadExternalStorage"));
+ assertTrue("WRITE_EXTERNAL app unable to write external storage", runDeviceTests(
+ WRITE_EXTERNAL_STORAGE_APP_PKG, WRITE_EXTERNAL_STORAGE_APP_CLASS,
+ "testWriteExternalStorage"));
+
+ } finally {
+ getDevice().uninstallPackage(EXTERNAL_STORAGE_APP_PKG);
+ getDevice().uninstallPackage(WRITE_EXTERNAL_STORAGE_APP_PKG);
+ }
+ }
+
+ /**
* Test that uninstall of an app removes its private data.
*/
public void testUninstallRemovesData() throws Exception {
@@ -319,4 +413,10 @@
return listener.getCurrentRunResults();
}
+ private static void setPermissionEnforced(
+ ITestDevice device, String permission, boolean enforced)
+ throws DeviceNotAvailableException {
+ device.executeShellCommand("pm set-permission-enforced " + permission + " "
+ + Boolean.toString(enforced));
+ }
}
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
new file mode 100644
index 0000000..3c687f1
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := 10
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := CtsExternalStorageApp
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/AndroidManifest.xml
new file mode 100644
index 0000000..0ba6684
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.externalstorageapp">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.cts.externalstorageapp" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
new file mode 100644
index 0000000..d42353d
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/ExternalStorageTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2012 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.cts.externalstorageapp;
+
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Test if {@link Environment#getExternalStorageDirectory()} is readable.
+ */
+public class ExternalStorageTest extends AndroidTestCase {
+
+ private static final String TEST_FILE = "meow";
+
+ private void assertExternalStorageMounted() {
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ }
+
+ private void readExternalStorage() throws IOException {
+ final File file = new File(Environment.getExternalStorageDirectory(), TEST_FILE);
+ final InputStream is = new FileInputStream(file);
+ try {
+ is.read();
+ } finally {
+ is.close();
+ }
+ }
+
+ public void testReadExternalStorage() throws Exception {
+ assertExternalStorageMounted();
+ try {
+ readExternalStorage();
+ } catch (IOException e) {
+ fail("unable to read external file");
+ }
+ }
+
+ public void testFailReadExternalStorage() throws Exception {
+ assertExternalStorageMounted();
+ try {
+ readExternalStorage();
+ fail("able read external file");
+ } catch (IOException e) {
+ // expected
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
new file mode 100644
index 0000000..bdb2887
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -0,0 +1,25 @@
+# Copyright (C) 2012 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := 10
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+LOCAL_PACKAGE_NAME := CtsWriteExternalStorageApp
+
+include $(BUILD_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/AndroidManifest.xml
new file mode 100644
index 0000000..82910aa
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2012 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.writeexternalstorageapp">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.cts.writeexternalstorageapp" />
+
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
new file mode 100644
index 0000000..b899bb0
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 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.cts.writeexternalstorageapp;
+
+import android.os.Environment;
+import android.test.AndroidTestCase;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Test if {@link Environment#getExternalStorageDirectory()} is writable.
+ */
+public class WriteExternalStorageTest extends AndroidTestCase {
+
+ private static final String TEST_FILE = "meow";
+
+ private void assertExternalStorageMounted() {
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+ }
+
+ private void readExternalStorage() throws IOException {
+ final File file = new File(Environment.getExternalStorageDirectory(), TEST_FILE);
+ final InputStream is = new FileInputStream(file);
+ try {
+ is.read();
+ } finally {
+ is.close();
+ }
+ }
+
+ private void writeExternalStorage() throws IOException {
+ final File file = new File(Environment.getExternalStorageDirectory(), TEST_FILE);
+ final OutputStream os = new FileOutputStream(file);
+ try {
+ os.write(32);
+ } finally {
+ os.close();
+ }
+ }
+
+ public void testReadExternalStorage() throws Exception {
+ assertExternalStorageMounted();
+ try {
+ readExternalStorage();
+ } catch (IOException e) {
+ fail("unable to read external file");
+ }
+ }
+
+ public void testWriteExternalStorage() throws Exception {
+ assertExternalStorageMounted();
+ try {
+ writeExternalStorage();
+ } catch (IOException e) {
+ fail("unable to read external file");
+ }
+ }
+
+}