Why would sendTextMessage require READ_PHONE_STATE

2019-04-06 07:49发布

问题:

My app sent home this stack trace which seems as though something very wrong is going on under the hood.

phone_model=SKY IM-A630K, android_version=2.1-update1

java.lang.SecurityException: Requires READ_PHONE_STATE: Neither user 10089 nor current process has android.permission.READ_PHONE_STATE.

   at android.os.Parcel.readException(Parcel.java:1218)
   at android.os.Parcel.readException(Parcel.java:1206)
   at com.android.internal.telephony.IPhoneSubInfo$Stub$Proxy.getLine1Number(IPhoneSubInfo.java:223)
   at android.telephony.TelephonyManager.getLine1Number(TelephonyManager.java:764)
   at android.telephony.SmsManager.sendTextMessage(SmsManager.java:129)
   at android.telephony.SmsManager.sendTextMessage(SmsManager.java:108)
   at com.emergency.button.SMSSender.safeSendSMS(SMSSender.java:91)
   at com.emergency.button.EmergencyActivity$EmergencyThread.sendSMS(EmergencyActivity.java:294)
   at com.emergency.button.EmergencyActivity$EmergencyThread.sendMessages(EmergencyActivity.java:386)
   at com.emergency.button.EmergencyActivity$EmergencyThread.run(EmergencyActivity.java:266)

So should I just catch any and all exceptions around sendTextMessage? Who's fault is this?

回答1:

My app sent home this stack trace which seems as though something very wrong is going on under the hood.

The way you say this, I assume this is the first time you've seen this problem and it doesn't happen on other phones.

Is it possible that in the Android implementation on this phone model, the SmsManager attempts to check the phone 'state' before attempting to send an SMS message. That's purely a guess but it doesn't seem an unreasonable thing to do although the Telephony API docs for SMS Manager don't mention it. Maybe not, I'm not sure.

As sending an SMS message is quite critical in your app, then yes you should certainly be doing all you can to catch any exceptions possibly related to sending the messae (and recovering from the exception state if possible).

As it seems this particular problem cannot be recovered from, why not declare uses-permission for READ_PHONE_STATE into your manifest?



回答2:

I now see that in Lollipop (API 21), even using a benign function like SmsManager.getDefault().divideMessage(String) - requires the READ_PHONE_STATE permission. I am sure that it was not required before, and that it is an OS issue, since I tested it on Nexus 5 devices before, and after upgrade to Lollipop. Before, when running KitKat, SMS worked just fine without the READ_PHONE_STATE permission. And after, it was required.

The reason is that, I guess, telephony functions try to make wise decisions about, well, everything. So a simple task like splitting an SMS (not even sending it) runs all the way to the SmsManager to query it about the phone state.

I think it is a design bug. And as you said above, it can, and should scare users. Why on earth do they have so many ambiguous permissions on Android?

This is my stack trace, just for fun:

java.lang.SecurityException: Requires READ_PHONE_STATE: Neither user 10078 nor current process has android.permission.READ_PHONE_STATE.
at android.os.Parcel.readException(Parcel.java:1540)
at android.os.Parcel.readException(Parcel.java:1493)
at com.android.internal.telephony.IPhoneSubInfo$Stub$Proxy.getGroupIdLevel1(IPhoneSubInfo.java:465)
at android.telephony.TelephonyManager.getGroupIdLevel1(TelephonyManager.java:1666)
at android.telephony.SmsMessage.hasEmsSupport(SmsMessage.java:776)
at com.android.internal.telephony.gsm.SmsMessage.calculateLength(SmsMessage.java:808)
at android.telephony.SmsMessage.fragmentText(SmsMessage.java:322)
at android.telephony.SmsManager.divideMessage(SmsManager.java:328)
at mobi.chatfish.utils.CFCommunications.sendSMSDirect(CFCommunications.java:138)


回答3:

I had the same problem with an HTC phone (Desire 728G) Dual Sim and I had to include "READ_PHONE_STATE" but now Google is asking for a privacy policy, and because I am too lazy to do it :) I did some research and I found a better way without the use of "READ_PHONE_STATE". The problem is that some devices (mainly dual sim) need the "READ_PHONE_STATE" permission to look for the default "SubscriptionId" that is what happens when you call "SmsManager.getDefault()". Below is the code I am using to avoid this issue by assigning the value (1) to SubscriptionId if any exception accrued:

            SmsManager smsManager = SmsManager.getDefault();

            if (android.os.Build.VERSION.SDK_INT >= 22){
                Log.e("Alert","Checking SubscriptionId");
            try {
                Log.e("Alert","SubscriptionId is " + smsManager.getSubscriptionId());
            } catch (Exception e) {
                Log.e("Alert",e.getMessage());
                Log.e("Alert","Fixed SubscriptionId to 1");
                smsManager = SmsManager.getSmsManagerForSubscriptionId(1);
            }
            }

            smsManager.sendTextMessage(mobileNumber, null, msgStr, null, null);