• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2021 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.net.module.util;
18 
19 import static android.Manifest.permission.ACCESS_NETWORK_STATE;
20 import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
21 import static android.Manifest.permission.NETWORK_STACK;
22 import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
23 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
24 import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.content.Context;
29 import android.content.pm.PackageInfo;
30 import android.os.Binder;
31 
32 import java.io.PrintWriter;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.List;
37 
38 /**
39  * Collection of permission utilities.
40  * @hide
41  */
42 public final class PermissionUtils {
43     /**
44      * Return true if the context has one of given permission.
45      */
checkAnyPermissionOf(@onNull Context context, @NonNull String... permissions)46     public static boolean checkAnyPermissionOf(@NonNull Context context,
47             @NonNull String... permissions) {
48         for (String permission : permissions) {
49             if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
50                 return true;
51             }
52         }
53         return false;
54     }
55 
56     /**
57      * Return true if the context has one of give permission that is allowed
58      * for a particular process and user ID running in the system.
59      */
checkAnyPermissionOf(@onNull Context context, int pid, int uid, @NonNull String... permissions)60     public static boolean checkAnyPermissionOf(@NonNull Context context,
61             int pid, int uid, @NonNull String... permissions) {
62         for (String permission : permissions) {
63             if (context.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) {
64                 return true;
65             }
66         }
67         return false;
68     }
69 
70     /**
71      * Enforce permission check on the context that should have one of given permission.
72      */
enforceAnyPermissionOf(@onNull Context context, @NonNull String... permissions)73     public static void enforceAnyPermissionOf(@NonNull Context context,
74             @NonNull String... permissions) {
75         if (!checkAnyPermissionOf(context, permissions)) {
76             throw new SecurityException("Requires one of the following permissions: "
77                     + String.join(", ", permissions) + ".");
78         }
79     }
80 
81     /**
82      * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a
83      * {@link SecurityException}.
84      *
85      * @param context {@link android.content.Context} for the process.
86      */
enforceNetworkStackPermission(final @NonNull Context context)87     public static void enforceNetworkStackPermission(final @NonNull Context context) {
88         enforceNetworkStackPermissionOr(context);
89     }
90 
91     /**
92      * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed
93      * for a particular process, throw a {@link SecurityException}.
94      *
95      * @param context {@link android.content.Context} for the process.
96      * @param otherPermissions The set of permissions that could be the candidate permissions , or
97      *                         empty string if none of other permissions needed.
98      */
enforceNetworkStackPermissionOr(final @NonNull Context context, final @NonNull String... otherPermissions)99     public static void enforceNetworkStackPermissionOr(final @NonNull Context context,
100             final @NonNull String... otherPermissions) {
101         ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
102         permissions.add(NETWORK_STACK);
103         permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
104         enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
105     }
106 
107     /**
108      * If the CONNECTIVITY_USE_RESTRICTED_NETWORKS is not allowed for a particular process, throw a
109      * {@link SecurityException}.
110      *
111      * @param context {@link android.content.Context} for the process.
112      * @param message A message to include in the exception if it is thrown.
113      */
enforceRestrictedNetworkPermission( final @NonNull Context context, final @Nullable String message)114     public static void enforceRestrictedNetworkPermission(
115             final @NonNull Context context, final @Nullable String message) {
116         context.enforceCallingOrSelfPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, message);
117     }
118 
119     /**
120      * If the ACCESS_NETWORK_STATE is not allowed for a particular process, throw a
121      * {@link SecurityException}.
122      *
123      * @param context {@link android.content.Context} for the process.
124      * @param message A message to include in the exception if it is thrown.
125      */
enforceAccessNetworkStatePermission( final @NonNull Context context, final @Nullable String message)126     public static void enforceAccessNetworkStatePermission(
127             final @NonNull Context context, final @Nullable String message) {
128         context.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, message);
129     }
130 
131     /**
132      * Return true if the context has DUMP permission.
133      */
checkDumpPermission(Context context, String tag, PrintWriter pw)134     public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
135         if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
136                 != PERMISSION_GRANTED) {
137             pw.println("Permission Denial: can't dump " + tag + " from from pid="
138                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
139                     + " due to missing android.permission.DUMP permission");
140             return false;
141         } else {
142             return true;
143         }
144     }
145 
146     /**
147      * Enforce that a given feature is available and if not, throw an
148      * {@link UnsupportedOperationException}.
149      *
150      * @param context {@link android.content.Context} for the process.
151      * @param feature the feature name to enforce.
152      * @param errorMessage an optional error message to include.
153      */
enforceSystemFeature(final @NonNull Context context, final @NonNull String feature, final @Nullable String errorMessage)154     public static void enforceSystemFeature(final @NonNull Context context,
155             final @NonNull String feature, final @Nullable String errorMessage) {
156         final boolean hasSystemFeature =
157                 context.getPackageManager().hasSystemFeature(feature);
158         if (!hasSystemFeature) {
159             if (null == errorMessage) {
160                 throw new UnsupportedOperationException();
161             }
162             throw new UnsupportedOperationException(errorMessage);
163         }
164     }
165 
166     /**
167      * Get the list of granted permissions for a package info.
168      *
169      * PackageInfo contains the list of requested permissions, and their state (whether they
170      * were granted or not, in particular) as a parallel array. Most users care only about
171      * granted permissions. This method returns the list of them.
172      *
173      * @param packageInfo the package info for the relevant uid.
174      * @return the list of granted permissions.
175      */
getGrantedPermissions(final @NonNull PackageInfo packageInfo)176     public static List<String> getGrantedPermissions(final @NonNull PackageInfo packageInfo) {
177         if (null == packageInfo.requestedPermissions) return Collections.emptyList();
178         final ArrayList<String> result = new ArrayList<>(packageInfo.requestedPermissions.length);
179         for (int i = 0; i < packageInfo.requestedPermissions.length; ++i) {
180             if (0 != (REQUESTED_PERMISSION_GRANTED & packageInfo.requestedPermissionsFlags[i])) {
181                 result.add(packageInfo.requestedPermissions[i]);
182             }
183         }
184         return result;
185     }
186 }
187