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