From 56a84b26f4b5f195ad5157fa99b46f72aab496a4 Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Wed, 4 Mar 2020 20:41:36 -0800 Subject: Refactor device ID access SystemAPI to PermissionManager Based on feedback during the API review of the new SystemAPI for telephony to check device identifier access the method was moved from DevicePolicyManager to a more generic location to perform the non-subscriber portions of the check. Bug: 147761267 Test: atest TelephonyPermissionsTest Test: atest PermissionManagerServiceTest Test: atest DeviceIdentifierTest Test: atest DeviceOwnerTest#testDeviceOwnerCanGetDeviceIdentifiers Test: atest TelephonyManagerTest Test: atest DeviceOwnerTest#testDeviceOwnerCannotGetDeviceIdentifiersWithoutPermission Test: atest ManagedProfileTest#testProfileOwnerOnPersonalDeviceCannotGetDeviceIdentifiers Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testProfileOwnerCannotGetDeviceIdentifiersWithoutPermission Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.OrgOwnedProfileOwnerTest#testProfileOwnerCanGetDeviceIdentifiers Change-Id: Ic1867dad0b2369f2dc1a7d31facb65f89131376f --- api/system-current.txt | 2 +- .../android/app/admin/DevicePolicyManager.java | 1 - .../android/permission/IPermissionManager.aidl | 2 + .../java/android/permission/PermissionManager.java | 44 ++++- .../pm/permission/PermissionManagerService.java | 161 ++++++++++++++++- .../permission/PermissionManagerServiceTest.java | 197 +++++++++++++++++++++ .../internal/telephony/TelephonyPermissions.java | 38 +--- 7 files changed, 405 insertions(+), 40 deletions(-) create mode 100644 services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java diff --git a/api/system-current.txt b/api/system-current.txt index 400c6e5e3ee2..ae0779c0cc2b 100755 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -872,7 +872,6 @@ package android.app.admin { method @Nullable public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException; method @Nullable @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException; method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserProvisioningState(); - method public boolean hasDeviceIdentifierAccess(@NonNull String, int, int); method public boolean isDeviceManaged(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioned(); method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isDeviceProvisioningConfigApplied(); @@ -8893,6 +8892,7 @@ package android.permission { } public final class PermissionManager { + method public int checkDeviceIdentifierAccess(@Nullable String, @Nullable String, @Nullable String, int, int); method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set getAutoRevokeExemptionGrantedPackages(); method @NonNull @RequiresPermission(android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY) public java.util.Set getAutoRevokeExemptionRequestedPackages(); method @IntRange(from=0) @RequiresPermission(anyOf={android.Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, android.Manifest.permission.UPGRADE_RUNTIME_PERMISSIONS}) public int getRuntimePermissionsVersion(); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 37f1a6559bfe..c3a7612cc571 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -7071,7 +7071,6 @@ public class DevicePolicyManager { * * @hide */ - @SystemApi public boolean hasDeviceIdentifierAccess(@NonNull String packageName, int pid, int uid) { throwIfParentInstance("hasDeviceIdentifierAccess"); if (packageName == null) { diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl index 09df72c286d0..235b0830b9aa 100644 --- a/core/java/android/permission/IPermissionManager.aidl +++ b/core/java/android/permission/IPermissionManager.aidl @@ -54,6 +54,8 @@ interface IPermissionManager { int checkUidPermission(String permName, int uid); + int checkDeviceIdentifierAccess(String packageName, String callingFeatureId, String message, int pid, int uid); + void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener); diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java index fc993b87a978..3dc8e9924444 100644 --- a/core/java/android/permission/PermissionManager.java +++ b/core/java/android/permission/PermissionManager.java @@ -40,6 +40,7 @@ import android.os.UserHandle; import android.util.Slog; import com.android.internal.annotations.Immutable; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.CollectionUtils; import java.util.ArrayList; @@ -84,10 +85,25 @@ public final class PermissionManager { */ public PermissionManager(@NonNull Context context, IPackageManager packageManager) throws ServiceManager.ServiceNotFoundException { + this(context, packageManager, IPermissionManager.Stub.asInterface( + ServiceManager.getServiceOrThrow("permissionmgr"))); + } + + /** + * Creates a new instance with the provided instantiation of the IPermissionManager. + * + * @param context the current context in which to operate + * @param packageManager package manager service to be used for package related permission + * requests + * @param permissionManager injectable permission manager service + * @hide + */ + @VisibleForTesting + public PermissionManager(@NonNull Context context, IPackageManager packageManager, + IPermissionManager permissionManager) { mContext = context; mPackageManager = packageManager; - mPermissionManager = IPermissionManager.Stub.asInterface( - ServiceManager.getServiceOrThrow("permissionmgr")); + mPermissionManager = permissionManager; } /** @@ -486,6 +502,30 @@ public final class PermissionManager { } } + /** + * Checks whether the package with the given pid/uid can read device identifiers. + * + * @param packageName the name of the package to be checked for identifier access + * @param message the message to be used for logging during identifier access + * verification + * @param callingFeatureId the feature in the package + * @param pid the process id of the package to be checked + * @param uid the uid of the package to be checked + * @return {@link PackageManager#PERMISSION_GRANTED} if the package is allowed identifier + * access, {@link PackageManager#PERMISSION_DENIED} otherwise + * @hide + */ + @SystemApi + public int checkDeviceIdentifierAccess(@Nullable String packageName, @Nullable String message, + @Nullable String callingFeatureId, int pid, int uid) { + try { + return mPermissionManager.checkDeviceIdentifierAccess(packageName, message, + callingFeatureId, pid, uid); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /* @hide */ private static int checkPermissionUncached(@Nullable String permission, int pid, int uid) { final IActivityManager am = ActivityManager.getService(); diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java index 5d6eaf22dae2..79d0c2db4448 100644 --- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java +++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java @@ -59,6 +59,7 @@ import android.app.AppOpsManager; import android.app.ApplicationPackageManager; import android.app.IActivityManager; import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManager; import android.app.admin.DevicePolicyManagerInternal; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; @@ -113,6 +114,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.compat.IPlatformCompat; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; @@ -243,6 +245,9 @@ public class PermissionManagerService extends IPermissionManager.Stub { @GuardedBy("mLock") private final PermissionSettings mSettings; + /** Injector that can be used to facilitate testing. */ + private final Injector mInjector; + @GuardedBy("mLock") private ArraySet mPrivappPermissionsViolations; @@ -352,10 +357,17 @@ public class PermissionManagerService extends IPermissionManager.Stub { PermissionManagerService(Context context, @NonNull Object externalLock) { + this(context, externalLock, new Injector(context)); + } + + @VisibleForTesting + PermissionManagerService(Context context, @NonNull Object externalLock, + @NonNull Injector injector) { + mInjector = injector; // The package info cache is the cache for package and permission information. - PackageManager.invalidatePackageInfoCache(); - PermissionManager.disablePermissionCache(); - PermissionManager.disablePackageNamePermissionCache(); + mInjector.invalidatePackageInfoCache(); + mInjector.disablePermissionCache(); + mInjector.disablePackageNamePermissionCache(); mContext = context; mLock = externalLock; @@ -951,6 +963,59 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } + @Override + public int checkDeviceIdentifierAccess(@Nullable String packageName, @Nullable String message, + @Nullable String callingFeatureId, int pid, int uid) { + // If the check is being requested by an app then only allow the app to query its own + // access status. + int callingUid = mInjector.getCallingUid(); + int callingPid = mInjector.getCallingPid(); + if (UserHandle.getAppId(callingUid) >= Process.FIRST_APPLICATION_UID && (callingUid != uid + || callingPid != pid)) { + String response = String.format( + "Calling uid %d, pid %d cannot check device identifier access for package %s " + + "(uid=%d, pid=%d)", + callingUid, callingPid, packageName, uid, pid); + Log.w(TAG, response); + throw new SecurityException(response); + } + // Allow system and root access to the device identifiers. + final int appId = UserHandle.getAppId(uid); + if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { + return PackageManager.PERMISSION_GRANTED; + } + // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission. + if (mInjector.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, + uid) == PackageManager.PERMISSION_GRANTED) { + return PackageManager.PERMISSION_GRANTED; + } + // If the calling package is not null then perform the appop and device / profile owner + // check. + if (packageName != null) { + // Allow access to a package that has been granted the READ_DEVICE_IDENTIFIERS appop. + long token = mInjector.clearCallingIdentity(); + AppOpsManager appOpsManager = (AppOpsManager) mInjector.getSystemService( + Context.APP_OPS_SERVICE); + try { + if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid, + packageName, callingFeatureId, message) == AppOpsManager.MODE_ALLOWED) { + return PackageManager.PERMISSION_GRANTED; + } + } finally { + mInjector.restoreCallingIdentity(token); + } + // Check if the calling packages meets the device / profile owner requirements for + // identifier access. + DevicePolicyManager devicePolicyManager = + (DevicePolicyManager) mInjector.getSystemService(Context.DEVICE_POLICY_SERVICE); + if (devicePolicyManager != null && devicePolicyManager.hasDeviceIdentifierAccess( + packageName, pid, uid)) { + return PackageManager.PERMISSION_GRANTED; + } + } + return PackageManager.PERMISSION_DENIED; + } + @Override public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) { mContext.enforceCallingOrSelfPermission( @@ -4797,4 +4862,94 @@ public class PermissionManagerService extends IPermissionManager.Stub { } } } + + /** + * Allows injection of services and method responses to facilitate testing. + * + *

