1 /* 2 * Copyright (C) 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.permission.cts; 18 19 import static android.Manifest.permission.ACCESS_BACKGROUND_LOCATION; 20 import static android.Manifest.permission.ACCESS_COARSE_LOCATION; 21 import static android.Manifest.permission.ACCESS_FINE_LOCATION; 22 import static android.app.AppOpsManager.MODE_ALLOWED; 23 import static android.app.AppOpsManager.MODE_FOREGROUND; 24 import static android.app.AppOpsManager.MODE_IGNORED; 25 import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; 26 import static android.content.pm.PermissionInfo.PROTECTION_INTERNAL; 27 import static android.permission.cts.PermissionUtils.getAppOp; 28 import static android.permission.cts.PermissionUtils.grantPermission; 29 import static android.permission.cts.PermissionUtils.install; 30 import static android.permission.cts.PermissionUtils.uninstallApp; 31 32 import static com.android.compatibility.common.util.SystemUtil.eventually; 33 34 import static com.google.common.truth.Truth.assertWithMessage; 35 36 import static org.junit.Assert.assertNotEquals; 37 import static org.junit.Assert.assertNotNull; 38 import static org.junit.Assert.assertTrue; 39 40 import android.app.AppOpsManager; 41 import android.app.UiAutomation; 42 import android.content.Context; 43 import android.content.pm.PackageInfo; 44 import android.content.pm.PackageManager; 45 import android.content.pm.PermissionInfo; 46 import android.platform.test.annotations.AppModeFull; 47 import android.util.ArrayMap; 48 import android.util.Log; 49 50 import androidx.test.platform.app.InstrumentationRegistry; 51 import androidx.test.runner.AndroidJUnit4; 52 53 import org.junit.After; 54 import org.junit.Test; 55 import org.junit.runner.RunWith; 56 57 @RunWith(AndroidJUnit4.class) 58 public class BackgroundPermissionsTest { 59 private static final String LOG_TAG = BackgroundPermissionsTest.class.getSimpleName(); 60 61 /** The package name of all apps used in the test */ 62 private static final String APP_PKG = "android.permission.cts.appthatrequestpermission"; 63 64 private static final String TMP_DIR = "/data/local/tmp/cts-permission/"; 65 private static final String APK_LOCATION_BACKGROUND_29 = 66 TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission29.apk"; 67 private static final String APK_LOCATION_29v4 = 68 TMP_DIR + "CtsAppThatRequestsLocationPermission29v4.apk"; 69 70 private static final Context sContext = 71 InstrumentationRegistry.getInstrumentation().getTargetContext(); 72 private static final UiAutomation sUiAutomation = 73 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 74 75 @After uninstallTestApp()76 public void uninstallTestApp() { 77 uninstallApp(APP_PKG); 78 } 79 80 @Test 81 @AppModeFull(reason = "Instant apps cannot read properties of other packages") verifybackgroundPermissionsProperties()82 public void verifybackgroundPermissionsProperties() throws Exception { 83 PackageInfo pkg = sContext.getPackageManager().getPackageInfo( 84 "android", PackageManager.GET_PERMISSIONS); 85 ArrayMap<String, String> potentialBackgroundPermissionsToGroup = new ArrayMap<>(); 86 87 int numPermissions = pkg.permissions.length; 88 for (int i = 0; i < numPermissions; i++) { 89 PermissionInfo permission = pkg.permissions[i]; 90 91 // background permissions must be dangerous or ungrantable or role 92 if ((permission.getProtection() & PROTECTION_DANGEROUS) != 0 93 || (permission.getProtection() == PROTECTION_INTERNAL 94 && (permission.getProtectionFlags() == 0 95 || permission.getProtectionFlags() == PermissionInfo.PROTECTION_FLAG_ROLE))) { 96 potentialBackgroundPermissionsToGroup.put(permission.name, permission.group); 97 } 98 } 99 100 for (int i = 0; i < numPermissions; i++) { 101 PermissionInfo permission = pkg.permissions[i]; 102 String backgroundPermissionName = permission.backgroundPermission; 103 104 if (backgroundPermissionName != null) { 105 Log.i(LOG_TAG, permission.name + "->" + backgroundPermissionName); 106 107 // foreground permissions must be dangerous 108 assertNotEquals(0, permission.getProtection() & PROTECTION_DANGEROUS); 109 110 // All foreground permissions need an app op 111 assertNotNull(AppOpsManager.permissionToOp(permission.name)); 112 113 // the background permission must exist 114 assertTrue(potentialBackgroundPermissionsToGroup 115 .containsKey(backgroundPermissionName)); 116 } 117 } 118 } 119 120 /** 121 * If a bg permission is lost during an upgrade, the app-op should downgrade to foreground 122 */ 123 @Test 124 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 125 + "to grant permissions to them. Also instant apps are never updated, hence the test " 126 + "is useless.") appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore()127 public void appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore() throws Exception { 128 install(APK_LOCATION_BACKGROUND_29); 129 grantPermission(APP_PKG, ACCESS_COARSE_LOCATION); 130 131 install(APK_LOCATION_29v4); 132 133 eventually(() -> assertWithMessage("foreground app-op").that( 134 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 135 } 136 137 /** 138 * Make sure location switch-op is set if no location access is granted. 139 */ 140 @Test 141 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 142 + "to grant permissions to them. Also instant apps are never updated, hence the test " 143 + "is useless.") appOpIsSetIfNoLocPermIsGranted()144 public void appOpIsSetIfNoLocPermIsGranted() { 145 install(APK_LOCATION_BACKGROUND_29); 146 147 // Wait until the system sets the app-op automatically 148 eventually(() -> assertWithMessage("loc app-op").that( 149 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_IGNORED)); 150 } 151 152 /** 153 * Make sure location switch-op is set if only coarse location is granted 154 */ 155 @Test 156 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 157 + "to grant permissions to them. Also instant apps are never updated, hence the test " 158 + "is useless.") appOpIsSetIfOnlyCoarseLocPermIsGranted()159 public void appOpIsSetIfOnlyCoarseLocPermIsGranted() { 160 install(APK_LOCATION_BACKGROUND_29); 161 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 162 163 // Wait until the system sets the app-op automatically 164 eventually(() -> assertWithMessage("loc app-op").that( 165 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 166 } 167 168 /** 169 * Make sure location switch-op is set if coarse location with background access is granted. 170 */ 171 @Test 172 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 173 + "to grant permissions to them. Also instant apps are never updated, hence the test " 174 + "is useless.") appOpIsSetIfCoarseAndBgLocPermIsGranted()175 public void appOpIsSetIfCoarseAndBgLocPermIsGranted() { 176 install(APK_LOCATION_BACKGROUND_29); 177 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 178 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION); 179 180 // Wait until the system sets the app-op automatically 181 eventually(() -> assertWithMessage("loc app-op").that( 182 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED)); 183 } 184 185 /** 186 * Make sure location switch-op is set if only fine location is granted 187 */ 188 @Test 189 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 190 + "to grant permissions to them. Also instant apps are never updated, hence the test " 191 + "is useless.") appOpIsSetIfOnlyFineLocPermIsGranted()192 public void appOpIsSetIfOnlyFineLocPermIsGranted() { 193 install(APK_LOCATION_BACKGROUND_29); 194 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 195 196 // Wait until the system sets the app-op automatically 197 // Fine location uses background location to limit access 198 eventually(() -> assertWithMessage("loc app-op").that( 199 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 200 } 201 202 /** 203 * Make sure location switch-op is set if fine location with background access is granted. 204 */ 205 @Test 206 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 207 + "to grant permissions to them. Also instant apps are never updated, hence the test " 208 + "is useless.") appOpIsSetIfFineAndBgLocPermIsGranted()209 public void appOpIsSetIfFineAndBgLocPermIsGranted() { 210 install(APK_LOCATION_BACKGROUND_29); 211 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 212 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION); 213 214 // Wait until the system sets the app-op automatically 215 eventually(() -> assertWithMessage("loc app-op").that( 216 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED)); 217 } 218 219 /** 220 * Make sure location switch-op is set if fine and coarse location access is granted. 221 */ 222 @Test 223 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 224 + "to grant permissions to them. Also instant apps are never updated, hence the test " 225 + "is useless.") appOpIsSetIfFineAndCoarseLocPermIsGranted()226 public void appOpIsSetIfFineAndCoarseLocPermIsGranted() { 227 install(APK_LOCATION_BACKGROUND_29); 228 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 229 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 230 231 // Wait until the system sets the app-op automatically 232 eventually(() -> assertWithMessage("loc app-op").that( 233 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 234 } 235 236 /** 237 * Make sure location switch-op is set if fine and coarse location with background access is 238 * granted. 239 */ 240 @Test 241 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 242 + "to grant permissions to them. Also instant apps are never updated, hence the test " 243 + "is useless.") appOpIsSetIfFineCoarseAndBgLocPermIsGranted()244 public void appOpIsSetIfFineCoarseAndBgLocPermIsGranted() { 245 install(APK_LOCATION_BACKGROUND_29); 246 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 247 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 248 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION); 249 250 // Wait until the system sets the app-op automatically 251 eventually(() -> assertWithMessage("loc app-op").that( 252 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED)); 253 } 254 } 255