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