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