1 /*
2  * Copyright (C) 2019 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 @file:JvmName("UserSensitiveFlagsUtils")
18 
19 package com.android.permissioncontroller.permission.utils
20 
21 import android.content.pm.PackageManager
22 import android.os.UserHandle
23 import android.util.Log
24 import com.android.permissioncontroller.PermissionControllerApplication
25 import com.android.permissioncontroller.permission.data.UserSensitivityLiveData
26 import com.android.permissioncontroller.permission.model.livedatatypes.UidSensitivityState
27 import com.android.permissioncontroller.permission.utils.Utils.FLAGS_ALWAYS_USER_SENSITIVE
28 import java.lang.IllegalStateException
29 import kotlinx.coroutines.GlobalScope
30 import kotlinx.coroutines.launch
31 
32 private const val LOG_TAG = "UserSensitiveFlagsUtils"
33 
34 /**
35  * Update the [PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED] and
36  * [PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED] for all apps of this user.
37  *
38  * @param user The user for whom packages will be updated
39  * @param callback A callback which will be executed when finished
40  * @see UserSensitivityLiveData.loadDataAndPostValue
41  */
updateUserSensitiveForUsernull42 fun updateUserSensitiveForUser(user: UserHandle, callback: Runnable) {
43     GlobalScope.launch(IPC) {
44         // a map of <uid, uid state>
45         val uidUserSensitivity = UserSensitivityLiveData[user].getInitializedValue()
46         if (uidUserSensitivity == null) {
47             callback.run()
48             throw IllegalStateException(
49                 "All uids sensitivity liveData should not be null if initialized"
50             )
51         }
52         updateUserSensitiveForUidsInternal(uidUserSensitivity, user, callback)
53     }
54 }
55 
updateUserSensitiveForUidsInternalnull56 private fun updateUserSensitiveForUidsInternal(
57     uidsUserSensitivity: Map<Int, UidSensitivityState>,
58     user: UserHandle,
59     callback: Runnable?
60 ) {
61     val userContext = Utils.getUserContext(PermissionControllerApplication.get(), user)
62     val pm = userContext.packageManager
63 
64     for ((uid, uidState) in uidsUserSensitivity) {
65         for (pkg in uidState.packages) {
66             for (perm in pkg.requestedPermissions) {
67                 var flags = uidState.permStates[perm] ?: continue
68 
69                 try {
70                     val oldFlags =
71                         pm.getPermissionFlags(perm, pkg.packageName, user) and
72                             FLAGS_ALWAYS_USER_SENSITIVE
73                     if (flags != oldFlags) {
74                         pm.updatePermissionFlags(
75                             perm,
76                             pkg.packageName,
77                             FLAGS_ALWAYS_USER_SENSITIVE,
78                             flags,
79                             user
80                         )
81                     }
82                 } catch (e: IllegalArgumentException) {
83                     if (e.message?.startsWith("Unknown permission: ") == false) {
84                         Log.e(
85                             LOG_TAG,
86                             "Unexpected exception while updating flags for " +
87                                 "${pkg.packageName} (uid $uid) permission $perm",
88                             e
89                         )
90                     } else {
91                         // Unknown permission - ignore
92                     }
93                 }
94             }
95         }
96     }
97     callback?.run()
98 }
99 
100 /**
101  * [updateUserSensitiveForUser] for a single [uid]
102  *
103  * @param uid The uid to be updated
104  * @param callback A callback which will be executed when finished
105  */
106 @JvmOverloads
updateUserSensitiveForUidnull107 fun updateUserSensitiveForUid(uid: Int, callback: Runnable? = null) {
108     GlobalScope.launch(IPC) {
109         val uidSensitivityState = UserSensitivityLiveData[uid].getInitializedValue()
110         if (uidSensitivityState != null) {
111             updateUserSensitiveForUidsInternal(
112                 uidSensitivityState,
113                 UserHandle.getUserHandleForUid(uid),
114                 callback
115             )
116         } else {
117             Log.e(LOG_TAG, "No packages associated with uid $uid, not updating flags")
118             callback?.run()
119         }
120     }
121 }
122