• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.support.v4.content;
18 
19 import android.content.Context;
20 import android.content.pm.PackageManager;
21 import android.os.Binder;
22 import android.os.Process;
23 import android.support.annotation.IntDef;
24 import android.support.annotation.NonNull;
25 import android.support.v4.app.AppOpsManagerCompat;
26 
27 import java.lang.annotation.Retention;
28 import java.lang.annotation.RetentionPolicy;
29 
30 /**
31  * This class provides permission check APIs that verify both the
32  * permission and the associated app op for this permission if
33  * such is defined.
34  * <p>
35  * In the new permission model permissions with protection level
36  * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M}
37  * and above the user may not grant such permissions or revoke
38  * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M}
39  * these permissions are always granted as such apps do not expect
40  * permission revocations and would crash. Therefore, when the
41  * user disables a permission for a legacy app in the UI the
42  * platform disables the APIs guarded by this permission making
43  * them a no-op which is doing nothing or returning an empty
44  * result or default error.
45  * </p>
46  * <p>
47  * It is important that when you perform an operation on behalf of
48  * another app you use these APIs to check for permissions as the
49  * app may be a legacy app that does not participate in the new
50  * permission model for which the user had disabled the "permission"
51  * which is achieved by disallowing the corresponding app op.
52  * </p>
53  */
54 public final class PermissionChecker {
55     /** Permission result: The permission is granted. */
56     public static final int PERMISSION_GRANTED =  PackageManager.PERMISSION_GRANTED;
57 
58     /** Permission result: The permission is denied. */
59     public static final int PERMISSION_DENIED =  PackageManager.PERMISSION_DENIED;
60 
61     /** Permission result: The permission is denied because the app op is not allowed. */
62     public static final int PERMISSION_DENIED_APP_OP =  PackageManager.PERMISSION_DENIED  - 1;
63 
64     @IntDef({PERMISSION_GRANTED,
65             PERMISSION_DENIED,
66             PERMISSION_DENIED_APP_OP})
67     @Retention(RetentionPolicy.SOURCE)
68     public @interface PermissionResult {}
69 
PermissionChecker()70     private PermissionChecker() {
71         /* do nothing */
72     }
73 
74     /**
75      * Checks whether a given package in a UID and PID has a given permission
76      * and whether the app op that corresponds to this permission is allowed.
77      *
78      * @param context Context for accessing resources.
79      * @param permission The permission to check.
80      * @param pid The process id for which to check.
81      * @param uid The uid for which to check.
82      * @param packageName The package name for which to check. If null the
83      *     the first package for the calling UID will be used.
84      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
85      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
86      */
checkPermission(@onNull Context context, @NonNull String permission, int pid, int uid, String packageName)87     public static int checkPermission(@NonNull Context context, @NonNull String permission,
88             int pid, int uid, String packageName) {
89         if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) {
90             return PERMISSION_DENIED;
91         }
92 
93         String op = AppOpsManagerCompat.permissionToOp(permission);
94         if (op == null) {
95             return PERMISSION_GRANTED;
96         }
97 
98         if (packageName == null) {
99             String[] packageNames = context.getPackageManager().getPackagesForUid(uid);
100             if (packageNames == null || packageNames.length <= 0) {
101                 return PERMISSION_DENIED;
102             }
103             packageName = packageNames[0];
104         }
105 
106         if (AppOpsManagerCompat.noteProxyOp(context, op, packageName)
107                 != AppOpsManagerCompat.MODE_ALLOWED) {
108             return PERMISSION_DENIED_APP_OP;
109         }
110 
111         return PERMISSION_GRANTED;
112     }
113 
114     /**
115      * Checks whether your app has a given permission and whether the app op
116      * that corresponds to this permission is allowed.
117      *
118      * @param context Context for accessing resources.
119      * @param permission The permission to check.
120      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
121      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
122      */
checkSelfPermission(@onNull Context context, @NonNull String permission)123     public static int checkSelfPermission(@NonNull Context context,
124             @NonNull String permission) {
125         return checkPermission(context, permission, android.os.Process.myPid(),
126                 android.os.Process.myUid(), context.getPackageName());
127     }
128 
129     /**
130      * Checks whether the IPC you are handling has a given permission and whether
131      * the app op that corresponds to this permission is allowed.
132      *
133      * @param context Context for accessing resources.
134      * @param permission The permission to check.
135      * @param packageName The package name making the IPC. If null the
136      *     the first package for the calling UID will be used.
137      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
138      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
139      */
checkCallingPermission(@onNull Context context, @NonNull String permission, String packageName)140     public static int checkCallingPermission(@NonNull Context context,
141             @NonNull String permission, String packageName) {
142         if (Binder.getCallingPid() == Process.myPid()) {
143             return PackageManager.PERMISSION_DENIED;
144         }
145         return checkPermission(context, permission, Binder.getCallingPid(),
146                 Binder.getCallingUid(), packageName);
147     }
148 
149     /**
150      * Checks whether the IPC you are handling or your app has a given permission
151      * and whether the app op that corresponds to this permission is allowed.
152      *
153      * @param context Context for accessing resources.
154      * @param permission The permission to check.
155      * @return The permission check result which is either {@link #PERMISSION_GRANTED}
156      *     or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}.
157      */
checkCallingOrSelfPermission(@onNull Context context, @NonNull String permission)158     public static int checkCallingOrSelfPermission(@NonNull Context context,
159             @NonNull String permission) {
160         String packageName = (Binder.getCallingPid() == Process.myPid())
161                 ? context.getPackageName() : null;
162         return checkPermission(context, permission, Binder.getCallingPid(),
163                 Binder.getCallingUid(), packageName);
164     }
165 }
166