1 /*
2  * Copyright (C) 2024 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.ecm
18 
19 import android.annotation.SuppressLint
20 import android.app.AppOpsManager
21 import android.app.ecm.EnhancedConfirmationManager
22 import android.content.Context
23 import android.content.pm.PackageManager
24 import android.os.UserHandle
25 import android.permission.flags.Flags
26 import android.util.Log
27 import com.android.modules.utils.build.SdkLevel
28 import com.android.permissioncontroller.PermissionControllerStatsLog
29 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_CANCELLED
30 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_LEARN_MORE
31 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_OK
32 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_SUPPRESSED
33 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_UNSPECIFIED
34 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_APPOP
35 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_OTHER
36 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_PERMISSION
37 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_ROLE
38 import com.android.permissioncontroller.PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_UNSPECIFIED
39 import com.android.permissioncontroller.permission.utils.Utils
40 
41 /**
42  * Provides ECM-related metrics logging for PermissionController.
43  *
44  * @hide
45  */
46 object EnhancedConfirmationStatsLogUtils {
47     private val LOG_TAG = EnhancedConfirmationStatsLogUtils::class.java.simpleName
48 
49     enum class DialogResult(val statsLogValue: Int) {
50         Unspecified(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_UNSPECIFIED),
51         Cancelled(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_CANCELLED),
52         LearnMore(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_LEARN_MORE),
53         Okay(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_OK),
54         Suppressed(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__RESULT__RESULT_SUPPRESSED)
55     }
56 
57     enum class SettingType(val statsLogValue: Int) {
58         Unspecified(
59             ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_UNSPECIFIED
60         ),
61         Appop(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_APPOP),
62         Permission(
63             ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_PERMISSION
64         ),
65         Role(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_ROLE),
66         Other(ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED__SETTING_TYPE__SETTING_TYPE_OTHER);
67 
68         companion object {
fromIdentifiernull69             fun fromIdentifier(settingIdentifier: String): SettingType =
70                 when {
71                     settingIdentifier.startsWith("android:") -> Appop
72                     settingIdentifier.startsWith("android.permission.") -> Permission
73                     settingIdentifier.startsWith("android.permission-group.") -> Permission
74                     settingIdentifier.startsWith("android.app.role.") -> Role
75                     else -> Other
76                 }
77         }
78     }
79 
logDialogResultReportednull80     fun logDialogResultReported(
81         uid: Int,
82         settingIdentifier: String,
83         firstShowForApp: Boolean,
84         dialogResult: DialogResult
85     ) {
86         if (!SdkLevel.isAtLeastV() || !Flags.enhancedConfirmationModeApisEnabled()) {
87             return
88         }
89         val settingType = SettingType.fromIdentifier(settingIdentifier)
90 
91         Log.v(
92             LOG_TAG,
93             "ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED: " +
94                 "uid='$uid', " +
95                 "settingIdentifier='$settingIdentifier', " +
96                 "firstShowForApp='$firstShowForApp', " +
97                 "settingType='$settingType', " +
98                 "result='${dialogResult.statsLogValue}'"
99         )
100 
101         PermissionControllerStatsLog.write(
102             PermissionControllerStatsLog.ENHANCED_CONFIRMATION_DIALOG_RESULT_REPORTED,
103             uid,
104             settingIdentifier,
105             firstShowForApp,
106             settingType.statsLogValue,
107             dialogResult.statsLogValue
108         )
109     }
110 
111     @SuppressLint("MissingPermission")
isPackageEcmRestrictednull112     fun isPackageEcmRestricted(context: Context, packageName: String, uid: Int): Boolean {
113         if (!SdkLevel.isAtLeastV() || !Flags.enhancedConfirmationModeApisEnabled()) {
114             return false
115         }
116         val userContext = Utils.getUserContext(context, UserHandle.getUserHandleForUid(uid))
117         val ecm = userContext.getSystemService(EnhancedConfirmationManager::class.java)
118         return try {
119             val arbitrarilyChosenRestrictedSetting = AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE
120             ecm?.isRestricted(packageName, arbitrarilyChosenRestrictedSetting) ?: false
121         } catch (e: PackageManager.NameNotFoundException) {
122             false
123         }
124     }
125 }
126