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.health.connect.HealthPermissions.HEALTH_PERMISSION_GROUP; 28 import static android.permission.cts.PermissionUtils.getAppOp; 29 import static android.permission.cts.PermissionUtils.grantPermission; 30 import static android.permission.cts.PermissionUtils.install; 31 import static android.permission.cts.PermissionUtils.uninstallApp; 32 33 import static com.android.compatibility.common.util.SystemUtil.eventually; 34 35 import static com.google.common.truth.Truth.assertThat; 36 import static com.google.common.truth.Truth.assertWithMessage; 37 38 import static org.junit.Assert.assertNotEquals; 39 import static org.junit.Assert.assertNotNull; 40 import static org.junit.Assert.assertTrue; 41 42 import android.app.AppOpsManager; 43 import android.app.UiAutomation; 44 import android.content.Context; 45 import android.content.pm.PackageInfo; 46 import android.content.pm.PackageManager; 47 import android.content.pm.PermissionInfo; 48 import android.os.Build; 49 import android.permission.flags.Flags; 50 import android.platform.test.annotations.AppModeFull; 51 import android.platform.test.annotations.RequiresFlagsEnabled; 52 import android.platform.test.flag.junit.CheckFlagsRule; 53 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 54 import android.util.ArrayMap; 55 import android.util.Log; 56 57 import androidx.test.filters.SdkSuppress; 58 import androidx.test.platform.app.InstrumentationRegistry; 59 import androidx.test.runner.AndroidJUnit4; 60 61 import org.junit.After; 62 import org.junit.Rule; 63 import org.junit.Test; 64 import org.junit.runner.RunWith; 65 66 @RunWith(AndroidJUnit4.class) 67 public class BackgroundPermissionsTest { 68 private static final String LOG_TAG = BackgroundPermissionsTest.class.getSimpleName(); 69 70 /** The package name of all apps used in the test */ 71 private static final String APP_PKG = "android.permission.cts.appthatrequestpermission"; 72 73 private static final String TMP_DIR = "/data/local/tmp/cts-permission/"; 74 private static final String APK_LOCATION_BACKGROUND_29 = 75 TMP_DIR + "CtsAppThatRequestsLocationAndBackgroundPermission29.apk"; 76 private static final String APK_LOCATION_29v4 = 77 TMP_DIR + "CtsAppThatRequestsLocationPermission29v4.apk"; 78 79 private static final Context sContext = 80 InstrumentationRegistry.getInstrumentation().getTargetContext(); 81 private static final UiAutomation sUiAutomation = 82 InstrumentationRegistry.getInstrumentation().getUiAutomation(); 83 84 @Rule 85 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 86 87 @After uninstallTestApp()88 public void uninstallTestApp() { 89 uninstallApp(APP_PKG); 90 } 91 92 @Test 93 @AppModeFull(reason = "Instant apps cannot read properties of other packages") verifyBackgroundPropertiesForPlatformPermissions()94 public void verifyBackgroundPropertiesForPlatformPermissions() throws Exception { 95 verifyBackgroundPermissionsProperties("android"); 96 } 97 98 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.BAKLAVA, codeName = "Baklava") 99 @RequiresFlagsEnabled({Flags.FLAG_REPLACE_BODY_SENSOR_PERMISSION_ENABLED}) 100 @Test 101 @AppModeFull(reason = "Instant apps cannot read properties of other packages") verifyBackgroundPropertiesForHealthPermissions()102 public void verifyBackgroundPropertiesForHealthPermissions() throws Exception { 103 String healthPackageName = sContext.getPackageManager().getPermissionGroupInfo( 104 HEALTH_PERMISSION_GROUP, /* flags= */ 0).packageName; 105 verifyBackgroundPermissionsProperties(healthPackageName); 106 } 107 verifyBackgroundPermissionsProperties(String packageName)108 private void verifyBackgroundPermissionsProperties(String packageName) 109 throws Exception { 110 PackageInfo pkg = sContext.getPackageManager().getPackageInfo( 111 packageName, PackageManager.GET_PERMISSIONS); 112 ArrayMap<String, String> potentialBackgroundPermissionsToGroup = new ArrayMap<>(); 113 114 int numPermissions = pkg.permissions.length; 115 for (int i = 0; i < numPermissions; i++) { 116 PermissionInfo permission = pkg.permissions[i]; 117 118 // background permissions must be dangerous or ungrantable or role 119 if ((permission.getProtection() & PROTECTION_DANGEROUS) != 0 120 || (permission.getProtection() == PROTECTION_INTERNAL 121 && (permission.getProtectionFlags() == 0 122 || permission.getProtectionFlags() == PermissionInfo.PROTECTION_FLAG_ROLE))) { 123 potentialBackgroundPermissionsToGroup.put(permission.name, permission.group); 124 } 125 } 126 127 int backgroundPermissionCount = 0; 128 for (int i = 0; i < numPermissions; i++) { 129 PermissionInfo permission = pkg.permissions[i]; 130 String backgroundPermissionName = permission.backgroundPermission; 131 132 if (backgroundPermissionName != null) { 133 backgroundPermissionCount += 1; 134 Log.i(LOG_TAG, permission.name + "->" + backgroundPermissionName); 135 136 // foreground permissions must be dangerous 137 assertNotEquals(0, permission.getProtection() & PROTECTION_DANGEROUS); 138 139 // All foreground permissions need an app op 140 assertNotNull(AppOpsManager.permissionToOp(permission.name)); 141 142 // the background permission must exist 143 assertTrue(potentialBackgroundPermissionsToGroup 144 .containsKey(backgroundPermissionName)); 145 } 146 } 147 // Tested packages must have at least one permission linked with a background permission. 148 assertThat(backgroundPermissionCount).isGreaterThan(0); 149 } 150 151 /** 152 * If a bg permission is lost during an upgrade, the app-op should downgrade to foreground 153 */ 154 @Test 155 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 156 + "to grant permissions to them. Also instant apps are never updated, hence the test " 157 + "is useless.") appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore()158 public void appOpGetsDowngradedWhenBgPermIsNotRequestedAnymore() throws Exception { 159 install(APK_LOCATION_BACKGROUND_29); 160 grantPermission(APP_PKG, ACCESS_COARSE_LOCATION); 161 162 install(APK_LOCATION_29v4); 163 164 eventually(() -> assertWithMessage("foreground 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 no location 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.") appOpIsSetIfNoLocPermIsGranted()175 public void appOpIsSetIfNoLocPermIsGranted() { 176 install(APK_LOCATION_BACKGROUND_29); 177 178 // Wait until the system sets the app-op automatically 179 eventually(() -> assertWithMessage("loc app-op").that( 180 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_IGNORED)); 181 } 182 183 /** 184 * Make sure location switch-op is set if only coarse location is granted 185 */ 186 @Test 187 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 188 + "to grant permissions to them. Also instant apps are never updated, hence the test " 189 + "is useless.") appOpIsSetIfOnlyCoarseLocPermIsGranted()190 public void appOpIsSetIfOnlyCoarseLocPermIsGranted() { 191 install(APK_LOCATION_BACKGROUND_29); 192 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 193 194 // Wait until the system sets the app-op automatically 195 eventually(() -> assertWithMessage("loc app-op").that( 196 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 197 } 198 199 /** 200 * Make sure location switch-op is set if coarse location with background access is granted. 201 */ 202 @Test 203 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 204 + "to grant permissions to them. Also instant apps are never updated, hence the test " 205 + "is useless.") appOpIsSetIfCoarseAndBgLocPermIsGranted()206 public void appOpIsSetIfCoarseAndBgLocPermIsGranted() { 207 install(APK_LOCATION_BACKGROUND_29); 208 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 209 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION); 210 211 // Wait until the system sets the app-op automatically 212 eventually(() -> assertWithMessage("loc app-op").that( 213 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED)); 214 } 215 216 /** 217 * Make sure location switch-op is set if only fine location is granted 218 */ 219 @Test 220 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 221 + "to grant permissions to them. Also instant apps are never updated, hence the test " 222 + "is useless.") appOpIsSetIfOnlyFineLocPermIsGranted()223 public void appOpIsSetIfOnlyFineLocPermIsGranted() { 224 install(APK_LOCATION_BACKGROUND_29); 225 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 226 227 // Wait until the system sets the app-op automatically 228 // Fine location uses background location to limit access 229 eventually(() -> assertWithMessage("loc app-op").that( 230 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 231 } 232 233 /** 234 * Make sure location switch-op is set if fine location with background access is granted. 235 */ 236 @Test 237 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 238 + "to grant permissions to them. Also instant apps are never updated, hence the test " 239 + "is useless.") appOpIsSetIfFineAndBgLocPermIsGranted()240 public void appOpIsSetIfFineAndBgLocPermIsGranted() { 241 install(APK_LOCATION_BACKGROUND_29); 242 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 243 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION); 244 245 // Wait until the system sets the app-op automatically 246 eventually(() -> assertWithMessage("loc app-op").that( 247 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED)); 248 } 249 250 /** 251 * Make sure location switch-op is set if fine and coarse location access is granted. 252 */ 253 @Test 254 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 255 + "to grant permissions to them. Also instant apps are never updated, hence the test " 256 + "is useless.") appOpIsSetIfFineAndCoarseLocPermIsGranted()257 public void appOpIsSetIfFineAndCoarseLocPermIsGranted() { 258 install(APK_LOCATION_BACKGROUND_29); 259 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 260 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 261 262 // Wait until the system sets the app-op automatically 263 eventually(() -> assertWithMessage("loc app-op").that( 264 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_FOREGROUND)); 265 } 266 267 /** 268 * Make sure location switch-op is set if fine and coarse location with background access is 269 * granted. 270 */ 271 @Test 272 @AppModeFull(reason = "Instant apps cannot read properties of other packages which is needed " 273 + "to grant permissions to them. Also instant apps are never updated, hence the test " 274 + "is useless.") appOpIsSetIfFineCoarseAndBgLocPermIsGranted()275 public void appOpIsSetIfFineCoarseAndBgLocPermIsGranted() { 276 install(APK_LOCATION_BACKGROUND_29); 277 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_FINE_LOCATION); 278 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_COARSE_LOCATION); 279 sUiAutomation.grantRuntimePermission(APP_PKG, ACCESS_BACKGROUND_LOCATION); 280 281 // Wait until the system sets the app-op automatically 282 eventually(() -> assertWithMessage("loc app-op").that( 283 getAppOp(APP_PKG, ACCESS_COARSE_LOCATION)).isEqualTo(MODE_ALLOWED)); 284 } 285 } 286