| /* |
| * Copyright (C) 2015 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.deviceandprofileowner; |
| |
| import android.app.admin.DevicePolicyManager; |
| import android.content.BroadcastReceiver; |
| import android.content.ComponentName; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.content.IntentFilter; |
| import android.content.PermissionChecker; |
| import android.content.pm.PackageInfo; |
| import android.content.pm.PackageManager; |
| import android.support.test.uiautomator.By; |
| import android.support.test.uiautomator.BySelector; |
| import android.support.test.uiautomator.UiDevice; |
| import android.support.test.uiautomator.UiObject2; |
| import android.support.test.uiautomator.UiWatcher; |
| import android.support.test.uiautomator.Until; |
| import android.test.suitebuilder.annotation.Suppress; |
| import android.util.Log; |
| |
| import java.util.concurrent.ArrayBlockingQueue; |
| import java.util.concurrent.BlockingQueue; |
| import java.util.concurrent.TimeUnit; |
| |
| /** |
| * Test Runtime Permissions APIs in DevicePolicyManager. |
| */ |
| public class PermissionsTest extends BaseDeviceAdminTest { |
| private static final String TAG = "PermissionsTest"; |
| |
| private static final String PERMISSION_APP_PACKAGE_NAME |
| = "com.android.cts.permissionapp"; |
| private static final String SIMPLE_PRE_M_APP_PACKAGE_NAME = |
| "com.android.cts.launcherapps.simplepremapp"; |
| private static final String PERMISSION_NAME = "android.permission.READ_CONTACTS"; |
| private static final String CUSTOM_PERM_A_NAME = "com.android.cts.permissionapp.permA"; |
| private static final String CUSTOM_PERM_B_NAME = "com.android.cts.permissionapp.permB"; |
| private static final String DEVELOPMENT_PERMISSION = "android.permission.INTERACT_ACROSS_USERS"; |
| |
| private static final String PERMISSIONS_ACTIVITY_NAME |
| = PERMISSION_APP_PACKAGE_NAME + ".PermissionActivity"; |
| private static final String ACTION_CHECK_HAS_PERMISSION |
| = "com.android.cts.permission.action.CHECK_HAS_PERMISSION"; |
| private static final String ACTION_REQUEST_PERMISSION |
| = "com.android.cts.permission.action.REQUEST_PERMISSION"; |
| private static final String ACTION_PERMISSION_RESULT |
| = "com.android.cts.permission.action.PERMISSION_RESULT"; |
| private static final String EXTRA_PERMISSION |
| = "com.android.cts.permission.extra.PERMISSION"; |
| private static final String EXTRA_GRANT_STATE |
| = "com.android.cts.permission.extra.GRANT_STATE"; |
| private static final int PERMISSION_ERROR = -2; |
| private static final BySelector CRASH_POPUP_BUTTON_SELECTOR = By |
| .clazz(android.widget.Button.class.getName()) |
| .text("OK") |
| .pkg("android"); |
| private static final BySelector CRASH_POPUP_TEXT_SELECTOR = By |
| .clazz(android.widget.TextView.class.getName()) |
| .pkg("android"); |
| private static final String CRASH_WATCHER_ID = "CRASH"; |
| |
| private PermissionBroadcastReceiver mReceiver; |
| private PackageManager mPackageManager; |
| private UiDevice mDevice; |
| |
| @Override |
| protected void setUp() throws Exception { |
| super.setUp(); |
| mReceiver = new PermissionBroadcastReceiver(); |
| mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PERMISSION_RESULT)); |
| mPackageManager = mContext.getPackageManager(); |
| mDevice = UiDevice.getInstance(getInstrumentation()); |
| } |
| |
| @Override |
| protected void tearDown() throws Exception { |
| mContext.unregisterReceiver(mReceiver); |
| mDevice.removeWatcher(CRASH_WATCHER_ID); |
| super.tearDown(); |
| } |
| |
| public void testPermissionGrantState() throws Exception { |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| assertPermissionGrantState(PackageManager.PERMISSION_DENIED); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| // Should stay denied |
| assertPermissionGrantState(PackageManager.PERMISSION_DENIED); |
| |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); |
| assertPermissionGrantState(PackageManager.PERMISSION_GRANTED); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| // Should stay granted |
| assertPermissionGrantState(PackageManager.PERMISSION_GRANTED); |
| } |
| |
| public void testPermissionPolicy() throws Exception { |
| // reset permission to denied and unlocked |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| // permission should be locked, so changing the policy should not change the grant state |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_PROMPT); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| |
| // reset permission to denied and unlocked |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| // permission should be locked, so changing the policy should not change the grant state |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_PROMPT); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_PROMPT); |
| } |
| |
| public void testPermissionMixedPolicies() throws Exception { |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_PROMPT); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_PROMPT); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| } |
| |
| public void testPermissionGrantOfDisallowedPermissionWhileOtherPermIsGranted() throws Exception { |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED, |
| CUSTOM_PERM_A_NAME); |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED, |
| CUSTOM_PERM_B_NAME); |
| |
| /* |
| * CUSTOM_PERM_A_NAME and CUSTOM_PERM_B_NAME are in the same permission group and one is |
| * granted the other one is not. |
| * |
| * It should not be possible to get the permission that was denied via policy granted by |
| * requesting it. |
| */ |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED, null, CUSTOM_PERM_B_NAME); |
| } |
| |
| @Suppress // Flakey. |
| public void testPermissionPrompts() throws Exception { |
| // register a crash watcher |
| mDevice.registerWatcher(CRASH_WATCHER_ID, new UiWatcher() { |
| @Override |
| public boolean checkForCondition() { |
| UiObject2 button = mDevice.findObject(CRASH_POPUP_BUTTON_SELECTOR); |
| if (button != null) { |
| UiObject2 text = mDevice.findObject(CRASH_POPUP_TEXT_SELECTOR); |
| Log.d(TAG, "Removing an error dialog: " + text != null ? text.getText() : null); |
| button.click(); |
| return true; |
| } |
| return false; |
| } |
| }); |
| mDevice.runWatchers(); |
| |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_PROMPT); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED, "permission_deny_button"); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED, "permission_allow_button"); |
| } |
| |
| public void testPermissionUpdate_setDeniedState() throws Exception { |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, PERMISSION_NAME), |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| } |
| |
| public void testPermissionUpdate_setAutoDeniedPolicy() throws Exception { |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, PERMISSION_NAME), |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_DENY); |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| } |
| |
| public void testPermissionUpdate_checkDenied() throws Exception { |
| assertPermissionRequest(PackageManager.PERMISSION_DENIED); |
| assertPermissionGrantState(PackageManager.PERMISSION_DENIED); |
| } |
| |
| public void testPermissionUpdate_setGrantedState() throws Exception { |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, PERMISSION_NAME), |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| assertSetPermissionGrantState(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); |
| } |
| |
| public void testPermissionUpdate_setAutoGrantedPolicy() throws Exception { |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, PERMISSION_NAME), |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| assertSetPermissionPolicy(DevicePolicyManager.PERMISSION_POLICY_AUTO_GRANT); |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| } |
| |
| public void testPermissionUpdate_checkGranted() throws Exception { |
| assertPermissionRequest(PackageManager.PERMISSION_GRANTED); |
| assertPermissionGrantState(PackageManager.PERMISSION_GRANTED); |
| } |
| |
| public void testPermissionGrantStateAppPreMDeviceAdminPreQ() throws Exception { |
| // These tests are to make sure that pre-M apps are not granted/denied runtime permissions |
| // by a profile owner that targets pre-Q |
| assertCannotSetPermissionGrantStateAppPreM( |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| assertCannotSetPermissionGrantStateAppPreM( |
| DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); |
| } |
| |
| public void testPermissionGrantStatePreMApp() throws Exception { |
| // These tests are to make sure that pre-M apps can be granted/denied runtime permissions |
| // by a profile owner targets Q or later |
| assertCanSetPermissionGrantStateAppPreM(DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| assertCanSetPermissionGrantStateAppPreM(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); |
| } |
| |
| public void testPermissionGrantState_developmentPermission() throws Exception { |
| assertFailedToSetDevelopmentPermissionGrantState( |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED); |
| assertFailedToSetDevelopmentPermissionGrantState( |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| assertFailedToSetDevelopmentPermissionGrantState( |
| DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED); |
| } |
| |
| private void assertPermissionRequest(int expected) throws Exception { |
| assertPermissionRequest(expected, null); |
| } |
| |
| private void assertPermissionRequest(int expected, String buttonResource) throws Exception { |
| assertPermissionRequest(expected, buttonResource, PERMISSION_NAME); |
| } |
| |
| private void assertPermissionRequest(int expected, String buttonResource, String permission) |
| throws Exception { |
| Intent launchIntent = new Intent(); |
| launchIntent.setComponent(new ComponentName(PERMISSION_APP_PACKAGE_NAME, |
| PERMISSIONS_ACTIVITY_NAME)); |
| launchIntent.putExtra(EXTRA_PERMISSION, permission); |
| launchIntent.setAction(ACTION_REQUEST_PERMISSION); |
| launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); |
| mContext.startActivity(launchIntent); |
| pressPermissionPromptButton(buttonResource); |
| assertEquals(expected, mReceiver.waitForBroadcast()); |
| assertEquals(expected, mPackageManager.checkPermission(permission, |
| PERMISSION_APP_PACKAGE_NAME)); |
| } |
| |
| private void assertPermissionGrantState(int expected) throws Exception { |
| assertEquals(expected, mPackageManager.checkPermission(PERMISSION_NAME, |
| PERMISSION_APP_PACKAGE_NAME)); |
| Intent launchIntent = new Intent(); |
| launchIntent.setComponent(new ComponentName(PERMISSION_APP_PACKAGE_NAME, |
| PERMISSIONS_ACTIVITY_NAME)); |
| launchIntent.putExtra(EXTRA_PERMISSION, PERMISSION_NAME); |
| launchIntent.setAction(ACTION_CHECK_HAS_PERMISSION); |
| launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK); |
| mContext.startActivity(launchIntent); |
| assertEquals(expected, mReceiver.waitForBroadcast()); |
| } |
| |
| private void assertSetPermissionPolicy(int value) throws Exception { |
| mDevicePolicyManager.setPermissionPolicy(ADMIN_RECEIVER_COMPONENT, |
| value); |
| assertEquals(mDevicePolicyManager.getPermissionPolicy(ADMIN_RECEIVER_COMPONENT), |
| value); |
| } |
| |
| private void assertSetPermissionGrantState(int value) throws Exception { |
| assertSetPermissionGrantState(value, PERMISSION_NAME); |
| } |
| private void assertSetPermissionGrantState(int value, String permission) throws Exception { |
| mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, permission, |
| value); |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, permission), |
| value); |
| } |
| |
| private void assertFailedToSetDevelopmentPermissionGrantState(int value) throws Exception { |
| assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, DEVELOPMENT_PERMISSION, value)); |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| PERMISSION_APP_PACKAGE_NAME, DEVELOPMENT_PERMISSION), |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| assertEquals(mPackageManager.checkPermission(DEVELOPMENT_PERMISSION, |
| PERMISSION_APP_PACKAGE_NAME), |
| PackageManager.PERMISSION_DENIED); |
| } |
| |
| private void assertCannotSetPermissionGrantStateAppPreM(int value) throws Exception { |
| assertFalse(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME, |
| value)); |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME), |
| DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT); |
| |
| // Install time permissions should always be granted |
| PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo( |
| SIMPLE_PRE_M_APP_PACKAGE_NAME, 0); |
| assertEquals(PackageManager.PERMISSION_GRANTED, |
| PermissionChecker.checkPermissionForDataDelivery(mContext, PERMISSION_NAME, |
| PermissionChecker.PID_UNKNOWN, packageInfo.applicationInfo.uid, |
| SIMPLE_PRE_M_APP_PACKAGE_NAME)); |
| } |
| |
| private void assertCanSetPermissionGrantStateAppPreM(int value) throws Exception { |
| assertTrue(mDevicePolicyManager.setPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME, |
| value)); |
| assertEquals(mDevicePolicyManager.getPermissionGrantState(ADMIN_RECEIVER_COMPONENT, |
| SIMPLE_PRE_M_APP_PACKAGE_NAME, PERMISSION_NAME), |
| value); |
| |
| // Install time permissions should always be granted |
| assertEquals(mPackageManager.checkPermission(PERMISSION_NAME, |
| SIMPLE_PRE_M_APP_PACKAGE_NAME), |
| PackageManager.PERMISSION_GRANTED); |
| |
| PackageInfo packageInfo = mContext.getPackageManager().getPackageInfo( |
| SIMPLE_PRE_M_APP_PACKAGE_NAME, 0); |
| |
| // For pre-M apps the access to the data might be prevented via app-ops. Hence check that |
| // they are correctly set |
| boolean isGranted = (PermissionChecker.checkPermissionForDataDelivery(mContext, |
| PERMISSION_NAME, PermissionChecker.PID_UNKNOWN, |
| packageInfo.applicationInfo.uid, SIMPLE_PRE_M_APP_PACKAGE_NAME) |
| == PackageManager.PERMISSION_GRANTED); |
| switch (value) { |
| case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: |
| assertTrue(isGranted); |
| break; |
| case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: |
| assertFalse(isGranted); |
| break; |
| default: |
| fail("unsupported policy value"); |
| } |
| } |
| |
| private void pressPermissionPromptButton(String resName) throws Exception { |
| if (resName == null) { |
| return; |
| } |
| |
| BySelector selector = By |
| .clazz(android.widget.Button.class.getName()) |
| .res("com.android.packageinstaller", resName); |
| mDevice.wait(Until.hasObject(selector), 5000); |
| UiObject2 button = mDevice.findObject(selector); |
| assertNotNull("Couldn't find button with resource id: " + resName, button); |
| button.click(); |
| } |
| |
| private class PermissionBroadcastReceiver extends BroadcastReceiver { |
| private BlockingQueue<Integer> mQueue = new ArrayBlockingQueue<Integer> (1); |
| |
| @Override |
| public void onReceive(Context context, Intent intent) { |
| Integer result = new Integer(intent.getIntExtra(EXTRA_GRANT_STATE, PERMISSION_ERROR)); |
| Log.d(TAG, "Grant state received " + result); |
| assertTrue(mQueue.add(result)); |
| } |
| |
| public int waitForBroadcast() throws Exception { |
| Integer result = mQueue.poll(30, TimeUnit.SECONDS); |
| mQueue.clear(); |
| assertNotNull(result); |
| Log.d(TAG, "Grant state retrieved " + result.intValue()); |
| return result.intValue(); |
| } |
| } |
| } |