1 /* <lambda>null2 * Copyright (C) 2022 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 com.android.server.permission.access.permission 18 19 import android.content.pm.PermissionInfo 20 import android.util.Slog 21 import com.android.modules.utils.BinaryXmlPullParser 22 import com.android.modules.utils.BinaryXmlSerializer 23 import com.android.server.permission.access.AccessState 24 import com.android.server.permission.access.AppIdPermissionFlags 25 import com.android.server.permission.access.MutableAccessState 26 import com.android.server.permission.access.MutableAppIdPermissionFlags 27 import com.android.server.permission.access.WriteMode 28 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports 29 import com.android.server.permission.access.immutable.* // ktlint-disable no-wildcard-imports 30 import com.android.server.permission.access.util.andInv 31 import com.android.server.permission.access.util.attribute 32 import com.android.server.permission.access.util.attributeInt 33 import com.android.server.permission.access.util.attributeIntHex 34 import com.android.server.permission.access.util.attributeIntHexWithDefault 35 import com.android.server.permission.access.util.attributeInterned 36 import com.android.server.permission.access.util.forEachTag 37 import com.android.server.permission.access.util.getAttributeIntHexOrDefault 38 import com.android.server.permission.access.util.getAttributeIntHexOrThrow 39 import com.android.server.permission.access.util.getAttributeIntOrThrow 40 import com.android.server.permission.access.util.getAttributeValue 41 import com.android.server.permission.access.util.getAttributeValueOrThrow 42 import com.android.server.permission.access.util.hasBits 43 import com.android.server.permission.access.util.tag 44 import com.android.server.permission.access.util.tagName 45 46 class AppIdPermissionPersistence { 47 fun BinaryXmlPullParser.parseSystemState(state: MutableAccessState) { 48 when (tagName) { 49 TAG_PERMISSION_TREES -> parsePermissions(state, true) 50 TAG_PERMISSIONS -> parsePermissions(state, false) 51 else -> {} 52 } 53 } 54 55 private fun BinaryXmlPullParser.parsePermissions( 56 state: MutableAccessState, 57 isPermissionTree: Boolean 58 ) { 59 val systemState = state.mutateSystemState(WriteMode.NONE) 60 val permissions = 61 if (isPermissionTree) { 62 systemState.mutatePermissionTrees() 63 } else { 64 systemState.mutatePermissions() 65 } 66 forEachTag { 67 when (val tagName = tagName) { 68 TAG_PERMISSION -> parsePermission(permissions) 69 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $tagName when parsing permissions") 70 } 71 } 72 permissions.forEachReversedIndexed { permissionIndex, _, permission -> 73 val packageName = permission.packageName 74 val externalState = state.externalState 75 if ( 76 packageName !in externalState.packageStates && 77 packageName !in externalState.disabledSystemPackageStates 78 ) { 79 Slog.w( 80 LOG_TAG, 81 "Dropping permission ${permission.name} from unknown package" + 82 " $packageName when parsing permissions" 83 ) 84 permissions.removeAt(permissionIndex) 85 systemState.requestWriteMode(WriteMode.ASYNCHRONOUS) 86 } 87 } 88 } 89 90 private fun BinaryXmlPullParser.parsePermission( 91 permissions: MutableIndexedMap<String, Permission> 92 ) { 93 val name = getAttributeValueOrThrow(ATTR_NAME).intern() 94 @Suppress("DEPRECATION") 95 val permissionInfo = 96 PermissionInfo().apply { 97 this.name = name 98 packageName = getAttributeValueOrThrow(ATTR_PACKAGE_NAME).intern() 99 protectionLevel = getAttributeIntHexOrThrow(ATTR_PROTECTION_LEVEL) 100 } 101 val type = getAttributeIntOrThrow(ATTR_TYPE) 102 when (type) { 103 Permission.TYPE_MANIFEST -> {} 104 Permission.TYPE_DYNAMIC -> { 105 permissionInfo.apply { 106 icon = getAttributeIntHexOrDefault(ATTR_ICON, 0) 107 nonLocalizedLabel = getAttributeValue(ATTR_LABEL) 108 } 109 } 110 else -> { 111 Slog.w(LOG_TAG, "Ignoring permission $name with unknown type $type") 112 return 113 } 114 } 115 val permission = Permission(permissionInfo, false, type, 0) 116 permissions[name] = permission 117 } 118 119 fun BinaryXmlSerializer.serializeSystemState(state: AccessState) { 120 val systemState = state.systemState 121 serializePermissions(TAG_PERMISSION_TREES, systemState.permissionTrees) 122 serializePermissions(TAG_PERMISSIONS, systemState.permissions) 123 } 124 125 private fun BinaryXmlSerializer.serializePermissions( 126 tagName: String, 127 permissions: IndexedMap<String, Permission> 128 ) { 129 tag(tagName) { permissions.forEachIndexed { _, _, it -> serializePermission(it) } } 130 } 131 132 private fun BinaryXmlSerializer.serializePermission(permission: Permission) { 133 tag(TAG_PERMISSION) { 134 attributeInterned(ATTR_NAME, permission.name) 135 attributeInterned(ATTR_PACKAGE_NAME, permission.packageName) 136 attributeIntHex(ATTR_PROTECTION_LEVEL, permission.protectionLevel) 137 val type = permission.type 138 attributeInt(ATTR_TYPE, type) 139 if (type == Permission.TYPE_DYNAMIC) { 140 val permissionInfo = permission.permissionInfo 141 attributeIntHexWithDefault(ATTR_ICON, permissionInfo.icon, 0) 142 permissionInfo.nonLocalizedLabel?.toString()?.let { attribute(ATTR_LABEL, it) } 143 } 144 } 145 } 146 147 fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) { 148 when (tagName) { 149 TAG_APP_ID_PERMISSIONS -> parseAppIdPermissions(state, userId) 150 else -> {} 151 } 152 } 153 154 private fun BinaryXmlPullParser.parseAppIdPermissions(state: MutableAccessState, userId: Int) { 155 val userState = state.mutateUserState(userId, WriteMode.NONE)!! 156 val appIdPermissionFlags = userState.mutateAppIdPermissionFlags() 157 forEachTag { 158 when (tagName) { 159 TAG_APP_ID -> parseAppId(appIdPermissionFlags) 160 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state") 161 } 162 } 163 appIdPermissionFlags.forEachReversedIndexed { appIdIndex, appId, _ -> 164 if (appId !in state.externalState.appIdPackageNames) { 165 Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state") 166 appIdPermissionFlags.removeAt(appIdIndex) 167 userState.requestWriteMode(WriteMode.ASYNCHRONOUS) 168 } 169 } 170 } 171 172 private fun BinaryXmlPullParser.parseAppId(appIdPermissionFlags: MutableAppIdPermissionFlags) { 173 val appId = getAttributeIntOrThrow(ATTR_ID) 174 val permissionFlags = MutableIndexedMap<String, Int>() 175 appIdPermissionFlags[appId] = permissionFlags 176 forEachTag { 177 when (tagName) { 178 TAG_PERMISSION -> parseAppIdPermission(permissionFlags) 179 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state") 180 } 181 } 182 } 183 184 private fun BinaryXmlPullParser.parseAppIdPermission( 185 permissionFlags: MutableIndexedMap<String, Int> 186 ) { 187 val name = getAttributeValueOrThrow(ATTR_NAME).intern() 188 val flags = getAttributeIntOrThrow(ATTR_FLAGS) 189 permissionFlags[name] = flags 190 } 191 192 fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) { 193 serializeAppIdPermissions(state.userStates[userId]!!.appIdPermissionFlags) 194 } 195 196 private fun BinaryXmlSerializer.serializeAppIdPermissions( 197 appIdPermissionFlags: AppIdPermissionFlags 198 ) { 199 tag(TAG_APP_ID_PERMISSIONS) { 200 appIdPermissionFlags.forEachIndexed { _, appId, permissionFlags -> 201 serializeAppId(appId, permissionFlags) 202 } 203 } 204 } 205 206 private fun BinaryXmlSerializer.serializeAppId( 207 appId: Int, 208 permissionFlags: IndexedMap<String, Int> 209 ) { 210 tag(TAG_APP_ID) { 211 attributeInt(ATTR_ID, appId) 212 permissionFlags.forEachIndexed { _, name, flags -> 213 serializeAppIdPermission(name, flags) 214 } 215 } 216 } 217 218 private fun BinaryXmlSerializer.serializeAppIdPermission(name: String, flags: Int) { 219 tag(TAG_PERMISSION) { 220 attributeInterned(ATTR_NAME, name) 221 // Never serialize one-time permissions as granted. 222 val serializedFlags = 223 if (flags.hasBits(PermissionFlags.ONE_TIME)) { 224 flags andInv PermissionFlags.RUNTIME_GRANTED 225 } else { 226 flags 227 } 228 attributeInt(ATTR_FLAGS, serializedFlags) 229 } 230 } 231 232 companion object { 233 private val LOG_TAG = AppIdPermissionPersistence::class.java.simpleName 234 235 private const val TAG_APP_ID = "app-id" 236 private const val TAG_APP_ID_PERMISSIONS = "app-id-permissions" 237 private const val TAG_PERMISSION = "permission" 238 private const val TAG_PERMISSIONS = "permissions" 239 private const val TAG_PERMISSION_TREES = "permission-trees" 240 241 private const val ATTR_FLAGS = "flags" 242 private const val ATTR_ICON = "icon" 243 private const val ATTR_ID = "id" 244 private const val ATTR_LABEL = "label" 245 private const val ATTR_NAME = "name" 246 private const val ATTR_PACKAGE_NAME = "packageName" 247 private const val ATTR_PROTECTION_LEVEL = "protectionLevel" 248 private const val ATTR_TYPE = "type" 249 } 250 } 251