Test classes can create a mock of this class and pass it to the PermissionManagerService + * constructor to control behavior of services and external methods during execution. + * @hide + */ + @VisibleForTesting + public static class Injector { + private final Context mContext; + + /** + * Public constructor that accepts a {@code context} within which to operate. + */ + public Injector(@NonNull Context context) { + mContext = context; + } + + /** + * Returns the UID of the calling package. + */ + public int getCallingUid() { + return Binder.getCallingUid(); + } + + /** + * Returns the process ID of the calling package. + */ + public int getCallingPid() { + return Binder.getCallingPid(); + } + + /** + * Invalidates the package info cache. + */ + public void invalidatePackageInfoCache() { + PackageManager.invalidatePackageInfoCache(); + } + + /** + * Disables the permission cache. + */ + public void disablePermissionCache() { + PermissionManager.disablePermissionCache(); + } + + /** + * Disables the package name permission cache. + */ + public void disablePackageNamePermissionCache() { + PermissionManager.disablePackageNamePermissionCache(); + } + + /** + * Checks if the package running under the specified {@code pid} and {@code uid} has been + * granted the provided {@code permission}. + * + * @return {@link PackageManager#PERMISSION_GRANTED} if the package has been granted the + * permission, {@link PackageManager#PERMISSION_DENIED} otherwise + */ + public int checkPermission(@NonNull String permission, int pid, int uid) { + return mContext.checkPermission(permission, pid, uid); + } + + /** + * Clears the calling identity to allow subsequent calls to be treated as coming from this + * package. + * + * @return a token that can be used to restore the calling identity + */ + public long clearCallingIdentity() { + return Binder.clearCallingIdentity(); + } + + /** + * Restores the calling identity to that of the calling package based on the provided + * {@code token}. + */ + public void restoreCallingIdentity(long token) { + Binder.restoreCallingIdentity(token); + } + + /** + * Returns the system service with the provided {@code name}. + */ + public Object getSystemService(@NonNull String name) { + return mContext.getSystemService(name); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java new file mode 100644 index 000000000000..56966776c8fb --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/pm/permission/PermissionManagerServiceTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm.permission; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.when; +import static org.testng.Assert.assertThrows; + +import android.app.AppOpsManager; +import android.app.admin.DevicePolicyManager; +import android.content.Context; +import android.content.pm.PackageManager; +import android.os.Process; +import android.permission.PermissionManagerInternal; + +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import com.android.server.LocalServices; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@RunWith(AndroidJUnit4.class) +public class PermissionManagerServiceTest { + private static final String TAG = "PermissionManagerServiceTag"; + + private static final int SYSTEM_UID = 1000; + private static final int SYSTEM_PID = 1234; + private static final int APP_UID = Process.FIRST_APPLICATION_UID; + private static final int APP_PID = 5678; + + private PermissionManagerService mPermissionManagerService; + private Context mContext; + + @Mock + private PermissionManagerService.Injector mInjector; + + @Mock + private AppOpsManager mAppOpsManager; + + @Mock + private DevicePolicyManager mDevicePolicyManager; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + + mContext = InstrumentationRegistry.getContext(); + Object lock = new Object(); + mPermissionManagerService = new PermissionManagerService(mContext, lock, mInjector); + } + + @After + public void tearDown() { + // The LocalServices added by the constructor of the PermissionManagerService can either be + // removed here after each test when tests are run serially, or to run them in parallel + // the Injector can provide methods to add these that can be ignored by the mock. + LocalServices.removeServiceForTest(PermissionManagerServiceInternal.class); + LocalServices.removeServiceForTest(PermissionManagerInternal.class); + } + + @Test + public void checkDeviceIdentifierAccess_callingAppUidMismatch_throwsException() { + // An application should only be able to query its own device identifier access, querying + // of any other UIDs should result in a SecurityException. + setupCheckDeviceIdentifierAccessTest(APP_PID, APP_UID); + + assertThrows(SecurityException.class, + () -> mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, + APP_PID, SYSTEM_UID)); + } + + @Test + public void checkDeviceIdentifierAccess_callingAppPidMismatch_throwsException() { + // Similar to above an app can only specify its own pid, a mismatch should result in a + // SecurityException. + setupCheckDeviceIdentifierAccessTest(APP_PID, APP_UID); + + assertThrows(SecurityException.class, + () -> mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, + SYSTEM_PID, APP_UID)); + } + + @Test + public void checkDeviceIdentifierAccess_callingAppIdWithoutAccess_returnsDenied() { + // An application can query its own device identifier access; this test verifies that all + // checks can run through completion and return denied. + setupCheckDeviceIdentifierAccessTest(APP_PID, APP_UID); + + int result = mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, APP_PID, + APP_UID); + + assertEquals(PackageManager.PERMISSION_DENIED, result); + } + + @Test + public void checkDeviceIdentifierAccess_systemUid_returnsGranted() { + // The system UID should always have access to device identifiers. + setupCheckDeviceIdentifierAccessTest(SYSTEM_PID, SYSTEM_UID); + int result = mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, SYSTEM_PID, + SYSTEM_UID); + + assertEquals(PackageManager.PERMISSION_GRANTED, result); + } + + @Test + public void checkDeviceIdentifierAccess_hasPrivilegedPermission_returnsGranted() { + // Apps with the READ_PRIVILEGED_PHONE_STATE permission should have access to device + // identifiers. + setupCheckDeviceIdentifierAccessTest(SYSTEM_PID, SYSTEM_UID); + when(mInjector.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, + APP_PID, APP_UID)).thenReturn(PackageManager.PERMISSION_GRANTED); + + int result = mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, APP_PID, + APP_UID); + + assertEquals(PackageManager.PERMISSION_GRANTED, result); + } + + @Test + public void checkDeviceIdentifierAccess_hasAppOp_returnsGranted() { + // Apps that have been granted the READ_DEVICE_IDENTIFIERS appop should have access to + // device identifiers. + setupCheckDeviceIdentifierAccessTest(SYSTEM_PID, SYSTEM_UID); + when(mAppOpsManager.noteOpNoThrow(eq(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS), + eq(APP_UID), eq(mContext.getPackageName()), any(), any())).thenReturn( + AppOpsManager.MODE_ALLOWED); + + int result = mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, APP_PID, + APP_UID); + + assertEquals(PackageManager.PERMISSION_GRANTED, result); + } + + @Test + public void checkDeviceIdentifierAccess_hasDpmAccess_returnsGranted() { + // Apps that pass a DevicePolicyManager device / profile owner check should have access to + // device identifiers. + setupCheckDeviceIdentifierAccessTest(SYSTEM_PID, SYSTEM_UID); + when(mDevicePolicyManager.hasDeviceIdentifierAccess(mContext.getPackageName(), APP_PID, + APP_UID)).thenReturn(true); + + int result = mPermissionManagerService.checkDeviceIdentifierAccess( + mContext.getPackageName(), "testCheckDeviceIdentifierAccess", null, APP_PID, + APP_UID); + + assertEquals(PackageManager.PERMISSION_GRANTED, result); + } + + private void setupCheckDeviceIdentifierAccessTest(int callingPid, int callingUid) { + when(mInjector.getCallingPid()).thenReturn(callingPid); + when(mInjector.getCallingUid()).thenReturn(callingUid); + + // Configure the checkDeviceIdentifierAccess tests to fail all access checks, then each test + // can individually set the access check to pass for verification. + when(mInjector.checkPermission(anyString(), anyInt(), anyInt())).thenReturn( + PackageManager.PERMISSION_DENIED); + + when(mAppOpsManager.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), + any())).thenReturn(AppOpsManager.MODE_DEFAULT); + when(mInjector.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOpsManager); + + when(mDevicePolicyManager.hasDeviceIdentifierAccess(anyString(), anyInt(), + anyInt())).thenReturn(false); + when(mInjector.getSystemService(eq(Context.DEVICE_POLICY_SERVICE))).thenReturn( + mDevicePolicyManager); + } +} diff --git a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java index 68b17688c22e..0b331744d922 100644 --- a/telephony/common/com/android/internal/telephony/TelephonyPermissions.java +++ b/telephony/common/com/android/internal/telephony/TelephonyPermissions.java @@ -20,7 +20,6 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import android.Manifest; import android.annotation.Nullable; import android.app.AppOpsManager; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; @@ -28,6 +27,7 @@ import android.os.Binder; import android.os.Build; import android.os.Process; import android.os.UserHandle; +import android.permission.PermissionManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; @@ -303,14 +303,10 @@ public final class TelephonyPermissions { String message, boolean allowCarrierPrivilegeOnAnySub) { int uid = Binder.getCallingUid(); int pid = Binder.getCallingPid(); - // Allow system and root access to the device identifiers. - final int appId = UserHandle.getAppId(uid); - if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { - return true; - } - // Allow access to packages that have the READ_PRIVILEGED_PHONE_STATE permission. - if (context.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, - uid) == PackageManager.PERMISSION_GRANTED) { + PermissionManager permissionManager = (PermissionManager) context.getSystemService( + Context.PERMISSION_SERVICE); + if (permissionManager.checkDeviceIdentifierAccess(callingPackage, message, callingFeatureId, + pid, uid) == PackageManager.PERMISSION_GRANTED) { return true; } @@ -323,30 +319,6 @@ public final class TelephonyPermissions { return true; } - // if the calling package is not null then perform the DevicePolicyManager device / - // profile owner and Appop checks. - if (callingPackage != null) { - // Allow access to an app that has been granted the READ_DEVICE_IDENTIFIERS app op. - long token = Binder.clearCallingIdentity(); - AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService( - Context.APP_OPS_SERVICE); - try { - if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid, - callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { - return true; - } - } finally { - Binder.restoreCallingIdentity(token); - } - // Allow access to a device / profile owner app. - DevicePolicyManager devicePolicyManager = - (DevicePolicyManager) context.getSystemService( - Context.DEVICE_POLICY_SERVICE); - if (devicePolicyManager != null && devicePolicyManager.hasDeviceIdentifierAccess( - callingPackage, pid, uid)) { - return true; - } - } return reportAccessDeniedToReadIdentifiers(context, subId, pid, uid, callingPackage, message); } -- cgit v1.2.3-59-g8ed1b