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 package com.android.permissioncontroller.permission.data
18 
19 import android.app.Application
20 import android.content.pm.PackageManager
21 import android.content.pm.PermissionInfo
22 import android.os.Build
23 import android.os.UserHandle
24 import com.android.permissioncontroller.PermissionControllerApplication
25 import com.android.permissioncontroller.permission.utils.PermissionMapping
26 import kotlinx.coroutines.Job
27 
28 /**
29  * LiveData with a map representing the runtime permissions a group requests and all of the
30  * installed, non-runtime, normal protection permissions. Key is the group name or
31  * NON_RUNTIME_NORMAL_PERMS, value is the requested runtime permissions in that group (or all
32  * installed non-runtime normal protection permissions, for NON_RUNTME_NORMAL_PERMS).
33  *
34  * @param app The current Application
35  * @param packageName The name of the package this LiveData will watch for mode changes for
36  * @param user The user for whom the packageInfo will be defined
37  */
38 class PackagePermissionsLiveData
39 private constructor(private val app: Application, packageName: String, user: UserHandle) :
40     SmartAsyncMediatorLiveData<Map<String, List<String>>?>() {
41 
42     private val packageInfoLiveData = LightPackageInfoLiveData[packageName, user]
43 
44     init {
<lambda>null45         addSource(packageInfoLiveData) {
46             if (packageInfoLiveData.isInitialized && packageInfoLiveData.value == null) {
47                 invalidateSingle(packageName to user)
48                 value = null
49                 return@addSource
50             }
51             update()
52         }
53     }
54 
loadDataAndPostValuenull55     override suspend fun loadDataAndPostValue(job: Job) {
56         val packageInfo = packageInfoLiveData.value ?: return
57         val permissionMap = mutableMapOf<String, MutableList<String>>()
58         for (permName in packageInfo.requestedPermissions) {
59             var groupName = PermissionMapping.getGroupOfPlatformPermission(permName)
60             if (groupName == null) {
61                 val permInfo =
62                     try {
63                         app.packageManager.getPermissionInfo(permName, 0)
64                     } catch (e: PackageManager.NameNotFoundException) {
65                         continue
66                     }
67 
68                 if (
69                     permInfo.flags and PermissionInfo.FLAG_INSTALLED == 0 ||
70                         permInfo.flags and PermissionInfo.FLAG_REMOVED != 0
71                 ) {
72                     continue
73                 }
74 
75                 if (
76                     packageInfo.isInstantApp &&
77                         permInfo.protectionFlags and PermissionInfo.PROTECTION_FLAG_INSTANT == 0
78                 ) {
79                     continue
80                 }
81 
82                 if (
83                     packageInfo.targetSdkVersion < Build.VERSION_CODES.M &&
84                         (permInfo.protectionFlags and
85                             PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0
86                 ) {
87                     continue
88                 }
89 
90                 // If this permission is a non-runtime, normal permission, add it to the
91                 // "non runtime" group
92                 if (permInfo.protection != PermissionInfo.PROTECTION_DANGEROUS) {
93                     if (permInfo.protection == PermissionInfo.PROTECTION_NORMAL) {
94                         val otherPermsList =
95                             permissionMap.getOrPut(NON_RUNTIME_NORMAL_PERMS) { mutableListOf() }
96                         otherPermsList.add(permInfo.name)
97                     }
98                     continue
99                 }
100 
101                 groupName = PermissionMapping.getGroupOfPermission(permInfo) ?: permName
102             }
103 
104             permissionMap.getOrPut(groupName) { mutableListOf() }.add(permName)
105         }
106 
107         postValue(permissionMap)
108     }
109 
110     /**
111      * Repository for PackagePermissionsLiveData objects
112      *
113      * <p> Key value is a string package name and userHandle, value is its corresponding LiveData.
114      */
115     companion object :
116         DataRepositoryForPackage<Pair<String, UserHandle>, PackagePermissionsLiveData>() {
newValuenull117         override fun newValue(key: Pair<String, UserHandle>): PackagePermissionsLiveData {
118             return PackagePermissionsLiveData(
119                 PermissionControllerApplication.get(),
120                 key.first,
121                 key.second
122             )
123         }
124 
125         const val NON_RUNTIME_NORMAL_PERMS = "nonRuntimeNormalPerms"
126     }
127 }
128