Loading core/java/android/permission/ILegacyPermissionManager.aidl +5 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,11 @@ import android.permission.IOnPermissionsChangeListener; * @hide */ interface ILegacyPermissionManager { int checkDeviceIdentifierAccess(String packageName, String callingFeatureId, String message, int pid, int uid); int checkDeviceIdentifierAccess(String packageName, String message, String callingFeatureId, int pid, int uid); int checkPhoneNumberAccess(String packageName, String message, String callingFeatureId, int pid, int uid); void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId); Loading core/java/android/permission/LegacyPermissionManager.java +30 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,36 @@ public final class LegacyPermissionManager { } } /** * Checks whether the package with the given pid/uid can read the device phone number. * * @param packageName the name of the package to be checked for phone number access * @param message the message to be used for logging during phone number 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 <ul> * <li>{@link PackageManager#PERMISSION_GRANTED} if the package is allowed phone number * access</li> * <li>{@link android.app.AppOpsManager#MODE_IGNORED} if the package does not have phone * number access but for appcompat reasons this should be a silent failure (ie return empty * or null data)</li> * <li>{@link PackageManager#PERMISSION_DENIED} if the package does not have phone number * access</li> * </ul> * @hide */ public int checkPhoneNumberAccess(@Nullable String packageName, @Nullable String message, @Nullable String callingFeatureId, int pid, int uid) { try { return mLegacyPermissionManager.checkPhoneNumberAccess(packageName, message, callingFeatureId, pid, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Grant default permissions to currently active LUI app * @param packageName The package name for the LUI app Loading services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java +118 −13 Original line number Diff line number Diff line Loading @@ -21,9 +21,11 @@ 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; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Build; import android.os.Process; import android.os.ServiceManager; import android.os.UserHandle; Loading Loading @@ -87,19 +89,7 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu @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); } verifyCallerCanCheckAccess(packageName, message, pid, uid); // Allow system and root access to the device identifiers. final int appId = UserHandle.getAppId(uid); if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { Loading Loading @@ -137,6 +127,110 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu return PackageManager.PERMISSION_DENIED; } @Override public int checkPhoneNumberAccess(@Nullable String packageName, @Nullable String message, @Nullable String callingFeatureId, int pid, int uid) { verifyCallerCanCheckAccess(packageName, message, pid, uid); if (mInjector.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid) == PackageManager.PERMISSION_GRANTED) { // Skip checking for runtime permission since caller has privileged permission return PackageManager.PERMISSION_GRANTED; } // if the packageName is null then just return now as the rest of the checks require a // valid package name. if (packageName == null) { return PackageManager.PERMISSION_DENIED; } // If the target SDK version is below R then also check for READ_PHONE_STATE; prior to R // the phone number was accessible with the READ_PHONE_STATE permission granted. boolean preR = false; int result = PackageManager.PERMISSION_DENIED; try { ApplicationInfo info = mInjector.getApplicationInfo(packageName, uid); preR = info.targetSdkVersion <= Build.VERSION_CODES.Q; } catch (PackageManager.NameNotFoundException nameNotFoundException) { } if (preR) { // For target SDK < R if the READ_PHONE_STATE permission is granted but the appop // is not granted then the caller should receive null / empty data instead of a // potentially crashing SecurityException. Save the result of the READ_PHONE_STATE // permission / appop check; if both do not pass then first check if the app meets // any of the other requirements for access, if not then return the result of this // check. result = checkPermissionAndAppop(packageName, android.Manifest.permission.READ_PHONE_STATE, AppOpsManager.OPSTR_READ_PHONE_STATE, callingFeatureId, message, pid, uid); if (result == PackageManager.PERMISSION_GRANTED) { return result; } } // Default SMS app can always read it. if (checkPermissionAndAppop(packageName, null, AppOpsManager.OPSTR_WRITE_SMS, callingFeatureId, message, pid, uid) == PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } // Can be read with READ_PHONE_NUMBERS too. if (checkPermissionAndAppop(packageName, android.Manifest.permission.READ_PHONE_NUMBERS, AppOpsManager.OPSTR_READ_PHONE_NUMBERS, callingFeatureId, message, pid, uid) == PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } // Can be read with READ_SMS too. if (checkPermissionAndAppop(packageName, android.Manifest.permission.READ_SMS, AppOpsManager.OPSTR_READ_SMS, callingFeatureId, message, pid, uid) == PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } return result; } private void verifyCallerCanCheckAccess(String packageName, String message, 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 access for package %s (uid=%d, pid=%d): %s", callingUid, callingPid, packageName, uid, pid, message); Log.w(TAG, response); throw new SecurityException(response); } } /** * Returns whether the specified {@code packageName} with {@code pid} and {@code uid} has been * granted the provided {@code permission} and {@code appop}, using the {@code callingFeatureId} * and {@code message} for the {@link * AppOpsManager#noteOpNoThrow(int, int, String, String, String)} call. * @return <ul> * <li>{@link PackageManager#PERMISSION_GRANTED} if both the permission and the appop * are granted to the package</li> * <li>{@link android.app.AppOpsManager#MODE_IGNORED} if the permission is granted to the * package but the appop is not</li> * <li>{@link PackageManager#PERMISSION_DENIED} if the permission is not granted to the * package</li> * </ul> */ private int checkPermissionAndAppop(String packageName, String permission, String appop, String callingFeatureId, String message, int pid, int uid) { if (permission != null) { if (mInjector.checkPermission(permission, pid, uid) != PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_DENIED; } } AppOpsManager appOpsManager = (AppOpsManager) mInjector.getSystemService( Context.APP_OPS_SERVICE); if (appOpsManager.noteOpNoThrow(appop, uid, packageName, callingFeatureId, message) != AppOpsManager.MODE_ALLOWED) { return AppOpsManager.MODE_IGNORED; } return PackageManager.PERMISSION_GRANTED; } @Override public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); Loading Loading @@ -348,5 +442,16 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu public Object getSystemService(@NonNull String name) { return mContext.getSystemService(name); } /** * Returns the {@link ApplicationInfo} for the specified {@code packageName} under the * provided {@code uid}. */ public ApplicationInfo getApplicationInfo(@Nullable String packageName, int uid) throws PackageManager.NameNotFoundException { return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, UserHandle.getUserHandleForUid(uid)); } } } services/tests/servicestests/src/com/android/server/pm/permission/LegacyPermissionManagerServiceTest.java +218 −15 File changed.Preview size limit exceeded, changes collapsed. Show changes telephony/common/com/android/internal/telephony/TelephonyPermissions.java +14 −53 Original line number Diff line number Diff line Loading @@ -482,64 +482,25 @@ public final class TelephonyPermissions { public static boolean checkReadPhoneNumber( Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { // First, check if the SDK version is below R boolean preR = false; try { ApplicationInfo info = context.getPackageManager().getApplicationInfoAsUser( callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid())); preR = info.targetSdkVersion <= Build.VERSION_CODES.Q; } catch (PackageManager.NameNotFoundException nameNotFoundException) { } if (preR) { // SDK < R allows READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier privilege try { return checkReadPhoneState( context, subId, pid, uid, callingPackage, callingFeatureId, message); } catch (SecurityException readPhoneStateException) { } } else { // SDK >= R allows READ_PRIVILEGED_PHONE_STATE or carrier privilege try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); // Skip checking for runtime permission since caller has privileged permission return true; } catch (SecurityException readPrivilegedPhoneStateException) { if (SubscriptionManager.isValidSubscriptionId(subId)) { try { enforceCarrierPrivilege(context, subId, uid, message); // Skip checking for runtime permission since caller has carrier privilege return true; } catch (SecurityException carrierPrivilegeException) { } } } } // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { LegacyPermissionManager permissionManager = (LegacyPermissionManager) context.getSystemService(Context.LEGACY_PERMISSION_SERVICE); // Apps with target SDK version < R can have the READ_PHONE_STATE permission granted with // the appop denied. If PERMISSION_GRANTED is not received then check if the caller has // carrier privileges; if not and the permission result is MODE_IGNORED then return false // to return null data to the caller. int permissionResult = permissionManager.checkPhoneNumberAccess(callingPackage, message, callingFeatureId, pid, uid); if (permissionResult == PackageManager.PERMISSION_GRANTED) { return true; } // Can be read with READ_SMS too. try { context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message); if (appOps.noteOp(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { if (SubscriptionManager.isValidSubscriptionId(subId)) { if (TelephonyPermissions.getCarrierPrivilegeStatus(context, subId, uid) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; } } catch (SecurityException readSmsSecurityException) { } // Can be read with READ_PHONE_NUMBERS too. try { context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid, message); if (appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { return true; } } catch (SecurityException readPhoneNumberSecurityException) { if (permissionResult == AppOpsManager.MODE_IGNORED) { return false; } throw new SecurityException(message + ": Neither user " + uid Loading Loading
core/java/android/permission/ILegacyPermissionManager.aidl +5 −1 Original line number Diff line number Diff line Loading @@ -30,7 +30,11 @@ import android.permission.IOnPermissionsChangeListener; * @hide */ interface ILegacyPermissionManager { int checkDeviceIdentifierAccess(String packageName, String callingFeatureId, String message, int pid, int uid); int checkDeviceIdentifierAccess(String packageName, String message, String callingFeatureId, int pid, int uid); int checkPhoneNumberAccess(String packageName, String message, String callingFeatureId, int pid, int uid); void grantDefaultPermissionsToEnabledCarrierApps(in String[] packageNames, int userId); Loading
core/java/android/permission/LegacyPermissionManager.java +30 −0 Original line number Diff line number Diff line Loading @@ -89,6 +89,36 @@ public final class LegacyPermissionManager { } } /** * Checks whether the package with the given pid/uid can read the device phone number. * * @param packageName the name of the package to be checked for phone number access * @param message the message to be used for logging during phone number 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 <ul> * <li>{@link PackageManager#PERMISSION_GRANTED} if the package is allowed phone number * access</li> * <li>{@link android.app.AppOpsManager#MODE_IGNORED} if the package does not have phone * number access but for appcompat reasons this should be a silent failure (ie return empty * or null data)</li> * <li>{@link PackageManager#PERMISSION_DENIED} if the package does not have phone number * access</li> * </ul> * @hide */ public int checkPhoneNumberAccess(@Nullable String packageName, @Nullable String message, @Nullable String callingFeatureId, int pid, int uid) { try { return mLegacyPermissionManager.checkPhoneNumberAccess(packageName, message, callingFeatureId, pid, uid); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** * Grant default permissions to currently active LUI app * @param packageName The package name for the LUI app Loading
services/core/java/com/android/server/pm/permission/LegacyPermissionManagerService.java +118 −13 Original line number Diff line number Diff line Loading @@ -21,9 +21,11 @@ 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; import android.content.pm.PackageManagerInternal; import android.os.Binder; import android.os.Build; import android.os.Process; import android.os.ServiceManager; import android.os.UserHandle; Loading Loading @@ -87,19 +89,7 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu @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); } verifyCallerCanCheckAccess(packageName, message, pid, uid); // Allow system and root access to the device identifiers. final int appId = UserHandle.getAppId(uid); if (appId == Process.SYSTEM_UID || appId == Process.ROOT_UID) { Loading Loading @@ -137,6 +127,110 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu return PackageManager.PERMISSION_DENIED; } @Override public int checkPhoneNumberAccess(@Nullable String packageName, @Nullable String message, @Nullable String callingFeatureId, int pid, int uid) { verifyCallerCanCheckAccess(packageName, message, pid, uid); if (mInjector.checkPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid) == PackageManager.PERMISSION_GRANTED) { // Skip checking for runtime permission since caller has privileged permission return PackageManager.PERMISSION_GRANTED; } // if the packageName is null then just return now as the rest of the checks require a // valid package name. if (packageName == null) { return PackageManager.PERMISSION_DENIED; } // If the target SDK version is below R then also check for READ_PHONE_STATE; prior to R // the phone number was accessible with the READ_PHONE_STATE permission granted. boolean preR = false; int result = PackageManager.PERMISSION_DENIED; try { ApplicationInfo info = mInjector.getApplicationInfo(packageName, uid); preR = info.targetSdkVersion <= Build.VERSION_CODES.Q; } catch (PackageManager.NameNotFoundException nameNotFoundException) { } if (preR) { // For target SDK < R if the READ_PHONE_STATE permission is granted but the appop // is not granted then the caller should receive null / empty data instead of a // potentially crashing SecurityException. Save the result of the READ_PHONE_STATE // permission / appop check; if both do not pass then first check if the app meets // any of the other requirements for access, if not then return the result of this // check. result = checkPermissionAndAppop(packageName, android.Manifest.permission.READ_PHONE_STATE, AppOpsManager.OPSTR_READ_PHONE_STATE, callingFeatureId, message, pid, uid); if (result == PackageManager.PERMISSION_GRANTED) { return result; } } // Default SMS app can always read it. if (checkPermissionAndAppop(packageName, null, AppOpsManager.OPSTR_WRITE_SMS, callingFeatureId, message, pid, uid) == PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } // Can be read with READ_PHONE_NUMBERS too. if (checkPermissionAndAppop(packageName, android.Manifest.permission.READ_PHONE_NUMBERS, AppOpsManager.OPSTR_READ_PHONE_NUMBERS, callingFeatureId, message, pid, uid) == PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } // Can be read with READ_SMS too. if (checkPermissionAndAppop(packageName, android.Manifest.permission.READ_SMS, AppOpsManager.OPSTR_READ_SMS, callingFeatureId, message, pid, uid) == PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_GRANTED; } return result; } private void verifyCallerCanCheckAccess(String packageName, String message, 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 access for package %s (uid=%d, pid=%d): %s", callingUid, callingPid, packageName, uid, pid, message); Log.w(TAG, response); throw new SecurityException(response); } } /** * Returns whether the specified {@code packageName} with {@code pid} and {@code uid} has been * granted the provided {@code permission} and {@code appop}, using the {@code callingFeatureId} * and {@code message} for the {@link * AppOpsManager#noteOpNoThrow(int, int, String, String, String)} call. * @return <ul> * <li>{@link PackageManager#PERMISSION_GRANTED} if both the permission and the appop * are granted to the package</li> * <li>{@link android.app.AppOpsManager#MODE_IGNORED} if the permission is granted to the * package but the appop is not</li> * <li>{@link PackageManager#PERMISSION_DENIED} if the permission is not granted to the * package</li> * </ul> */ private int checkPermissionAndAppop(String packageName, String permission, String appop, String callingFeatureId, String message, int pid, int uid) { if (permission != null) { if (mInjector.checkPermission(permission, pid, uid) != PackageManager.PERMISSION_GRANTED) { return PackageManager.PERMISSION_DENIED; } } AppOpsManager appOpsManager = (AppOpsManager) mInjector.getSystemService( Context.APP_OPS_SERVICE); if (appOpsManager.noteOpNoThrow(appop, uid, packageName, callingFeatureId, message) != AppOpsManager.MODE_ALLOWED) { return AppOpsManager.MODE_IGNORED; } return PackageManager.PERMISSION_GRANTED; } @Override public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) { final int callingUid = Binder.getCallingUid(); Loading Loading @@ -348,5 +442,16 @@ public class LegacyPermissionManagerService extends ILegacyPermissionManager.Stu public Object getSystemService(@NonNull String name) { return mContext.getSystemService(name); } /** * Returns the {@link ApplicationInfo} for the specified {@code packageName} under the * provided {@code uid}. */ public ApplicationInfo getApplicationInfo(@Nullable String packageName, int uid) throws PackageManager.NameNotFoundException { return mContext.getPackageManager().getApplicationInfoAsUser(packageName, 0, UserHandle.getUserHandleForUid(uid)); } } }
services/tests/servicestests/src/com/android/server/pm/permission/LegacyPermissionManagerServiceTest.java +218 −15 File changed.Preview size limit exceeded, changes collapsed. Show changes
telephony/common/com/android/internal/telephony/TelephonyPermissions.java +14 −53 Original line number Diff line number Diff line Loading @@ -482,64 +482,25 @@ public final class TelephonyPermissions { public static boolean checkReadPhoneNumber( Context context, int subId, int pid, int uid, String callingPackage, @Nullable String callingFeatureId, String message) { // First, check if the SDK version is below R boolean preR = false; try { ApplicationInfo info = context.getPackageManager().getApplicationInfoAsUser( callingPackage, 0, UserHandle.getUserHandleForUid(Binder.getCallingUid())); preR = info.targetSdkVersion <= Build.VERSION_CODES.Q; } catch (PackageManager.NameNotFoundException nameNotFoundException) { } if (preR) { // SDK < R allows READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, or carrier privilege try { return checkReadPhoneState( context, subId, pid, uid, callingPackage, callingFeatureId, message); } catch (SecurityException readPhoneStateException) { } } else { // SDK >= R allows READ_PRIVILEGED_PHONE_STATE or carrier privilege try { context.enforcePermission( android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, pid, uid, message); // Skip checking for runtime permission since caller has privileged permission return true; } catch (SecurityException readPrivilegedPhoneStateException) { if (SubscriptionManager.isValidSubscriptionId(subId)) { try { enforceCarrierPrivilege(context, subId, uid, message); // Skip checking for runtime permission since caller has carrier privilege return true; } catch (SecurityException carrierPrivilegeException) { } } } } // Default SMS app can always read it. AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); if (appOps.noteOp(AppOpsManager.OPSTR_WRITE_SMS, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { LegacyPermissionManager permissionManager = (LegacyPermissionManager) context.getSystemService(Context.LEGACY_PERMISSION_SERVICE); // Apps with target SDK version < R can have the READ_PHONE_STATE permission granted with // the appop denied. If PERMISSION_GRANTED is not received then check if the caller has // carrier privileges; if not and the permission result is MODE_IGNORED then return false // to return null data to the caller. int permissionResult = permissionManager.checkPhoneNumberAccess(callingPackage, message, callingFeatureId, pid, uid); if (permissionResult == PackageManager.PERMISSION_GRANTED) { return true; } // Can be read with READ_SMS too. try { context.enforcePermission(android.Manifest.permission.READ_SMS, pid, uid, message); if (appOps.noteOp(AppOpsManager.OPSTR_READ_SMS, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { if (SubscriptionManager.isValidSubscriptionId(subId)) { if (TelephonyPermissions.getCarrierPrivilegeStatus(context, subId, uid) == TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) { return true; } } catch (SecurityException readSmsSecurityException) { } // Can be read with READ_PHONE_NUMBERS too. try { context.enforcePermission(android.Manifest.permission.READ_PHONE_NUMBERS, pid, uid, message); if (appOps.noteOp(AppOpsManager.OPSTR_READ_PHONE_NUMBERS, uid, callingPackage, callingFeatureId, null) == AppOpsManager.MODE_ALLOWED) { return true; } } catch (SecurityException readPhoneNumberSecurityException) { if (permissionResult == AppOpsManager.MODE_IGNORED) { return false; } throw new SecurityException(message + ": Neither user " + uid Loading