SecurityException: not allowed to perform OP_READ_PHONE_STATE

AndroidSecurityAndroid PermissionsAndroid 6.0-Marshmallow

Android Problem Overview


User is reporting my app crashes with this error trace

java.lang.SecurityException: com.android.phone from uid 10134 not allowed to perform OP_READ_PHONE_STATE
at android.os.Parcel.readException(Parcel.java:1620)
at android.os.Parcel.readException(Parcel.java:1573)
at com.android.internal.telephony.IPhoneSubInfo$Stub$Proxy.getVoiceMailNumberForSubscriber(IPhoneSubInfo.java:858)
at android.telephony.TelephonyManager.getVoiceMailNumber(TelephonyManager.java:2383)
at android.telephony.TelephonyManager.getVoiceMailNumber(TelephonyManager.java:2366)

So far only one user has reported this problem. Several thousand other users are running this version of the app with no apparent problems.

The exception is thrown when we call TelephonyManager.getVoiceMailNumber(). This operation is documented as required the READ_PHONE_STATE permission, which has absolutely, positively been granted.

I tracked down the OP_READ_PHONE_STATE permission to the android.apps.AppOpsManager class but can not figure out exactly what it is unhappy about.

Can anyone explain just what is happening and what needs to be done to fix things.

Thanks, -Ken

Android Solutions


Solution 1 - Android

Looking for that method in AOSP eventually leads to the cheakReadPhoneState() method.

In Android 6, that method was here.

In both cases, it looks pretty similar. Here's the Android 6 code:

private boolean checkReadPhoneState(String callingPackage, String message) {
    try {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, message);

        // SKIP checking run-time OP_READ_PHONE_STATE since self or using PRIVILEGED
        return true;
    } catch (SecurityException e) {
        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PHONE_STATE,
                message);
    }

    return mAppOps.noteOp(AppOpsManager.OP_READ_PHONE_STATE, Binder.getCallingUid(),
        callingPackage) == AppOpsManager.MODE_ALLOWED;
}

First it checks to see if READ_PRIVILEGED_PHONE_STATE is granted. If it is, then the rest of the code is short-circuited and it returns true. Otherwise, it makes sure that READ_PHONE_STATE is granted, throwing a SecurityException otherwise.

Finally, if READ_PHONE_STATE is granted, it makes sure that OP_READ_PHONE_STATE is also granted. I'm not entirely sure why it's doing that, but that's where the problem is coming from. Whichever devices this error is occurring on have changed something with the way runtime permissions work. When the READ_PHONE_STATE permission is granted, the OP_READ_PHONE_STATE op should also be granted, but the system is revoking that op for whatever reason.

(It's also possible that the user is using an app to manage app-ops and has revoked it manually.)

For fixing it, I don't really think you can. The best you can do is catch the error and ask that users run an ADB command to manually grant the op:

adb shell appops set com.your.packagename READ_PHONE_STATE allow.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionkencorbinView Question on Stackoverflow
Solution 1 - AndroidTheWandererView Answer on Stackoverflow