1 package com.android.nfc; 2 3 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 4 5 import android.annotation.Nullable; 6 import android.app.ActivityManager; 7 import android.app.admin.DevicePolicyManager; 8 import android.content.ComponentName; 9 import android.content.Context; 10 import android.content.pm.PackageManager; 11 import android.os.Binder; 12 import android.os.UserHandle; 13 import android.os.UserManager; 14 import android.util.Log; 15 import android.util.Pair; 16 17 import java.util.List; 18 19 public class NfcPermissions { 20 21 private static final String TAG = "NfcPermissions"; 22 23 /** 24 * NFC ADMIN permission - only for system apps 25 */ 26 private static final String ADMIN_PERM = android.Manifest.permission.WRITE_SECURE_SETTINGS; 27 private static final String ADMIN_PERM_ERROR = "WRITE_SECURE_SETTINGS permission required"; 28 29 /** 30 * Regular NFC permission 31 */ 32 static final String NFC_PERMISSION = android.Manifest.permission.NFC; 33 private static final String NFC_PERM_ERROR = "NFC permission required"; 34 35 /** 36 * NFC PREFERRED PAYMENT INFO permission 37 */ 38 static final String NFC_PREFERRED_PAYMENT_INFO_PERMISSION = 39 android.Manifest.permission.NFC_PREFERRED_PAYMENT_INFO; 40 private static final String NFC_PREFERRED_PAYMENT_INFO_PERM_ERROR = 41 "NFC_PREFERRED_PAYMENT_INFO permission required"; 42 43 /** 44 * NFC SET CONTROLLER ALWAYS ON permission 45 */ 46 static final String NFC_SET_CONTROLLER_ALWAYS_ON = 47 android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON; 48 private static final String NFC_SET_CONTROLLER_ALWAYS_ON_ERROR = 49 "NFC_SET_CONTROLLER_ALWAYS_ON permission required"; 50 51 private final Context mContext; 52 NfcPermissions(Context context)53 public NfcPermissions(Context context) { 54 mContext = context; 55 } 56 57 validateUserId(int userId)58 public static void validateUserId(int userId) { 59 if (userId != UserHandle.getUserHandleForUid(Binder.getCallingUid()).getIdentifier()) { 60 throw new SecurityException("userId passed in is not the calling user."); 61 } 62 } 63 64 /** 65 * Validate whether the profileId belongs to current user 66 */ validateProfileId(Context context, int profileId)67 public static void validateProfileId(Context context, int profileId) { 68 // Propagate the state change to all user profiles 69 UserManager um = context.createContextAsUser( 70 UserHandle.of(ActivityManager.getCurrentUser()), /*flags=*/0) 71 .getSystemService(UserManager.class); 72 List<UserHandle> luh = um.getEnabledProfiles(); 73 74 for (UserHandle uh : luh) { 75 if (profileId == uh.getIdentifier()) { 76 return; 77 } 78 } 79 80 throw new SecurityException("profileId passed in does not belong to the calling user."); 81 } 82 enforceAdminPermissions(Context context)83 public static void enforceAdminPermissions(Context context) { 84 context.enforceCallingOrSelfPermission(ADMIN_PERM, ADMIN_PERM_ERROR); 85 } 86 checkAdminPermissions(Context context)87 public static boolean checkAdminPermissions(Context context) { 88 return context.checkCallingOrSelfPermission(ADMIN_PERM) == PERMISSION_GRANTED; 89 } 90 enforceUserPermissions(Context context)91 public static void enforceUserPermissions(Context context) { 92 context.enforceCallingOrSelfPermission(NFC_PERMISSION, NFC_PERM_ERROR); 93 } 94 enforcePreferredPaymentInfoPermissions(Context context)95 public static void enforcePreferredPaymentInfoPermissions(Context context) { 96 context.enforceCallingOrSelfPermission(NFC_PREFERRED_PAYMENT_INFO_PERMISSION, 97 NFC_PREFERRED_PAYMENT_INFO_PERM_ERROR); 98 } 99 100 /** 101 * Permission check for android.Manifest.permission.NFC_SET_CONTROLLER_ALWAYS_ON 102 */ enforceSetControllerAlwaysOnPermissions(Context context)103 public static void enforceSetControllerAlwaysOnPermissions(Context context) { 104 context.enforceCallingOrSelfPermission(NFC_SET_CONTROLLER_ALWAYS_ON, 105 NFC_SET_CONTROLLER_ALWAYS_ON_ERROR); 106 } 107 108 /** 109 * Returns the DevicePolicyManager from context 110 */ retrieveDevicePolicyManagerFromContext(Context context)111 public static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) { 112 DevicePolicyManager devicePolicyManager = 113 context.getSystemService(DevicePolicyManager.class); 114 if (devicePolicyManager == null 115 && context.getPackageManager().hasSystemFeature( 116 PackageManager.FEATURE_DEVICE_ADMIN)) { 117 Log.w(TAG, "Error retrieving DPM service"); 118 } 119 return devicePolicyManager; 120 } 121 122 @Nullable getDeviceOwner()123 private Pair<UserHandle, ComponentName> getDeviceOwner() { 124 DevicePolicyManager devicePolicyManager = 125 retrieveDevicePolicyManagerFromContext(mContext); 126 if (devicePolicyManager == null) return null; 127 long ident = Binder.clearCallingIdentity(); 128 UserHandle deviceOwnerUser = null; 129 ComponentName deviceOwnerComponent = null; 130 try { 131 deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser(); 132 deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser(); 133 } finally { 134 Binder.restoreCallingIdentity(ident); 135 } 136 if (deviceOwnerUser == null || deviceOwnerComponent == null) return null; 137 138 if (deviceOwnerComponent.getPackageName() == null) { 139 // shouldn't happen 140 Log.wtf(TAG, "no package name on device owner component: " + deviceOwnerComponent); 141 return null; 142 } 143 return new Pair<>(deviceOwnerUser, deviceOwnerComponent); 144 } 145 146 /** 147 * Returns {@code true} if the calling {@code uid} and {@code packageName} is the device owner. 148 */ isDeviceOwner(int uid, @Nullable String packageName)149 public boolean isDeviceOwner(int uid, @Nullable String packageName) { 150 // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be 151 // safe. 152 if (packageName == null) { 153 Log.e(TAG, "isDeviceOwner: packageName is null, returning false"); 154 return false; 155 } 156 Pair<UserHandle, ComponentName> deviceOwner = getDeviceOwner(); 157 Log.v(TAG, "deviceOwner:" + deviceOwner); 158 159 // no device owner 160 if (deviceOwner == null) return false; 161 162 return deviceOwner.first.equals(UserHandle.getUserHandleForUid(uid)) 163 && deviceOwner.second.getPackageName().equals(packageName); 164 } 165 166 @Nullable createPackageContextAsUser(int uid)167 private Context createPackageContextAsUser(int uid) { 168 Context userContext = null; 169 try { 170 userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0, 171 UserHandle.getUserHandleForUid(uid)); 172 } catch (PackageManager.NameNotFoundException e) { 173 Log.e(TAG, "Unknown package name"); 174 return null; 175 } 176 if (userContext == null) { 177 Log.e(TAG, "Unable to retrieve user context for " + uid); 178 return null; 179 } 180 return userContext; 181 } 182 retrieveDevicePolicyManagerFromUserContext(int uid)183 private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) { 184 long ident = Binder.clearCallingIdentity(); 185 try { 186 Context userContext = createPackageContextAsUser(uid); 187 if (userContext == null) return null; 188 return retrieveDevicePolicyManagerFromContext(userContext); 189 } finally { 190 Binder.restoreCallingIdentity(ident); 191 } 192 } 193 194 /** 195 * Returns true if the |callingUid|/|callingPackage| is the profile owner. 196 */ isProfileOwner(int uid, @Nullable String packageName)197 public boolean isProfileOwner(int uid, @Nullable String packageName) { 198 // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be 199 // safe. 200 if (packageName == null) { 201 Log.e(TAG, "isProfileOwner: packageName is null, returning false"); 202 return false; 203 } 204 DevicePolicyManager devicePolicyManager = 205 retrieveDevicePolicyManagerFromUserContext(uid); 206 if (devicePolicyManager == null) return false; 207 return devicePolicyManager.isProfileOwnerApp(packageName); 208 } 209 } 210