1 /* 2 * Copyright (C) 2019 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.permissionpolicy.cts 18 19 import android.Manifest.permission.ACCEPT_HANDOVER 20 import android.Manifest.permission.ACCESS_COARSE_LOCATION 21 import android.Manifest.permission.ACCESS_FINE_LOCATION 22 import android.Manifest.permission.ACTIVITY_RECOGNITION 23 import android.Manifest.permission.ADD_VOICEMAIL 24 import android.Manifest.permission.ANSWER_PHONE_CALLS 25 import android.Manifest.permission.BLUETOOTH_ADVERTISE 26 import android.Manifest.permission.BLUETOOTH_CONNECT 27 import android.Manifest.permission.BLUETOOTH_SCAN 28 import android.Manifest.permission.BODY_SENSORS 29 import android.Manifest.permission.CALL_PHONE 30 import android.Manifest.permission.CAMERA 31 import android.Manifest.permission.GET_ACCOUNTS 32 import android.Manifest.permission.NEARBY_WIFI_DEVICES 33 import android.Manifest.permission.PACKAGE_USAGE_STATS 34 import android.Manifest.permission.POST_NOTIFICATIONS 35 import android.Manifest.permission.PROCESS_OUTGOING_CALLS 36 import android.Manifest.permission.RANGING 37 import android.Manifest.permission.READ_CALENDAR 38 import android.Manifest.permission.READ_CALL_LOG 39 import android.Manifest.permission.READ_CELL_BROADCASTS 40 import android.Manifest.permission.READ_CONTACTS 41 import android.Manifest.permission.READ_EXTERNAL_STORAGE 42 import android.Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED 43 import android.Manifest.permission.READ_PHONE_NUMBERS 44 import android.Manifest.permission.READ_PHONE_STATE 45 import android.Manifest.permission.READ_SMS 46 import android.Manifest.permission.RECEIVE_MMS 47 import android.Manifest.permission.RECEIVE_SMS 48 import android.Manifest.permission.RECEIVE_WAP_PUSH 49 import android.Manifest.permission.RECORD_AUDIO 50 import android.Manifest.permission.SEND_SMS 51 import android.Manifest.permission.USE_SIP 52 import android.Manifest.permission.UWB_RANGING 53 import android.Manifest.permission.WRITE_CALENDAR 54 import android.Manifest.permission.WRITE_CALL_LOG 55 import android.Manifest.permission.WRITE_CONTACTS 56 import android.Manifest.permission.WRITE_EXTERNAL_STORAGE 57 import android.Manifest.permission_group.UNDEFINED 58 import android.app.AppOpsManager.permissionToOp 59 import android.content.pm.PackageManager.GET_PERMISSIONS 60 import android.content.pm.PermissionInfo.PROTECTION_DANGEROUS 61 import android.content.pm.PermissionInfo.PROTECTION_FLAG_APPOP 62 import android.health.connect.HealthPermissions 63 import android.os.Build 64 import android.permission.flags.Flags 65 import android.permission.PermissionManager 66 import androidx.test.platform.app.InstrumentationRegistry 67 import androidx.test.runner.AndroidJUnit4 68 import com.google.common.truth.Truth.assertThat 69 import com.google.common.truth.Truth.assertWithMessage 70 import org.junit.Test 71 import org.junit.runner.RunWith 72 73 @RunWith(AndroidJUnit4::class) 74 class RuntimePermissionProperties { 75 private val context = InstrumentationRegistry.getInstrumentation().getTargetContext() 76 private val pm = context.packageManager 77 78 private val platformPkg = pm.getPackageInfo("android", GET_PERMISSIONS) 79 private val platformRuntimePerms = <lambda>null80 platformPkg.permissions!!.filter { it.protection == PROTECTION_DANGEROUS } <lambda>null81 private val platformBgPermNames = platformRuntimePerms.mapNotNull { it.backgroundPermission } 82 83 @Test allRuntimeForegroundPermissionNeedAnAppOpnull84 fun allRuntimeForegroundPermissionNeedAnAppOp() { 85 val platformFgPerms = platformRuntimePerms.filter { !platformBgPermNames.contains(it.name) } 86 87 for (perm in platformFgPerms) { 88 assertWithMessage("AppOp for ${perm.name}").that(permissionToOp(perm.name)).isNotNull() 89 } 90 } 91 92 @Test groupOfRuntimePermissionsShouldBeUnknownnull93 fun groupOfRuntimePermissionsShouldBeUnknown() { 94 for (perm in platformRuntimePerms) { 95 assertWithMessage("Group of ${perm.name}").that(perm.group).isEqualTo(UNDEFINED) 96 } 97 } 98 99 @Test allAppOpPermissionNeedAnAppOpnull100 fun allAppOpPermissionNeedAnAppOp() { 101 val platformAppOpPerms = 102 platformPkg.permissions!! 103 .filter { (it.protectionFlags and PROTECTION_FLAG_APPOP) != 0 } 104 .filter { 105 // Grandfather incomplete definition of PACKAGE_USAGE_STATS 106 it.name != PACKAGE_USAGE_STATS 107 } 108 109 for (perm in platformAppOpPerms) { 110 assertWithMessage("AppOp for ${perm.name}").that(permissionToOp(perm.name)).isNotNull() 111 } 112 } 113 114 /** The permission of a background permission is the one of its foreground permission */ 115 @Test allRuntimeBackgroundPermissionCantHaveAnAppOpnull116 fun allRuntimeBackgroundPermissionCantHaveAnAppOp() { 117 val platformBgPerms = platformRuntimePerms.filter { platformBgPermNames.contains(it.name) } 118 119 for (perm in platformBgPerms) { 120 assertWithMessage("AppOp for ${perm.name}").that(permissionToOp(perm.name)).isNull() 121 } 122 } 123 124 /** Commonly a new runtime permission is created by splitting an old one into twice */ 125 @Test runtimePermissionsShouldHaveBeenSplitFromPreviousPermissionnull126 fun runtimePermissionsShouldHaveBeenSplitFromPreviousPermission() { 127 // Runtime permissions in Android P 128 val expectedPerms = 129 mutableSetOf( 130 READ_CONTACTS, 131 WRITE_CONTACTS, 132 GET_ACCOUNTS, 133 READ_CALENDAR, 134 WRITE_CALENDAR, 135 SEND_SMS, 136 RECEIVE_SMS, 137 READ_SMS, 138 RECEIVE_MMS, 139 RECEIVE_WAP_PUSH, 140 READ_CELL_BROADCASTS, 141 READ_EXTERNAL_STORAGE, 142 WRITE_EXTERNAL_STORAGE, 143 ACCESS_FINE_LOCATION, 144 ACCESS_COARSE_LOCATION, 145 READ_CALL_LOG, 146 WRITE_CALL_LOG, 147 PROCESS_OUTGOING_CALLS, 148 READ_PHONE_STATE, 149 READ_PHONE_NUMBERS, 150 CALL_PHONE, 151 ADD_VOICEMAIL, 152 USE_SIP, 153 ANSWER_PHONE_CALLS, 154 ACCEPT_HANDOVER, 155 RECORD_AUDIO, 156 CAMERA, 157 BODY_SENSORS 158 ) 159 160 // Add permission split since P 161 for (sdkVersion in Build.VERSION_CODES.P + 1..Build.VERSION_CODES.CUR_DEVELOPMENT + 1) { 162 for (splitPerm in 163 context.getSystemService(PermissionManager::class.java)!!.splitPermissions) { 164 if ( 165 splitPerm.targetSdk == sdkVersion && 166 expectedPerms.contains(splitPerm.splitPermission) 167 ) { 168 expectedPerms.addAll(splitPerm.newPermissions) 169 } 170 } 171 } 172 173 // Add runtime permission added in Q which were _not_ split from a previously existing 174 // runtime permission 175 expectedPerms.add(ACTIVITY_RECOGNITION) 176 177 // Add runtime permissions added in S which were _not_ split from a previously existing 178 // runtime permission 179 expectedPerms.add(BLUETOOTH_ADVERTISE) 180 expectedPerms.add(BLUETOOTH_CONNECT) 181 expectedPerms.add(BLUETOOTH_SCAN) 182 expectedPerms.add(UWB_RANGING) 183 184 // Add runtime permissions added in T which were _not_ split from a previously existing 185 // runtime permission 186 expectedPerms.add(POST_NOTIFICATIONS) 187 expectedPerms.add(NEARBY_WIFI_DEVICES) 188 189 // Add runtime permissions added in U which were _not_ split from a previously existing 190 // runtime permission 191 expectedPerms.add(READ_MEDIA_VISUAL_USER_SELECTED) 192 193 // Add runtime permissions added in B which were _not_ split from a previously existing 194 // runtime permission 195 if (Flags.rangingPermissionEnabled()) { 196 expectedPerms.add(RANGING) 197 } 198 199 // Separately check health permissions. 200 if (Flags.replaceBodySensorPermissionEnabled()) { 201 assertThat(expectedPerms).contains(HealthPermissions.READ_HEART_RATE); 202 assertThat(expectedPerms).contains(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND); 203 204 // Remove these from the expected list once we've confirmed their 205 // present. These are not permissions owned by "android" so won't be 206 // in the list of platform runtime permissions. 207 expectedPerms.remove(HealthPermissions.READ_HEART_RATE); 208 expectedPerms.remove(HealthPermissions.READ_HEALTH_DATA_IN_BACKGROUND); 209 } 210 211 assertThat(platformRuntimePerms.map { it.name }).containsExactlyElementsIn(expectedPerms) 212 } 213 } 214