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.permissioncontroller.permission.utils.v34
18 
19 import android.content.Context
20 import android.content.pm.PackageManager
21 import android.content.pm.PackageManager.APP_METADATA_SOURCE_APK
22 import android.util.Log
23 import com.android.modules.utils.build.SdkLevel
24 import com.android.permission.safetylabel.DataCategory
25 import com.android.permission.safetylabel.DataType
26 import com.android.permission.safetylabel.DataTypeConstants
27 import com.android.permission.safetylabel.SafetyLabel
28 import com.android.permissioncontroller.permission.utils.PermissionMapping
29 
30 object SafetyLabelUtils {
31     private val LOG_TAG = SafetyLabelUtils::class.java.simpleName
32 
33     /*
34      * Get the sharing purposes for a SafetyLabel related to a specific permission group.
35      */
36     @JvmStatic
37     fun getSafetyLabelSharingPurposesForGroup(
38         safetyLabel: SafetyLabel,
39         groupName: String
40     ): Set<Int> {
41         val purposeSet = mutableSetOf<Int>()
42         val categoriesForPermission =
43             PermissionMapping.getDataCategoriesForPermissionGroup(groupName)
44         categoriesForPermission.forEach categoryLoop@{ category ->
45             val dataCategory: DataCategory? = safetyLabel.dataLabel.dataShared[category]
46             if (dataCategory == null) {
47                 // Continue to next
48                 return@categoryLoop
49             }
50             val typesForCategory = DataTypeConstants.getValidDataTypesForCategory(category)
51             typesForCategory.forEach typeLoop@{ type ->
52                 val dataType: DataType? = dataCategory.dataTypes[type]
53                 if (dataType == null) {
54                     // Continue to next
55                     return@typeLoop
56                 }
57                 if (dataType.purposeSet.isNotEmpty()) {
58                     purposeSet.addAll(dataType.purposeSet)
59                 }
60             }
61         }
62 
63         return purposeSet
64     }
65 
66     /**
67      * Returns the {@code TRUE} if [AppMetadataSource] for the given package is
68      * supported for permission rationale, as well as for U- where getAppMetadataSource isn't
69      * available.
70      */
71     fun isAppMetadataSourceSupported(userContext: Context, packageName: String): Boolean {
72         if (!SdkLevel.isAtLeastV() || !android.content.pm.Flags.aslInApkAppMetadataSource()) {
73             // PackageManager.getAppMetadataSource() is not available and ASL in APK is ignored in
74             // U and below. We can assume it came from oem/pre-install or installer source (app
75             // store). Treat this as AppMetadataSource allowed.
76             return true
77         }
78 
79         return try {
80             userContext.packageManager.getAppMetadataSource(packageName) != APP_METADATA_SOURCE_APK
81         } catch (e: PackageManager.NameNotFoundException) {
82             Log.w(LOG_TAG, "AppMetadataSource for $packageName not found")
83             false
84         }
85     }
86 }
87