• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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