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