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.appop
18 
19 import android.util.Log
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.UserState
24 import com.android.server.permission.access.collection.* // ktlint-disable no-wildcard-imports
25 import com.android.server.permission.access.util.attributeInt
26 import com.android.server.permission.access.util.forEachTag
27 import com.android.server.permission.access.util.getAttributeIntOrThrow
28 import com.android.server.permission.access.util.tag
29 import com.android.server.permission.access.util.tagName
30 
31 class UidAppOpPersistence : BaseAppOpPersistence() {
32     override fun BinaryXmlPullParser.parseUserState(state: AccessState, userId: Int) {
33         when (tagName) {
34             TAG_UID_APP_OPS -> parseUidAppOps(state, userId)
35             else -> {}
36         }
37     }
38 
39     private fun BinaryXmlPullParser.parseUidAppOps(state: AccessState, userId: Int) {
40         val userState = state.userStates[userId]
41         forEachTag {
42             when (tagName) {
43                 TAG_APP_ID -> parseAppId(userState)
44                 else -> Log.w(LOG_TAG, "Ignoring unknown tag $name when parsing app-op state")
45             }
46         }
47         userState.uidAppOpModes.retainAllIndexed { _, appId, _ ->
48             val hasAppId = appId in state.systemState.appIds
49             if (!hasAppId) {
50                 Log.w(LOG_TAG, "Dropping unknown app ID $appId when parsing app-op state")
51             }
52             hasAppId
53         }
54     }
55 
56     private fun BinaryXmlPullParser.parseAppId(userState: UserState) {
57         val appId = getAttributeIntOrThrow(ATTR_ID)
58         val appOpModes = IndexedMap<String, Int>()
59         userState.uidAppOpModes[appId] = appOpModes
60         parseAppOps(appOpModes)
61     }
62 
63     override fun BinaryXmlSerializer.serializeUserState(state: AccessState, userId: Int) {
64         serializeUidAppOps(state.userStates[userId])
65     }
66 
67     private fun BinaryXmlSerializer.serializeUidAppOps(userState: UserState) {
68         tag(TAG_UID_APP_OPS) {
69             userState.uidAppOpModes.forEachIndexed { _, appId, appOpModes ->
70                 serializeAppId(appId, appOpModes)
71             }
72         }
73     }
74 
75     private fun BinaryXmlSerializer.serializeAppId(
76         appId: Int,
77         appOpModes: IndexedMap<String, Int>
78     ) {
79         tag(TAG_APP_ID) {
80             attributeInt(ATTR_ID, appId)
81             serializeAppOps(appOpModes)
82         }
83     }
84 
85     companion object {
86         private val LOG_TAG = UidAppOpPersistence::class.java.simpleName
87 
88         private const val TAG_APP_ID = "app-id"
89         private const val TAG_UID_APP_OPS = "uid-app-ops"
90 
91         private const val ATTR_ID = "id"
92     }
93 }
94