1 /*
2  * Copyright (C) 2016 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.server.wifi.util;
18 
19 import android.Manifest;
20 import android.annotation.Nullable;
21 import android.app.AppOpsManager;
22 import android.app.admin.DevicePolicyManager;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.pm.PackageManager;
26 import android.location.LocationManager;
27 import android.net.NetworkStack;
28 import android.os.Binder;
29 import android.os.Build;
30 import android.os.UserHandle;
31 import android.os.UserManager;
32 import android.provider.Settings;
33 import android.util.Log;
34 
35 import com.android.internal.annotations.GuardedBy;
36 import com.android.server.wifi.FrameworkFacade;
37 import com.android.server.wifi.WifiInjector;
38 import com.android.server.wifi.WifiLog;
39 
40 /**
41  * A wifi permissions utility assessing permissions
42  * for getting scan results by a package.
43  */
44 public class WifiPermissionsUtil {
45     private static final String TAG = "WifiPermissionsUtil";
46     private final WifiPermissionsWrapper mWifiPermissionsWrapper;
47     private final Context mContext;
48     private final FrameworkFacade mFrameworkFacade;
49     private final AppOpsManager mAppOps;
50     private final UserManager mUserManager;
51     private final Object mLock = new Object();
52     @GuardedBy("mLock")
53     private LocationManager mLocationManager;
54     private WifiLog mLog;
55 
WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper, Context context, UserManager userManager, WifiInjector wifiInjector)56     public WifiPermissionsUtil(WifiPermissionsWrapper wifiPermissionsWrapper,
57             Context context, UserManager userManager, WifiInjector wifiInjector) {
58         mWifiPermissionsWrapper = wifiPermissionsWrapper;
59         mContext = context;
60         mFrameworkFacade = wifiInjector.getFrameworkFacade();
61         mUserManager = userManager;
62         mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
63         mLog = wifiInjector.makeLog(TAG);
64     }
65 
66     /**
67      * Checks if the app has the permission to override Wi-Fi network configuration or not.
68      *
69      * @param uid uid of the app.
70      * @return true if the app does have the permission, false otherwise.
71      */
checkConfigOverridePermission(int uid)72     public boolean checkConfigOverridePermission(int uid) {
73         int permission = mWifiPermissionsWrapper.getOverrideWifiConfigPermission(uid);
74         return permission == PackageManager.PERMISSION_GRANTED;
75     }
76 
77     /**
78      * Check and enforce Coarse or Fine Location permission (depending on target SDK).
79      *
80      * @param pkgName PackageName of the application requesting access
81      * @param featureId The feature in the package
82      * @param uid The uid of the package
83      */
enforceLocationPermission(String pkgName, @Nullable String featureId, int uid)84     public void enforceLocationPermission(String pkgName, @Nullable String featureId, int uid) {
85         if (!checkCallersLocationPermission(pkgName, featureId,
86                 uid, /* coarseForTargetSdkLessThanQ */ true, null)) {
87             throw new SecurityException(
88                     "UID " + uid + " does not have Coarse/Fine Location permission");
89         }
90     }
91 
92     /**
93      * Checks whether than the target SDK of the package is less than the specified version code.
94      */
isTargetSdkLessThan(String packageName, int versionCode, int callingUid)95     public boolean isTargetSdkLessThan(String packageName, int versionCode, int callingUid) {
96         long ident = Binder.clearCallingIdentity();
97         try {
98             if (mContext.getPackageManager().getApplicationInfoAsUser(
99                     packageName, 0,
100                     UserHandle.getUserHandleForUid(callingUid)).targetSdkVersion
101                     < versionCode) {
102                 return true;
103             }
104         } catch (PackageManager.NameNotFoundException e) {
105             // In case of exception, assume unknown app (more strict checking)
106             // Note: This case will never happen since checkPackage is
107             // called to verify validity before checking App's version.
108         } finally {
109             Binder.restoreCallingIdentity(ident);
110         }
111         return false;
112     }
113 
114     /**
115      * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION or
116      * android.Manifest.permission.ACCESS_FINE_LOCATION (depending on config/targetSDK leve)
117      * and a corresponding app op is allowed for this package and uid.
118      *
119      * @param pkgName PackageName of the application requesting access
120      * @param featureId The feature in the package
121      * @param uid The uid of the package
122      * @param coarseForTargetSdkLessThanQ If true and the targetSDK < Q then will check for COARSE
123      *                                    else (false or targetSDK >= Q) then will check for FINE
124      * @param message A message describing why the permission was checked. Only needed if this is
125      *                not inside of a two-way binder call from the data receiver
126      */
checkCallersLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message)127     public boolean checkCallersLocationPermission(String pkgName, @Nullable String featureId,
128             int uid, boolean coarseForTargetSdkLessThanQ, @Nullable String message) {
129         boolean isTargetSdkLessThanQ = isTargetSdkLessThan(pkgName, Build.VERSION_CODES.Q, uid);
130 
131         String permissionType = Manifest.permission.ACCESS_FINE_LOCATION;
132         if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
133             // Having FINE permission implies having COARSE permission (but not the reverse)
134             permissionType = Manifest.permission.ACCESS_COARSE_LOCATION;
135         }
136         if (mWifiPermissionsWrapper.getUidPermission(permissionType, uid)
137                 == PackageManager.PERMISSION_DENIED) {
138             return false;
139         }
140 
141         // Always checking FINE - even if will not enforce. This will record the request for FINE
142         // so that a location request by the app is surfaced to the user.
143         boolean isFineLocationAllowed = noteAppOpAllowed(
144                 AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid, message);
145         if (isFineLocationAllowed) {
146             return true;
147         }
148         if (coarseForTargetSdkLessThanQ && isTargetSdkLessThanQ) {
149             return noteAppOpAllowed(AppOpsManager.OPSTR_COARSE_LOCATION, pkgName, featureId, uid,
150                     message);
151         }
152         return false;
153     }
154 
155     /**
156      * Check and enforce Fine Location permission.
157      *
158      * @param pkgName PackageName of the application requesting access
159      * @param featureId The feature in the package
160      * @param uid The uid of the package
161      */
enforceFineLocationPermission(String pkgName, @Nullable String featureId, int uid)162     public void enforceFineLocationPermission(String pkgName, @Nullable String featureId,
163             int uid) {
164         if (!checkCallersFineLocationPermission(pkgName, featureId, uid, false)) {
165             throw new SecurityException("UID " + uid + " does not have Fine Location permission");
166         }
167     }
168 
169     /**
170      * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION
171      * and a corresponding app op is allowed for this package and uid.
172      *
173      * @param pkgName PackageName of the application requesting access
174      * @param featureId The feature in the package
175      * @param uid The uid of the package
176      * @param hideFromAppOps True to invoke {@link AppOpsManager#checkOp(int, int, String)}, false
177      *                       to invoke {@link AppOpsManager#noteOp(String, int, String, String,
178      *                       String)}.
179      */
checkCallersFineLocationPermission(String pkgName, @Nullable String featureId, int uid, boolean hideFromAppOps)180     private boolean checkCallersFineLocationPermission(String pkgName, @Nullable String featureId,
181             int uid, boolean hideFromAppOps) {
182         // Having FINE permission implies having COARSE permission (but not the reverse)
183         if (mWifiPermissionsWrapper.getUidPermission(
184                 Manifest.permission.ACCESS_FINE_LOCATION, uid)
185                 == PackageManager.PERMISSION_DENIED) {
186             return false;
187         }
188         if (hideFromAppOps) {
189             // Don't note the operation, just check if the app is allowed to perform the operation.
190             return checkAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, uid);
191         } else {
192             return noteAppOpAllowed(AppOpsManager.OPSTR_FINE_LOCATION, pkgName, featureId, uid,
193                     null);
194         }
195     }
196 
197     /**
198      * Checks that calling process has android.Manifest.permission.LOCATION_HARDWARE.
199      *
200      * @param uid The uid of the package
201      */
checkCallersHardwareLocationPermission(int uid)202     private boolean checkCallersHardwareLocationPermission(int uid) {
203         return mWifiPermissionsWrapper.getUidPermission(Manifest.permission.LOCATION_HARDWARE, uid)
204                 == PackageManager.PERMISSION_GRANTED;
205     }
206 
207     /**
208      * API to determine if the caller has permissions to get scan results. Throws SecurityException
209      * if the caller has no permission.
210      * @param pkgName package name of the application requesting access
211      * @param featureId The feature in the package
212      * @param uid The uid of the package
213      * @param message A message describing why the permission was checked. Only needed if this is
214      *                not inside of a two-way binder call from the data receiver
215      */
enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid, @Nullable String message)216     public void enforceCanAccessScanResults(String pkgName, @Nullable String featureId, int uid,
217             @Nullable String message)
218             throws SecurityException {
219         checkPackage(uid, pkgName);
220 
221         // Apps with NETWORK_SETTINGS, NETWORK_SETUP_WIZARD, NETWORK_MANAGED_PROVISIONING,
222         // NETWORK_STACK & MAINLINE_NETWORK_STACK, RADIO_SCAN_WITHOUT_LOCATION are granted a bypass.
223         if (checkNetworkSettingsPermission(uid) || checkNetworkSetupWizardPermission(uid)
224                 || checkNetworkManagedProvisioningPermission(uid)
225                 || checkNetworkStackPermission(uid) || checkMainlineNetworkStackPermission(uid)
226                 || checkScanWithoutLocationPermission(uid)) {
227             return;
228         }
229 
230         // Location mode must be enabled
231         if (!isLocationModeEnabled()) {
232             // Location mode is disabled, scan results cannot be returned
233             throw new SecurityException("Location mode is disabled for the device");
234         }
235 
236         // Check if the calling Uid has CAN_READ_PEER_MAC_ADDRESS permission.
237         boolean canCallingUidAccessLocation = checkCallerHasPeersMacAddressPermission(uid);
238         // LocationAccess by App: caller must have Coarse/Fine Location permission to have access to
239         // location information.
240         boolean canAppPackageUseLocation = checkCallersLocationPermission(pkgName, featureId,
241                 uid, /* coarseForTargetSdkLessThanQ */ true, message);
242 
243         // If neither caller or app has location access, there is no need to check
244         // any other permissions. Deny access to scan results.
245         if (!canCallingUidAccessLocation && !canAppPackageUseLocation) {
246             throw new SecurityException("UID " + uid + " has no location permission");
247         }
248         // Check if Wifi Scan request is an operation allowed for this App.
249         if (!isScanAllowedbyApps(pkgName, featureId, uid)) {
250             throw new SecurityException("UID " + uid + " has no wifi scan permission");
251         }
252         // If the User or profile is current, permission is granted
253         // Otherwise, uid must have INTERACT_ACROSS_USERS_FULL permission.
254         if (!isCurrentProfile(uid) && !checkInteractAcrossUsersFull(uid)) {
255             throw new SecurityException("UID " + uid + " profile not permitted");
256         }
257     }
258 
259     /**
260      * API to determine if the caller has permissions to get scan results. Throws SecurityException
261      * if the caller has no permission.
262      * @param pkgName package name of the application requesting access
263      * @param featureId The feature in the package
264      * @param uid The uid of the package
265      * @param ignoreLocationSettings Whether this request can bypass location settings.
266      * @param hideFromAppOps Whether to note the request in app-ops logging or not.
267      *
268      * Note: This is to be used for checking permissions in the internal WifiScanner API surface
269      * for requests coming from system apps.
270      */
enforceCanAccessScanResultsForWifiScanner(String pkgName, @Nullable String featureId, int uid, boolean ignoreLocationSettings, boolean hideFromAppOps)271     public void enforceCanAccessScanResultsForWifiScanner(String pkgName,
272             @Nullable String featureId, int uid, boolean ignoreLocationSettings,
273             boolean hideFromAppOps) throws SecurityException {
274         checkPackage(uid, pkgName);
275 
276         // Location mode must be enabled
277         if (!isLocationModeEnabled()) {
278             if (ignoreLocationSettings) {
279                 mLog.w("Request from " + pkgName + " violated location settings");
280             } else {
281                 // Location mode is disabled, scan results cannot be returned
282                 throw new SecurityException("Location mode is disabled for the device");
283             }
284         }
285         // LocationAccess by App: caller must have fine & hardware Location permission to have
286         // access to location information.
287         if (!checkCallersFineLocationPermission(pkgName, featureId, uid, hideFromAppOps)
288                 || !checkCallersHardwareLocationPermission(uid)) {
289             throw new SecurityException("UID " + uid + " has no location permission");
290         }
291         // Check if Wifi Scan request is an operation allowed for this App.
292         if (!isScanAllowedbyApps(pkgName, featureId, uid)) {
293             throw new SecurityException("UID " + uid + " has no wifi scan permission");
294         }
295     }
296 
297     /**
298      *
299      * Checks that calling process has android.Manifest.permission.ACCESS_FINE_LOCATION
300      * and a corresponding app op is allowed for this package and uid
301      *
302      * @param pkgName package name of the application requesting access
303      * @param featureId The feature in the package
304      * @param uid The uid of the package
305      * @param needLocationModeEnabled indicates location mode must be enabled.
306      *
307      * @return true if caller has permission, false otherwise
308      */
checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid, boolean needLocationModeEnabled)309     public boolean checkCanAccessWifiDirect(String pkgName, @Nullable String featureId, int uid,
310                                             boolean needLocationModeEnabled) {
311         try {
312             checkPackage(uid, pkgName);
313         } catch (SecurityException se) {
314             Log.e(TAG, "Package check exception - " + se);
315             return false;
316         }
317 
318         // Apps with NETWORK_SETTINGS are granted a bypass.
319         if (checkNetworkSettingsPermission(uid)) {
320             return true;
321         }
322 
323         // Location mode must be enabled if needed.
324         if (needLocationModeEnabled && !isLocationModeEnabled()) {
325             Log.e(TAG, "Location mode is disabled for the device");
326             return false;
327         }
328 
329         // LocationAccess by App: caller must have Fine Location permission to have access to
330         // location information.
331         if (!checkCallersLocationPermission(pkgName, featureId, uid,
332                 /* coarseForTargetSdkLessThanQ */ false, null)) {
333             Log.e(TAG, "UID " + uid + " has no location permission");
334             return false;
335         }
336         return true;
337     }
338 
339     /**
340      * API to check to validate if a package name belongs to a UID. Throws SecurityException
341      * if pkgName does not belongs to a UID
342      *
343      * @param pkgName package name of the application requesting access
344      * @param uid The uid of the package
345      *
346      */
checkPackage(int uid, String pkgName)347     public void checkPackage(int uid, String pkgName) throws SecurityException {
348         if (pkgName == null) {
349             throw new SecurityException("Checking UID " + uid + " but Package Name is Null");
350         }
351         mAppOps.checkPackage(uid, pkgName);
352     }
353 
354     /**
355      * Returns true if the caller holds PEERS_MAC_ADDRESS permission.
356      */
checkCallerHasPeersMacAddressPermission(int uid)357     private boolean checkCallerHasPeersMacAddressPermission(int uid) {
358         return mWifiPermissionsWrapper.getUidPermission(
359                 android.Manifest.permission.PEERS_MAC_ADDRESS, uid)
360                 == PackageManager.PERMISSION_GRANTED;
361     }
362 
363     /**
364      * Returns true if Wifi scan operation is allowed for this caller
365      * and package.
366      */
isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid)367     private boolean isScanAllowedbyApps(String pkgName, @Nullable String featureId, int uid) {
368         return noteAppOpAllowed(AppOpsManager.OPSTR_WIFI_SCAN, pkgName, featureId, uid, null);
369     }
370 
371     /**
372      * Returns true if the caller holds INTERACT_ACROSS_USERS_FULL.
373      */
checkInteractAcrossUsersFull(int uid)374     private boolean checkInteractAcrossUsersFull(int uid) {
375         return mWifiPermissionsWrapper.getUidPermission(
376                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)
377                 == PackageManager.PERMISSION_GRANTED;
378     }
379 
380     /**
381      * Returns true if the calling user is the current one or a profile of the
382      * current user.
383      */
isCurrentProfile(int uid)384     private boolean isCurrentProfile(int uid) {
385         UserHandle currentUser = UserHandle.of(mWifiPermissionsWrapper.getCurrentUser());
386         UserHandle callingUser = UserHandle.getUserHandleForUid(uid);
387         return currentUser.equals(callingUser)
388                 || mUserManager.isSameProfileGroup(currentUser, callingUser);
389     }
390 
noteAppOpAllowed(String op, String pkgName, @Nullable String featureId, int uid, @Nullable String message)391     private boolean noteAppOpAllowed(String op, String pkgName, @Nullable String featureId,
392             int uid, @Nullable String message) {
393         return mAppOps.noteOp(op, uid, pkgName, featureId, message) == AppOpsManager.MODE_ALLOWED;
394     }
395 
checkAppOpAllowed(String op, String pkgName, int uid)396     private boolean checkAppOpAllowed(String op, String pkgName, int uid) {
397         return mAppOps.unsafeCheckOp(op, uid, pkgName) == AppOpsManager.MODE_ALLOWED;
398     }
399 
retrieveLocationManagerIfNecessary()400     private boolean retrieveLocationManagerIfNecessary() {
401         // This is going to be accessed by multiple threads.
402         synchronized (mLock) {
403             if (mLocationManager == null) {
404                 mLocationManager =
405                         (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
406             }
407         }
408         return mLocationManager != null;
409     }
410 
411     /**
412      * Retrieves a handle to LocationManager (if not already done) and check if location is enabled.
413      */
isLocationModeEnabled()414     public boolean isLocationModeEnabled() {
415         if (!retrieveLocationManagerIfNecessary()) return false;
416         try {
417             return mLocationManager.isLocationEnabledForUser(UserHandle.of(
418                     mWifiPermissionsWrapper.getCurrentUser()));
419         } catch (Exception e) {
420             Log.e(TAG, "Failure to get location mode via API, falling back to settings", e);
421             return mFrameworkFacade.getIntegerSetting(
422                     mContext, Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF)
423                     == Settings.Secure.LOCATION_MODE_ON;
424         }
425     }
426 
427     /**
428      * Returns true if the |uid| holds NETWORK_SETTINGS permission.
429      */
checkNetworkSettingsPermission(int uid)430     public boolean checkNetworkSettingsPermission(int uid) {
431         return mWifiPermissionsWrapper.getUidPermission(
432                 android.Manifest.permission.NETWORK_SETTINGS, uid)
433                 == PackageManager.PERMISSION_GRANTED;
434     }
435 
436     /**
437      * Returns true if the |uid| holds RADIO_SCAN_WITHOUT_LOCATION permission.
438      */
checkScanWithoutLocationPermission(int uid)439     public boolean checkScanWithoutLocationPermission(int uid) {
440         return mWifiPermissionsWrapper.getUidPermission(
441                 android.Manifest.permission.RADIO_SCAN_WITHOUT_LOCATION, uid)
442                 == PackageManager.PERMISSION_GRANTED;
443     }
444 
445     /**
446      * Returns true if the |uid| holds LOCAL_MAC_ADDRESS permission.
447      */
checkLocalMacAddressPermission(int uid)448     public boolean checkLocalMacAddressPermission(int uid) {
449         return mWifiPermissionsWrapper.getUidPermission(
450                 android.Manifest.permission.LOCAL_MAC_ADDRESS, uid)
451                 == PackageManager.PERMISSION_GRANTED;
452     }
453 
454     /**
455      * Returns true if the |uid| holds NETWORK_SETUP_WIZARD permission.
456      */
checkNetworkSetupWizardPermission(int uid)457     public boolean checkNetworkSetupWizardPermission(int uid) {
458         return mWifiPermissionsWrapper.getUidPermission(
459                 android.Manifest.permission.NETWORK_SETUP_WIZARD, uid)
460                 == PackageManager.PERMISSION_GRANTED;
461     }
462 
463     /**
464      * Returns true if the |uid| holds NETWORK_STACK permission.
465      */
checkNetworkStackPermission(int uid)466     public boolean checkNetworkStackPermission(int uid) {
467         return mWifiPermissionsWrapper.getUidPermission(
468                 android.Manifest.permission.NETWORK_STACK, uid)
469                 == PackageManager.PERMISSION_GRANTED;
470     }
471 
472     /**
473      * Returns true if the |uid| holds MAINLINE_NETWORK_STACK permission.
474      */
checkMainlineNetworkStackPermission(int uid)475     public boolean checkMainlineNetworkStackPermission(int uid) {
476         return mWifiPermissionsWrapper.getUidPermission(
477                 NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, uid)
478                 == PackageManager.PERMISSION_GRANTED;
479     }
480 
481     /**
482      * Returns true if the |uid| holds NETWORK_MANAGED_PROVISIONING permission.
483      */
checkNetworkManagedProvisioningPermission(int uid)484     public boolean checkNetworkManagedProvisioningPermission(int uid) {
485         return mWifiPermissionsWrapper.getUidPermission(
486                 android.Manifest.permission.NETWORK_MANAGED_PROVISIONING, uid)
487                 == PackageManager.PERMISSION_GRANTED;
488     }
489 
490     /**
491      * Returns true if the |uid| holds NETWORK_CARRIER_PROVISIONING permission.
492      */
checkNetworkCarrierProvisioningPermission(int uid)493     public boolean checkNetworkCarrierProvisioningPermission(int uid) {
494         return mWifiPermissionsWrapper.getUidPermission(
495                 android.Manifest.permission.NETWORK_CARRIER_PROVISIONING, uid)
496                 == PackageManager.PERMISSION_GRANTED;
497     }
498 
499     /**
500      * Returns true if the |uid| holds READ_WIFI_CREDENTIAL permission.
501      */
checkReadWifiCredentialPermission(int uid)502     public boolean checkReadWifiCredentialPermission(int uid) {
503         return mWifiPermissionsWrapper.getUidPermission(
504                 android.Manifest.permission.READ_WIFI_CREDENTIAL, uid)
505                 == PackageManager.PERMISSION_GRANTED;
506     }
507 
508     /**
509      * Returns true if the |callingUid|/\callingPackage| holds SYSTEM_ALERT_WINDOW permission.
510      */
checkSystemAlertWindowPermission(int callingUid, String callingPackage)511     public boolean checkSystemAlertWindowPermission(int callingUid, String callingPackage) {
512         final int mode = mAppOps.noteOp(AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW, callingUid,
513                 callingPackage, null, null);
514         if (mode == AppOpsManager.MODE_DEFAULT) {
515             return mWifiPermissionsWrapper.getUidPermission(
516                     Manifest.permission.SYSTEM_ALERT_WINDOW, callingUid)
517                     == PackageManager.PERMISSION_GRANTED;
518         }
519         return mode == AppOpsManager.MODE_ALLOWED;
520     }
521 
retrieveDevicePolicyManagerFromContext(Context context)522     private static DevicePolicyManager retrieveDevicePolicyManagerFromContext(Context context) {
523         DevicePolicyManager devicePolicyManager =
524                 context.getSystemService(DevicePolicyManager.class);
525         if (devicePolicyManager == null
526                 && context.getPackageManager().hasSystemFeature(
527                 PackageManager.FEATURE_DEVICE_ADMIN)) {
528             Log.w(TAG, "Error retrieving DPM service");
529         }
530         return devicePolicyManager;
531     }
532 
retrieveDevicePolicyManagerFromUserContext(int uid)533     private DevicePolicyManager retrieveDevicePolicyManagerFromUserContext(int uid) {
534         Context userContext = null;
535         try {
536             userContext = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
537                     UserHandle.getUserHandleForUid(uid));
538         } catch (PackageManager.NameNotFoundException e) {
539             Log.e(TAG, "Unknown package name");
540             return null;
541         }
542         if (userContext == null) {
543             Log.e(TAG, "Unable to retrieve user context for " + uid);
544             return null;
545         }
546         return retrieveDevicePolicyManagerFromContext(userContext);
547     }
548 
549     /**
550      * Returns true if the |callingUid|/\callingPackage| is the device owner.
551      */
isDeviceOwner(int uid, @Nullable String packageName)552     public boolean isDeviceOwner(int uid, @Nullable String packageName) {
553         // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be
554         // safe.
555         if (packageName == null) {
556             Log.e(TAG, "isDeviceOwner: packageName is null, returning false");
557             return false;
558         }
559         DevicePolicyManager devicePolicyManager =
560                 retrieveDevicePolicyManagerFromContext(mContext);
561         if (devicePolicyManager == null) return false;
562         long ident = Binder.clearCallingIdentity();
563         UserHandle deviceOwnerUser = null;
564         ComponentName deviceOwnerComponent = null;
565         try {
566             deviceOwnerUser = devicePolicyManager.getDeviceOwnerUser();
567             deviceOwnerComponent = devicePolicyManager.getDeviceOwnerComponentOnAnyUser();
568         } finally {
569             Binder.restoreCallingIdentity(ident);
570         }
571         // no device owner
572         if (deviceOwnerUser == null || deviceOwnerComponent == null) return false;
573         return deviceOwnerUser.equals(UserHandle.getUserHandleForUid(uid))
574                 && deviceOwnerComponent.getPackageName().equals(packageName);
575     }
576 
577     /**
578      * Returns true if the |callingUid|/\callingPackage| is the profile owner.
579      */
isProfileOwner(int uid, @Nullable String packageName)580     public boolean isProfileOwner(int uid, @Nullable String packageName) {
581         // Cannot determine if the app is DO/PO if packageName is null. So, will return false to be
582         // safe.
583         if (packageName == null) {
584             Log.e(TAG, "isProfileOwner: packageName is null, returning false");
585             return false;
586         }
587         DevicePolicyManager devicePolicyManager =
588                 retrieveDevicePolicyManagerFromUserContext(uid);
589         if (devicePolicyManager == null) return false;
590         return devicePolicyManager.isProfileOwnerApp(packageName);
591     }
592 }
593