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.server.location; 18 19 import static android.Manifest.permission.ACCESS_COARSE_LOCATION; 20 import static android.Manifest.permission.ACCESS_FINE_LOCATION; 21 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 22 23 import android.annotation.IntDef; 24 import android.app.AppOpsManager; 25 import android.content.Context; 26 import android.os.Binder; 27 28 import java.lang.annotation.Retention; 29 import java.lang.annotation.RetentionPolicy; 30 31 /** Utility class for dealing with location permissions. */ 32 public final class LocationPermissions { 33 34 /** 35 * Indicates no location permissions are present, or no location permission are required. 36 */ 37 public static final int PERMISSION_NONE = 0; 38 39 /** 40 * Indicates the coarse location permission is present, or either the coarse or fine permissions 41 * are required. 42 */ 43 public static final int PERMISSION_COARSE = 1; 44 45 /** 46 * Indicates the fine location permission is present, or the fine location permission is 47 * required. 48 */ 49 public static final int PERMISSION_FINE = 2; 50 51 @IntDef({PERMISSION_NONE, PERMISSION_COARSE, PERMISSION_FINE}) 52 @Retention(RetentionPolicy.SOURCE) 53 public @interface PermissionLevel {} 54 55 /** 56 * Converts the given permission level to the corresponding permission. 57 */ asPermission(@ermissionLevel int permissionLevel)58 public static String asPermission(@PermissionLevel int permissionLevel) { 59 switch (permissionLevel) { 60 case PERMISSION_COARSE: 61 return ACCESS_COARSE_LOCATION; 62 case PERMISSION_FINE: 63 return ACCESS_FINE_LOCATION; 64 default: 65 throw new IllegalArgumentException(); 66 } 67 } 68 69 /** 70 * Converts the given permission level to the corresponding appop. 71 */ asAppOp(@ermissionLevel int permissionLevel)72 public static int asAppOp(@PermissionLevel int permissionLevel) { 73 switch (permissionLevel) { 74 case PERMISSION_COARSE: 75 return AppOpsManager.OP_COARSE_LOCATION; 76 case PERMISSION_FINE: 77 return AppOpsManager.OP_FINE_LOCATION; 78 default: 79 throw new IllegalArgumentException(); 80 } 81 } 82 83 /** 84 * Throws a security exception if the caller does not hold the required location permissions. 85 */ enforceCallingOrSelfLocationPermission(Context context, @PermissionLevel int requiredPermissionLevel)86 public static void enforceCallingOrSelfLocationPermission(Context context, 87 @PermissionLevel int requiredPermissionLevel) { 88 enforceLocationPermission(Binder.getCallingUid(), 89 getPermissionLevel(context, Binder.getCallingUid(), Binder.getCallingPid()), 90 requiredPermissionLevel); 91 } 92 93 /** 94 * Throws a security exception if the given uid/pid does not hold the required location 95 * permissions. 96 */ enforceLocationPermission(Context context, int uid, int pid, @PermissionLevel int requiredPermissionLevel)97 public static void enforceLocationPermission(Context context, int uid, int pid, 98 @PermissionLevel int requiredPermissionLevel) { 99 enforceLocationPermission(uid, 100 getPermissionLevel(context, uid, pid), 101 requiredPermissionLevel); 102 } 103 104 /** 105 * Throws a security exception if the given permission level does not meet the required location 106 * permission level. 107 */ enforceLocationPermission(int uid, @PermissionLevel int permissionLevel, @PermissionLevel int requiredPermissionLevel)108 public static void enforceLocationPermission(int uid, @PermissionLevel int permissionLevel, 109 @PermissionLevel int requiredPermissionLevel) { 110 if (checkLocationPermission(permissionLevel, requiredPermissionLevel)) { 111 return; 112 } 113 114 if (requiredPermissionLevel == PERMISSION_COARSE) { 115 throw new SecurityException("uid " + uid + " does not have " + ACCESS_COARSE_LOCATION 116 + " or " + ACCESS_FINE_LOCATION + "."); 117 } else if (requiredPermissionLevel == PERMISSION_FINE) { 118 throw new SecurityException("uid " + uid + " does not have " + ACCESS_FINE_LOCATION 119 + "."); 120 } 121 } 122 123 /** 124 * Returns false if the caller does not hold the required location permissions. 125 */ checkCallingOrSelfLocationPermission(Context context, @PermissionLevel int requiredPermissionLevel)126 public static boolean checkCallingOrSelfLocationPermission(Context context, 127 @PermissionLevel int requiredPermissionLevel) { 128 return checkLocationPermission( 129 getCallingOrSelfPermissionLevel(context), 130 requiredPermissionLevel); 131 } 132 133 /** 134 * Returns false if the given uid/pid does not hold the required location permissions. 135 */ checkLocationPermission(Context context, int uid, int pid, @PermissionLevel int requiredPermissionLevel)136 public static boolean checkLocationPermission(Context context, int uid, int pid, 137 @PermissionLevel int requiredPermissionLevel) { 138 return checkLocationPermission( 139 getPermissionLevel(context, uid, pid), 140 requiredPermissionLevel); 141 } 142 143 /** 144 * Returns false if the given permission level does not meet the required location permission 145 * level. 146 */ checkLocationPermission(@ermissionLevel int permissionLevel, @PermissionLevel int requiredPermissionLevel)147 public static boolean checkLocationPermission(@PermissionLevel int permissionLevel, 148 @PermissionLevel int requiredPermissionLevel) { 149 return permissionLevel >= requiredPermissionLevel; 150 } 151 152 /** 153 * Returns the permission level of the caller. 154 */ 155 @PermissionLevel getCallingOrSelfPermissionLevel(Context context)156 public static int getCallingOrSelfPermissionLevel(Context context) { 157 return getPermissionLevel(context, Binder.getCallingUid(), Binder.getCallingPid()); 158 } 159 160 /** 161 * Returns the permission level of the given uid/pid. 162 */ 163 @PermissionLevel getPermissionLevel(Context context, int uid, int pid)164 public static int getPermissionLevel(Context context, int uid, int pid) { 165 if (context.checkPermission(ACCESS_FINE_LOCATION, pid, uid) == PERMISSION_GRANTED) { 166 return PERMISSION_FINE; 167 } 168 if (context.checkPermission(ACCESS_COARSE_LOCATION, pid, uid) == PERMISSION_GRANTED) { 169 return PERMISSION_COARSE; 170 } 171 172 return PERMISSION_NONE; 173 } 174 LocationPermissions()175 private LocationPermissions() {} 176 } 177