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