1 /* 2 * 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.Log 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.UserState 25 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports 26 import com.android.server.permission.access.util.attribute 27 import com.android.server.permission.access.util.attributeInt 28 import com.android.server.permission.access.util.attributeIntHex 29 import com.android.server.permission.access.util.attributeIntHexWithDefault 30 import com.android.server.permission.access.util.attributeInterned 31 import com.android.server.permission.access.util.forEachTag 32 import com.android.server.permission.access.util.getAttributeIntHexOrDefault 33 import com.android.server.permission.access.util.getAttributeIntHexOrThrow 34 import com.android.server.permission.access.util.getAttributeIntOrThrow 35 import com.android.server.permission.access.util.getAttributeValue 36 import com.android.server.permission.access.util.getAttributeValueOrThrow 37 import com.android.server.permission.access.util.tag 38 import com.android.server.permission.access.util.tagName 39 40 class UidPermissionPersistence { 41 fun BinaryXmlPullParser.parseSystemState(state: AccessState) { 42 val systemState = state.systemState 43 when (tagName) { 44 TAG_PERMISSION_TREES -> parsePermissions(systemState.permissionTrees) 45 TAG_PERMISSIONS -> parsePermissions(systemState.permissions) 46 else -> {} 47 } 48 } 49 50 private fun BinaryXmlPullParser.parsePermissions(permissions: IndexedMap<String, Permission>) { 51 forEachTag { 52 when (val tagName = tagName) { 53 TAG_PERMISSION -> parsePermission(permissions) 54 else -> Log.w(LOG_TAG, "Ignoring unknown tag $tagName when parsing permissions") 55 } 56 } 57 } 58 59 private fun BinaryXmlPullParser.parsePermission(permissions: IndexedMap<String, Permission>) { 60 val name = getAttributeValueOrThrow(ATTR_NAME).intern() 61 @Suppress("DEPRECATION") 62 val permissionInfo = PermissionInfo().apply { 63 this.name = name 64 packageName = getAttributeValueOrThrow(ATTR_PACKAGE_NAME).intern() 65 protectionLevel = getAttributeIntHexOrThrow(ATTR_PROTECTION_LEVEL) 66 } 67 val type = getAttributeIntOrThrow(ATTR_TYPE) 68 when (type) { 69 Permission.TYPE_MANIFEST -> {} 70 Permission.TYPE_CONFIG -> { 71 Log.w(LOG_TAG, "Ignoring unexpected config permission $name") 72 return 73 } 74 Permission.TYPE_DYNAMIC -> { 75 permissionInfo.apply { 76 icon = getAttributeIntHexOrDefault(ATTR_ICON, 0) 77 nonLocalizedLabel = getAttributeValue(ATTR_LABEL) 78 } 79 } 80 else -> { 81 Log.w(LOG_TAG, "Ignoring permission $name with unknown type $type") 82 return 83 } 84 } 85 val permission = Permission(permissionInfo, false, type, 0) 86 permissions[name] = permission 87 } 88 89 fun BinaryXmlSerializer.serializeSystemState(state: AccessState) { 90 val systemState = state.systemState 91 serializePermissions(TAG_PERMISSION_TREES, systemState.permissionTrees) 92 serializePermissions(TAG_PERMISSIONS, systemState.permissions) 93 } 94 95 private fun BinaryXmlSerializer.serializePermissions( 96 tagName: String, 97 permissions: IndexedMap<String, Permission> 98 ) { 99 tag(tagName) { 100 permissions.forEachValueIndexed { _, it -> serializePermission(it) } 101 } 102 } 103 104 private fun BinaryXmlSerializer.serializePermission(permission: Permission) { 105 val type = permission.type 106 when (type) { 107 Permission.TYPE_MANIFEST, Permission.TYPE_DYNAMIC -> {} 108 Permission.TYPE_CONFIG -> return 109 else -> { 110 Log.w(LOG_TAG, "Skipping serializing permission $name with unknown type $type") 111 return 112 } 113 } 114 tag(TAG_PERMISSION) { 115 attributeInterned(ATTR_NAME, permission.name) 116 attributeInterned(ATTR_PACKAGE_NAME, permission.packageName) 117 attributeIntHex(ATTR_PROTECTION_LEVEL, permission.protectionLevel) 118 attributeInt(ATTR_TYPE, type) 119 if (type == Permission.TYPE_DYNAMIC) { 120 val permissionInfo = permission.permissionInfo 121 attributeIntHexWithDefault(ATTR_ICON, permissionInfo.icon, 0) 122 permissionInfo.nonLocalizedLabel?.toString()?.let { attribute(ATTR_LABEL, it) } 123 } 124 } 125 } 126 127 fun BinaryXmlPullParser.parseUserState(state: AccessState, userId: Int) { 128 when (tagName) { 129 TAG_PERMISSIONS -> parsePermissionFlags(state, userId) 130 else -> {} 131 } 132 } 133 134 private fun BinaryXmlPullParser.parsePermissionFlags(state: AccessState, userId: Int) { 135 val userState = state.userStates[userId] 136 forEachTag { 137 when (tagName) { 138 TAG_APP_ID -> parseAppId(userState) 139 else -> Log.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state") 140 } 141 } 142 userState.uidPermissionFlags.retainAllIndexed { _, appId, _ -> 143 val hasAppId = appId in state.systemState.appIds 144 if (!hasAppId) { 145 Log.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state") 146 } 147 hasAppId 148 } 149 } 150 151 private fun BinaryXmlPullParser.parseAppId(userState: UserState) { 152 val appId = getAttributeIntOrThrow(ATTR_ID) 153 val permissionFlags = IndexedMap<String, Int>() 154 userState.uidPermissionFlags[appId] = permissionFlags 155 parseAppIdPermissions(permissionFlags) 156 } 157 158 private fun BinaryXmlPullParser.parseAppIdPermissions( 159 permissionFlags: IndexedMap<String, Int> 160 ) { 161 forEachTag { 162 when (tagName) { 163 TAG_PERMISSION -> parseAppIdPermission(permissionFlags) 164 else -> Log.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state") 165 } 166 } 167 } 168 169 private fun BinaryXmlPullParser.parseAppIdPermission(permissionFlags: IndexedMap<String, Int>) { 170 val name = getAttributeValueOrThrow(ATTR_NAME).intern() 171 val flags = getAttributeIntOrThrow(ATTR_FLAGS) 172 permissionFlags[name] = flags 173 } 174 175 fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) { 176 serializePermissionFlags(state.userStates[userId]) 177 } 178 179 private fun BinaryXmlSerializer.serializePermissionFlags(userState: UserState) { 180 tag(TAG_PERMISSIONS) { 181 userState.uidPermissionFlags.forEachIndexed { _, appId, permissionFlags -> 182 serializeAppId(appId, permissionFlags) 183 } 184 } 185 } 186 187 private fun BinaryXmlSerializer.serializeAppId( 188 appId: Int, 189 permissionFlags: IndexedMap<String, Int> 190 ) { 191 tag(TAG_APP_ID) { 192 attributeInt(ATTR_ID, appId) 193 serializeAppIdPermissions(permissionFlags) 194 } 195 } 196 197 private fun BinaryXmlSerializer.serializeAppIdPermissions( 198 permissionFlags: IndexedMap<String, Int> 199 ) { 200 permissionFlags.forEachIndexed { _, name, flags -> 201 serializeAppIdPermission(name, flags) 202 } 203 } 204 205 private fun BinaryXmlSerializer.serializeAppIdPermission(name: String, flags: Int) { 206 tag(TAG_PERMISSION) { 207 attributeInterned(ATTR_NAME, name) 208 attributeInt(ATTR_FLAGS, flags) 209 } 210 } 211 212 companion object { 213 private val LOG_TAG = UidPermissionPersistence::class.java.simpleName 214 215 private const val TAG_APP_ID = "app-id" 216 private const val TAG_PERMISSION = "permission" 217 private const val TAG_PERMISSIONS = "permissions" 218 private const val TAG_PERMISSION_TREES = "permission-trees" 219 220 private const val ATTR_FLAGS = "flags" 221 private const val ATTR_ICON = "icon" 222 private const val ATTR_ID = "id" 223 private const val ATTR_LABEL = "label" 224 private const val ATTR_NAME = "name" 225 private const val ATTR_PACKAGE_NAME = "packageName" 226 private const val ATTR_PROTECTION_LEVEL = "protectionLevel" 227 private const val ATTR_TYPE = "type" 228 } 229 } 230