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