Merge "Test behavior when declaring duplicate permissions"
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index 1754dcd..490bb18 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -16,11 +16,14 @@
package android.appsecurity.cts;
+import static android.appsecurity.cts.Utils.waitForBootCompleted;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.AppModeInstant;
+
import com.android.ddmlib.Log;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -78,6 +81,11 @@
private static final String PERMISSION_DIFF_CERT_PKG =
"com.android.cts.usespermissiondiffcertapp";
+ private static final String DUPLICATE_DECLARE_PERMISSION_APK =
+ "CtsDuplicatePermissionDeclareApp.apk";
+ private static final String DUPLICATE_DECLARE_PERMISSION_PKG =
+ "com.android.cts.duplicatepermissiondeclareapp";
+
private static final String LOG_TAG = "AppSecurityTests";
@Before
@@ -265,6 +273,27 @@
}
/**
+ * Test what happens if an app tried to take a permission away from another
+ */
+ @Test
+ public void rebootWithDuplicatePermission() throws Exception {
+ try {
+ new InstallMultiple(false).addApk(DECLARE_PERMISSION_APK).run();
+ new InstallMultiple(false).addApk(DUPLICATE_DECLARE_PERMISSION_APK).run();
+
+ runDeviceTests(DUPLICATE_DECLARE_PERMISSION_PKG, null);
+
+ // make sure behavior is preserved after reboot
+ getDevice().reboot();
+ waitForBootCompleted(getDevice());
+ runDeviceTests(DUPLICATE_DECLARE_PERMISSION_PKG, null);
+ } finally {
+ getDevice().uninstallPackage(DECLARE_PERMISSION_PKG);
+ getDevice().uninstallPackage(DUPLICATE_DECLARE_PERMISSION_PKG);
+ }
+ }
+
+ /**
* Tests that an arbitrary file cannot be installed using the 'cmd' command.
*/
@Test
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
index 6c598ec..6cdc9fd 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DirectBootHostTest.java
@@ -16,13 +16,13 @@
package android.appsecurity.cts;
+import static android.appsecurity.cts.Utils.waitForBootCompleted;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.platform.test.annotations.RequiresDevice;
-import com.android.ddmlib.AdbCommandRejectedException;
-import com.android.ddmlib.CollectingOutputReceiver;
import com.android.ddmlib.Log;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
@@ -173,7 +173,7 @@
} else {
getDevice().rebootUntilOnline();
}
- waitForBootCompleted();
+ waitForBootCompleted(getDevice());
if (doTest) {
if (MODE_NONE.equals(mode)) {
@@ -215,21 +215,6 @@
return getDevice().executeShellCommand("sm get-fbe-mode").trim();
}
- private boolean isBootCompleted() throws Exception {
- CollectingOutputReceiver receiver = new CollectingOutputReceiver();
- try {
- getDevice().getIDevice().executeShellCommand("getprop sys.boot_completed", receiver);
- } catch (AdbCommandRejectedException e) {
- // do nothing: device might be temporarily disconnected
- Log.d(TAG, "Ignored AdbCommandRejectedException while `getprop sys.boot_completed`");
- }
- String output = receiver.getOutput();
- if (output != null) {
- output = output.trim();
- }
- return "1".equals(output);
- }
-
private boolean isSupportedDevice() throws Exception {
return getDevice().hasFeature(FEATURE_DEVICE_ADMIN);
}
@@ -238,21 +223,6 @@
return getDevice().hasFeature(FEATURE_AUTOMOTIVE);
}
- private void waitForBootCompleted() throws Exception {
- for (int i = 0; i < 45; i++) {
- if (isBootCompleted()) {
- Log.d(TAG, "Yay, system is ready!");
- // or is it really ready?
- // guard against potential USB mode switch weirdness at boot
- Thread.sleep(10 * 1000);
- return;
- }
- Log.d(TAG, "Waiting for system ready...");
- Thread.sleep(1000);
- }
- throw new AssertionError("System failed to become ready!");
- }
-
private class InstallMultiple extends BaseInstallMultiple<InstallMultiple> {
public InstallMultiple() {
super(getDevice(), getBuild(), getAbi());
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
index d5aa6e1..0b5594b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -16,6 +16,9 @@
package android.appsecurity.cts;
+import com.android.ddmlib.AdbCommandRejectedException;
+import com.android.ddmlib.CollectingOutputReceiver;
+import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestResult.TestStatus;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -31,6 +34,8 @@
import java.util.concurrent.TimeUnit;
public class Utils {
+ private static final String LOG_TAG = Utils.class.getSimpleName();
+
public static final int USER_SYSTEM = 0;
public static void runDeviceTests(ITestDevice device, String packageName, String testClassName,
@@ -157,4 +162,35 @@
}
return users;
}
+
+ public static void waitForBootCompleted(ITestDevice device) throws Exception {
+ for (int i = 0; i < 45; i++) {
+ if (isBootCompleted(device)) {
+ Log.d(LOG_TAG, "Yay, system is ready!");
+ // or is it really ready?
+ // guard against potential USB mode switch weirdness at boot
+ Thread.sleep(10 * 1000);
+ return;
+ }
+ Log.d(LOG_TAG, "Waiting for system ready...");
+ Thread.sleep(1000);
+ }
+ throw new AssertionError("System failed to become ready!");
+ }
+
+ private static boolean isBootCompleted(ITestDevice device) throws Exception {
+ CollectingOutputReceiver receiver = new CollectingOutputReceiver();
+ try {
+ device.getIDevice().executeShellCommand("getprop sys.boot_completed", receiver);
+ } catch (AdbCommandRejectedException e) {
+ // do nothing: device might be temporarily disconnected
+ Log.d(LOG_TAG, "Ignored AdbCommandRejectedException while `getprop sys.boot_completed`");
+ }
+ String output = receiver.getOutput();
+ if (output != null) {
+ output = output.trim();
+ }
+ return "1".equals(output);
+ }
+
}
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.mk b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.mk
new file mode 100644
index 0000000..ce49914
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2018 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_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+
+LOCAL_PACKAGE_NAME := CtsDuplicatePermissionDeclareApp
+
+# Use the same cert as the app that also defined the permission
+LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/AndroidManifest.xml b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/AndroidManifest.xml
new file mode 100644
index 0000000..0c8b2d6
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2018 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.duplicatepermissiondeclareapp">
+
+ <permission android:name="com.android.cts.permissionNormal"/>
+ <uses-permission android:name="com.android.cts.permissionNormal" />
+
+ <permission-tree android:name="com.android.cts" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.duplicatepermissiondeclareapp" />
+
+</manifest>
diff --git a/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/src/com/android/cts/duplicatepermissiondeclareapp/VerifyDuplicatePermissionTest.java b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/src/com/android/cts/duplicatepermissiondeclareapp/VerifyDuplicatePermissionTest.java
new file mode 100644
index 0000000..3584876
--- /dev/null
+++ b/hostsidetests/appsecurity/test-apps/DuplicatePermissionDeclareApp/src/com/android/cts/duplicatepermissiondeclareapp/VerifyDuplicatePermissionTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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.duplicatepermissiondeclareapp;
+
+import static android.content.pm.PackageManager.GET_PERMISSIONS;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class VerifyDuplicatePermissionTest {
+ private final static String APP_THAT_WAS_INSTALLED_FIRST =
+ "com.android.cts.permissiondeclareapp";
+ private final static String APP_THAT_WAS_INSTALLED_AFTER =
+ "com.android.cts.duplicatepermissiondeclareapp";
+ private final static String PERM = "com.android.cts.permissionNormal";
+
+ private final static PackageManager sPm =
+ InstrumentationRegistry.getTargetContext().getPackageManager();
+
+ private PermissionInfo getDeclaredPermission(String pkg, String permission) throws Exception {
+ for (PermissionInfo permInfo : sPm.getPackageInfo(pkg, GET_PERMISSIONS).permissions) {
+ if (permInfo.name.equals(permission)) {
+ return permInfo;
+ }
+ }
+
+ return null;
+ }
+
+ @Test
+ public void verifyDuplicatePermission() throws Exception {
+ // The other app was first. The second app could not steal the permission. Hence the
+ // permission belongs to the first app.
+ assertEquals(APP_THAT_WAS_INSTALLED_FIRST, sPm.getPermissionInfo(PERM, 0).packageName);
+
+ // The first app declared the permission
+ assertEquals(APP_THAT_WAS_INSTALLED_FIRST,
+ getDeclaredPermission(APP_THAT_WAS_INSTALLED_FIRST, PERM).packageName);
+
+ // The second app declared the permission too, but the permission is owned by first app.
+ // Hence we end up with a permission info that is different from the one read from the
+ // system.
+ assertEquals(APP_THAT_WAS_INSTALLED_AFTER,
+ getDeclaredPermission(APP_THAT_WAS_INSTALLED_AFTER, PERM).packageName);
+ }
+}