1 /*
<lambda>null2  * Copyright (C) 2023 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.util.Slog
20 import com.android.modules.utils.BinaryXmlPullParser
21 import com.android.modules.utils.BinaryXmlSerializer
22 import com.android.server.permission.access.AccessState
23 import com.android.server.permission.access.DevicePermissionFlags
24 import com.android.server.permission.access.MutableAccessState
25 import com.android.server.permission.access.MutableAppIdDevicePermissionFlags
26 import com.android.server.permission.access.MutableDevicePermissionFlags
27 import com.android.server.permission.access.WriteMode
28 import com.android.server.permission.access.immutable.IndexedMap
29 import com.android.server.permission.access.immutable.MutableIndexedMap
30 import com.android.server.permission.access.immutable.forEachIndexed
31 import com.android.server.permission.access.immutable.forEachReversedIndexed
32 import com.android.server.permission.access.immutable.set
33 import com.android.server.permission.access.util.andInv
34 import com.android.server.permission.access.util.attributeInt
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.getAttributeIntOrThrow
38 import com.android.server.permission.access.util.getAttributeValueOrThrow
39 import com.android.server.permission.access.util.hasBits
40 import com.android.server.permission.access.util.tag
41 import com.android.server.permission.access.util.tagName
42 
43 class DevicePermissionPersistence {
44     fun BinaryXmlPullParser.parseUserState(state: MutableAccessState, userId: Int) {
45         when (tagName) {
46             TAG_APP_ID_DEVICE_PERMISSIONS -> parseAppIdDevicePermissions(state, userId)
47             else -> {}
48         }
49     }
50 
51     private fun BinaryXmlPullParser.parseAppIdDevicePermissions(
52         state: MutableAccessState,
53         userId: Int
54     ) {
55         val userState = state.mutateUserState(userId, WriteMode.NONE)!!
56         val appIdDevicePermissionFlags = userState.mutateAppIdDevicePermissionFlags()
57         forEachTag {
58             when (tagName) {
59                 TAG_APP_ID -> parseAppId(appIdDevicePermissionFlags)
60                 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
61             }
62         }
63 
64         appIdDevicePermissionFlags.forEachReversedIndexed { appIdIndex, appId, _ ->
65             if (appId !in state.externalState.appIdPackageNames) {
66                 Slog.w(LOG_TAG, "Dropping unknown app ID $appId when parsing permission state")
67                 appIdDevicePermissionFlags.removeAt(appIdIndex)
68                 userState.requestWriteMode(WriteMode.ASYNCHRONOUS)
69             }
70         }
71     }
72 
73     private fun BinaryXmlPullParser.parseAppId(
74         appIdPermissionFlags: MutableAppIdDevicePermissionFlags
75     ) {
76         val appId = getAttributeIntOrThrow(ATTR_ID)
77         val devicePermissionFlags = MutableDevicePermissionFlags()
78         appIdPermissionFlags[appId] = devicePermissionFlags
79         forEachTag {
80             when (tagName) {
81                 TAG_DEVICE -> parseDevice(devicePermissionFlags)
82                 else -> {
83                     Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
84                 }
85             }
86         }
87     }
88 
89     private fun BinaryXmlPullParser.parseDevice(
90         deviceIdPermissionFlags: MutableDevicePermissionFlags
91     ) {
92         val deviceId = getAttributeValueOrThrow(ATTR_ID)
93         val permissionFlags = MutableIndexedMap<String, Int>()
94         deviceIdPermissionFlags.put(deviceId, permissionFlags)
95         forEachTag {
96             when (tagName) {
97                 TAG_PERMISSION -> parsePermission(permissionFlags)
98                 else -> Slog.w(LOG_TAG, "Ignoring unknown tag $name when parsing permission state")
99             }
100         }
101     }
102 
103     private fun BinaryXmlPullParser.parsePermission(
104         permissionFlags: MutableIndexedMap<String, Int>
105     ) {
106         val name = getAttributeValueOrThrow(ATTR_NAME).intern()
107         val flags = getAttributeIntOrThrow(ATTR_FLAGS)
108         permissionFlags[name] = flags
109     }
110 
111     fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
112         val appIdDevicePermissionFlags = state.userStates[userId]!!.appIdDevicePermissionFlags
113         tag(TAG_APP_ID_DEVICE_PERMISSIONS) {
114             appIdDevicePermissionFlags.forEachIndexed { _, appId, devicePermissionFlags ->
115                 serializeAppId(appId, devicePermissionFlags)
116             }
117         }
118     }
119 
120     private fun BinaryXmlSerializer.serializeAppId(
121         appId: Int,
122         devicePermissionFlags: DevicePermissionFlags
123     ) {
124         tag(TAG_APP_ID) {
125             attributeInt(ATTR_ID, appId)
126             devicePermissionFlags.forEachIndexed { _, deviceId, permissionFlags ->
127                 serializeDevice(deviceId, permissionFlags)
128             }
129         }
130     }
131 
132     private fun BinaryXmlSerializer.serializeDevice(
133         deviceId: String,
134         permissionFlags: IndexedMap<String, Int>
135     ) {
136         tag(TAG_DEVICE) {
137             attributeInterned(ATTR_ID, deviceId)
138             permissionFlags.forEachIndexed { _, name, flags -> serializePermission(name, flags) }
139         }
140     }
141 
142     private fun BinaryXmlSerializer.serializePermission(name: String, flags: Int) {
143         tag(TAG_PERMISSION) {
144             attributeInterned(ATTR_NAME, name)
145             // Never serialize one-time permissions as granted.
146             val serializedFlags =
147                 if (flags.hasBits(PermissionFlags.ONE_TIME)) {
148                     flags andInv PermissionFlags.RUNTIME_GRANTED
149                 } else {
150                     flags
151                 }
152             attributeInt(ATTR_FLAGS, serializedFlags)
153         }
154     }
155 
156     companion object {
157         private val LOG_TAG = DevicePermissionPersistence::class.java.simpleName
158 
159         private const val TAG_APP_ID_DEVICE_PERMISSIONS = "app-id-device-permissions"
160         private const val TAG_APP_ID = "app-id"
161         private const val TAG_DEVICE = "device"
162         private const val TAG_PERMISSION = "permission"
163 
164         private const val ATTR_ID = "id"
165         private const val ATTR_NAME = "name"
166         private const val ATTR_FLAGS = "flags"
167     }
168 }
169