1 /* 2 * Copyright (C) 2020 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.role.model; 18 19 import android.app.AppOpsManager; 20 import android.content.Context; 21 import android.content.pm.PackageInfo; 22 import android.content.pm.PackageManager; 23 import android.os.Build; 24 25 import androidx.annotation.NonNull; 26 27 import com.android.permissioncontroller.permission.utils.ArrayUtils; 28 import com.android.permissioncontroller.role.utils.PackageUtils; 29 30 /** 31 * App op permissions to be granted or revoke by a {@link Role}. 32 */ 33 public class AppOpPermissions { 34 AppOpPermissions()35 private AppOpPermissions() {} 36 37 /** 38 * Grant the app op of an app op permission to an application. 39 * 40 * @param packageName the package name of the application 41 * @param appOpPermission the name of the app op permission 42 * @param overrideNonDefaultMode whether to override the app opp mode if it isn't in the default 43 * mode 44 * @param context the {@code Context} to retrieve system services 45 * 46 * @return whether any app op mode has changed 47 */ grant(@onNull String packageName, @NonNull String appOpPermission, boolean overrideNonDefaultMode, @NonNull Context context)48 public static boolean grant(@NonNull String packageName, @NonNull String appOpPermission, 49 boolean overrideNonDefaultMode, @NonNull Context context) { 50 PackageInfo packageInfo = PackageUtils.getPackageInfo(packageName, 51 PackageManager.GET_PERMISSIONS, context); 52 if (packageInfo == null) { 53 return false; 54 } 55 if (!ArrayUtils.contains(packageInfo.requestedPermissions, appOpPermission)) { 56 return false; 57 } 58 String appOp = AppOpsManager.permissionToOp(appOpPermission); 59 if (!overrideNonDefaultMode) { 60 Integer currentMode = Permissions.getAppOpMode(packageName, appOp, context); 61 if (currentMode != null && currentMode != Permissions.getDefaultAppOpMode(appOp)) { 62 return false; 63 } 64 } 65 boolean changed = setAppOpMode(packageName, appOp, AppOpsManager.MODE_ALLOWED, context); 66 if (changed) { 67 Permissions.setPermissionGrantedByRole(packageName, appOpPermission, true, context); 68 } 69 return changed; 70 } 71 72 /** 73 * Revoke the app op of an app op permission from an application. 74 * 75 * @param packageName the package name of the application 76 * @param appOpPermission the name of the app op permission 77 * @param context the {@code Context} to retrieve system services 78 * 79 * @return whether any app op mode has changed 80 */ revoke(@onNull String packageName, @NonNull String appOpPermission, @NonNull Context context)81 public static boolean revoke(@NonNull String packageName, @NonNull String appOpPermission, 82 @NonNull Context context) { 83 if (!Permissions.isPermissionGrantedByRole(packageName, appOpPermission, context)) { 84 return false; 85 } 86 String appOp = AppOpsManager.permissionToOp(appOpPermission); 87 int defaultMode = Permissions.getDefaultAppOpMode(appOp); 88 boolean changed = setAppOpMode(packageName, appOp, defaultMode, context); 89 Permissions.setPermissionGrantedByRole(packageName, appOpPermission, false, context); 90 return changed; 91 } 92 setAppOpMode(@onNull String packageName, @NonNull String appOp, int mode, @NonNull Context context)93 private static boolean setAppOpMode(@NonNull String packageName, @NonNull String appOp, 94 int mode, @NonNull Context context) { 95 switch (appOp) { 96 case AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS: 97 case AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW: 98 case AppOpsManager.OPSTR_WRITE_SETTINGS: 99 case AppOpsManager.OPSTR_REQUEST_INSTALL_PACKAGES: 100 case AppOpsManager.OPSTR_START_FOREGROUND: 101 // This isn't an API but we are deprecating it soon anyway. 102 //case AppOpsManager.OPSTR_SMS_FINANCIAL_TRANSACTIONS: 103 case AppOpsManager.OPSTR_MANAGE_IPSEC_TUNNELS: 104 case AppOpsManager.OPSTR_INSTANT_APP_START_FOREGROUND: 105 case AppOpsManager.OPSTR_LOADER_USAGE_STATS: 106 return Permissions.setAppOpPackageMode(packageName, appOp, mode, context); 107 case AppOpsManager.OPSTR_INTERACT_ACROSS_PROFILES: 108 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { 109 // We fixed OP_INTERACT_ACROSS_PROFILES to use UID mode on S and backported it 110 // to R, but still, we might have an out-of-date platform or an upgraded 111 // platform with old state. 112 boolean changed = false; 113 changed |= Permissions.setAppOpUidMode(packageName, appOp, mode, context); 114 changed |= Permissions.setAppOpPackageMode(packageName, appOp, 115 Permissions.getDefaultAppOpMode(appOp), context); 116 return changed; 117 } else { 118 return Permissions.setAppOpPackageMode(packageName, appOp, mode, context); 119 } 120 default: 121 return Permissions.setAppOpUidMode(packageName, appOp, mode, context); 122 } 123 } 124 } 125