• 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      * Enforce permission check on the context that should have one of given permission.
58      */
enforceAnyPermissionOf(@onNull Context context, @NonNull String... permissions)59     public static void enforceAnyPermissionOf(@NonNull Context context,
60             @NonNull String... permissions) {
61         if (!checkAnyPermissionOf(context, permissions)) {
62             throw new SecurityException("Requires one of the following permissions: "
63                     + String.join(", ", permissions) + ".");
64         }
65     }
66 
67     /**
68      * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a
69      * {@link SecurityException}.
70      *
71      * @param context {@link android.content.Context} for the process.
72      */
enforceNetworkStackPermission(final @NonNull Context context)73     public static void enforceNetworkStackPermission(final @NonNull Context context) {
74         enforceNetworkStackPermissionOr(context);
75     }
76 
77     /**
78      * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed
79      * for a particular process, throw a {@link SecurityException}.
80      *
81      * @param context {@link android.content.Context} for the process.
82      * @param otherPermissions The set of permissions that could be the candidate permissions , or
83      *                         empty string if none of other permissions needed.
84      */
enforceNetworkStackPermissionOr(final @NonNull Context context, final @NonNull String... otherPermissions)85     public static void enforceNetworkStackPermissionOr(final @NonNull Context context,
86             final @NonNull String... otherPermissions) {
87         ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
88         permissions.add(NETWORK_STACK);
89         permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
90         enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
91     }
92 
93     /**
94      * If the CONNECTIVITY_USE_RESTRICTED_NETWORKS is not allowed for a particular process, throw a
95      * {@link SecurityException}.
96      *
97      * @param context {@link android.content.Context} for the process.
98      * @param message A message to include in the exception if it is thrown.
99      */
enforceRestrictedNetworkPermission( final @NonNull Context context, final @Nullable String message)100     public static void enforceRestrictedNetworkPermission(
101             final @NonNull Context context, final @Nullable String message) {
102         context.enforceCallingOrSelfPermission(CONNECTIVITY_USE_RESTRICTED_NETWORKS, message);
103     }
104 
105     /**
106      * If the ACCESS_NETWORK_STATE is not allowed for a particular process, throw a
107      * {@link SecurityException}.
108      *
109      * @param context {@link android.content.Context} for the process.
110      * @param message A message to include in the exception if it is thrown.
111      */
enforceAccessNetworkStatePermission( final @NonNull Context context, final @Nullable String message)112     public static void enforceAccessNetworkStatePermission(
113             final @NonNull Context context, final @Nullable String message) {
114         context.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, message);
115     }
116 
117     /**
118      * Return true if the context has DUMP permission.
119      */
checkDumpPermission(Context context, String tag, PrintWriter pw)120     public static boolean checkDumpPermission(Context context, String tag, PrintWriter pw) {
121         if (context.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
122                 != PERMISSION_GRANTED) {
123             pw.println("Permission Denial: can't dump " + tag + " from from pid="
124                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
125                     + " due to missing android.permission.DUMP permission");
126             return false;
127         } else {
128             return true;
129         }
130     }
131 
132     /**
133      * Enforce that a given feature is available and if not, throw an
134      * {@link UnsupportedOperationException}.
135      *
136      * @param context {@link android.content.Context} for the process.
137      * @param feature the feature name to enforce.
138      * @param errorMessage an optional error message to include.
139      */
enforceSystemFeature(final @NonNull Context context, final @NonNull String feature, final @Nullable String errorMessage)140     public static void enforceSystemFeature(final @NonNull Context context,
141             final @NonNull String feature, final @Nullable String errorMessage) {
142         final boolean hasSystemFeature =
143                 context.getPackageManager().hasSystemFeature(feature);
144         if (!hasSystemFeature) {
145             if (null == errorMessage) {
146                 throw new UnsupportedOperationException();
147             }
148             throw new UnsupportedOperationException(errorMessage);
149         }
150     }
151 
152     /**
153      * Get the list of granted permissions for a package info.
154      *
155      * PackageInfo contains the list of requested permissions, and their state (whether they
156      * were granted or not, in particular) as a parallel array. Most users care only about
157      * granted permissions. This method returns the list of them.
158      *
159      * @param packageInfo the package info for the relevant uid.
160      * @return the list of granted permissions.
161      */
getGrantedPermissions(final @NonNull PackageInfo packageInfo)162     public static List<String> getGrantedPermissions(final @NonNull PackageInfo packageInfo) {
163         if (null == packageInfo.requestedPermissions) return Collections.emptyList();
164         final ArrayList<String> result = new ArrayList<>(packageInfo.requestedPermissions.length);
165         for (int i = 0; i < packageInfo.requestedPermissions.length; ++i) {
166             if (0 != (REQUESTED_PERMISSION_GRANTED & packageInfo.requestedPermissionsFlags[i])) {
167                 result.add(packageInfo.requestedPermissions[i]);
168             }
169         }
170         return result;
171     }
172 }
173