1 /* 2 * Copyright (C) 2018 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 android.permission; 18 19 import android.annotation.IntDef; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.app.AppOpsManager; 23 import android.content.AttributionSourceState; 24 import android.content.Context; 25 import android.content.pm.PackageManager; 26 import android.os.RemoteException; 27 import android.os.ServiceManager; 28 29 import java.lang.annotation.Retention; 30 import java.lang.annotation.RetentionPolicy; 31 import java.util.Objects; 32 33 /** 34 * Manager for checking runtime and app op permissions. This is a temporary 35 * class and we may fold its function in the PermissionManager once the 36 * permission re-architecture starts falling into place. The main benefit 37 * of this class is to allow context level caching. 38 * 39 * @hide 40 */ 41 public class PermissionCheckerManager { 42 43 /** 44 * The permission is granted. 45 */ 46 public static final int PERMISSION_GRANTED = IPermissionChecker.PERMISSION_GRANTED; 47 48 /** 49 * The permission is denied. Applicable only to runtime and app op permissions. 50 * 51 * <p>Returned when: 52 * <ul> 53 * <li>the runtime permission is granted, but the corresponding app op is denied 54 * for runtime permissions.</li> 55 * <li>the app ops is ignored for app op permissions.</li> 56 * </ul> 57 */ 58 public static final int PERMISSION_SOFT_DENIED = IPermissionChecker.PERMISSION_SOFT_DENIED; 59 60 /** 61 * The permission is denied. 62 * 63 * <p>Returned when: 64 * <ul> 65 * <li>the permission is denied for non app op permissions.</li> 66 * <li>the app op is denied or app op is {@link AppOpsManager#MODE_DEFAULT} 67 * and permission is denied.</li> 68 * </ul> 69 */ 70 public static final int PERMISSION_HARD_DENIED = IPermissionChecker.PERMISSION_HARD_DENIED; 71 72 /** @hide */ 73 @IntDef({PERMISSION_GRANTED, 74 PERMISSION_SOFT_DENIED, 75 PERMISSION_HARD_DENIED}) 76 @Retention(RetentionPolicy.SOURCE) 77 public @interface PermissionResult {} 78 79 @NonNull 80 private final Context mContext; 81 82 @NonNull 83 private final IPermissionChecker mService; 84 85 @NonNull 86 private final PackageManager mPackageManager; 87 PermissionCheckerManager(@onNull Context context)88 public PermissionCheckerManager(@NonNull Context context) 89 throws ServiceManager.ServiceNotFoundException { 90 mContext = context; 91 mService = IPermissionChecker.Stub.asInterface(ServiceManager.getServiceOrThrow( 92 Context.PERMISSION_CHECKER_SERVICE)); 93 mPackageManager = context.getPackageManager(); 94 } 95 96 /** 97 * Checks a permission by validating the entire attribution source chain. If the 98 * permission is associated with an app op the op is also noted/started for the 99 * entire attribution chain. 100 * 101 * @param permission The permission 102 * @param attributionSource The attribution chain to check. 103 * @param message Message associated with the permission if permission has an app op 104 * @param forDataDelivery Whether the check is for delivering data if permission has an app op 105 * @param startDataDelivery Whether to start data delivery (start op) if permission has 106 * an app op 107 * @param fromDatasource Whether the check is by a datasource (skip checks for the 108 * first attribution source in the chain as this is the datasource) 109 * @param attributedOp Alternative app op to attribute 110 * @return The permission check result. 111 */ 112 @PermissionResult checkPermission(@onNull String permission, @NonNull AttributionSourceState attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource, int attributedOp)113 public int checkPermission(@NonNull String permission, 114 @NonNull AttributionSourceState attributionSource, @Nullable String message, 115 boolean forDataDelivery, boolean startDataDelivery, boolean fromDatasource, 116 int attributedOp) { 117 Objects.requireNonNull(permission); 118 Objects.requireNonNull(attributionSource); 119 // Fast path for non-runtime, non-op permissions where the attribution chain has 120 // length one. This is the majority of the cases and we want these to be fast by 121 // hitting the local in process permission cache. 122 if (AppOpsManager.permissionToOpCode(permission) == AppOpsManager.OP_NONE) { 123 if (fromDatasource) { 124 if (attributionSource.next != null && attributionSource.next.length > 0) { 125 return mContext.checkPermission(permission, attributionSource.next[0].pid, 126 attributionSource.next[0].uid) == PackageManager.PERMISSION_GRANTED 127 ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; 128 } 129 } else { 130 return (mContext.checkPermission(permission, attributionSource.pid, 131 attributionSource.uid) == PackageManager.PERMISSION_GRANTED) 132 ? PERMISSION_GRANTED : PERMISSION_HARD_DENIED; 133 } 134 } 135 try { 136 return mService.checkPermission(permission, attributionSource, message, forDataDelivery, 137 startDataDelivery, fromDatasource, attributedOp); 138 } catch (RemoteException e) { 139 e.rethrowFromSystemServer(); 140 } 141 return PERMISSION_HARD_DENIED; 142 } 143 144 /** 145 * Finishes an app op by validating the entire attribution source chain. 146 * 147 * @param op The op to finish. 148 * @param attributionSource The attribution chain to finish. 149 * @param fromDatasource Whether the finish is by a datasource (skip finish for the 150 * first attribution source in the chain as this is the datasource) 151 */ finishDataDelivery(int op, @NonNull AttributionSourceState attributionSource, boolean fromDatasource)152 public void finishDataDelivery(int op, @NonNull AttributionSourceState attributionSource, 153 boolean fromDatasource) { 154 Objects.requireNonNull(attributionSource); 155 try { 156 mService.finishDataDelivery(op, attributionSource, fromDatasource); 157 } catch (RemoteException e) { 158 e.rethrowFromSystemServer(); 159 } 160 } 161 162 /** 163 * Checks an app op by validating the entire attribution source chain. The op is 164 * also noted/started for the entire attribution chain. 165 * 166 * @param op The op to check. 167 * @param attributionSource The attribution chain to check. 168 * @param message Message associated with the permission if permission has an app op 169 * @param forDataDelivery Whether the check is for delivering data if permission has an app op 170 * @param startDataDelivery Whether to start data delivery (start op) if permission has 171 * an app op 172 * @return The op check result. 173 */ 174 @PermissionResult checkOp(int op, @NonNull AttributionSourceState attributionSource, @Nullable String message, boolean forDataDelivery, boolean startDataDelivery)175 public int checkOp(int op, @NonNull AttributionSourceState attributionSource, 176 @Nullable String message, boolean forDataDelivery, boolean startDataDelivery) { 177 Objects.requireNonNull(attributionSource); 178 try { 179 return mService.checkOp(op, attributionSource, message, forDataDelivery, 180 startDataDelivery); 181 } catch (RemoteException e) { 182 e.rethrowFromSystemServer(); 183 } 184 return PERMISSION_HARD_DENIED; 185 } 186 } 187