10

I have a problem reading APNs in Android v4.2 (Yes reading, not writing APNS), it is throwing a security exception:

No permission to write APN settings: Neither user 10068 nor current process has android.permission.WRITE_APN_SETTINGS.

Same code used to work on all previous platforms, does anyone know of any work around to this?

Thanks!

Shatazone
  • 2,220
  • 6
  • 27
  • 36
  • 4
    That sounds like either a bug or a ham-fisted way to secure APN data (should have a dedicated `READ_APN_SETTINGS` permission in that case). I do not see an issue filed for this, so if you can create a project that reproduces the error, post it and instructions to http://b.android.com. – CommonsWare Nov 19 '12 at 12:23
  • 1
    Done, you can check it here http://code.google.com/p/android/issues/detail?id=39987 – Shatazone Nov 19 '12 at 13:04
  • 2
    Also see http://code.google.com/p/android/issues/detail?id=29264. Hopefully the same solution could be applied for both reading and writing APN's. Hopefully before 4.2 gets picked up by the other manufacturers. Call me a dreamer. – Tom Nov 22 '12 at 03:40
  • I put my app in /system/app and I'm still getting this error. Shouldn't this permission be granted to any app in system folder OR signed by OEM? – Miguel Ribeiro May 15 '13 at 09:15

4 Answers4

11

If you want to Read APN for Android 4.2 and more they are a change to do. I tested and it's work.

In Android 4.1 and below use this :

Cursor c = getContentResolver().query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "current"), null, null, null, null);

And for Android 4.2 and above use this code :

private static final String[] APN_PROJECTION = {
     Telephony.Carriers.TYPE,            // 0
     Telephony.Carriers.MMSC,            // 1
     Telephony.Carriers.MMSPROXY,        // 2
     Telephony.Carriers.MMSPORT          // 3
 };

And this line :

final Cursor apnCursor =SqliteWrapper.query(context, this.context.getContentResolver(), Uri.withAppendedPath(Carriers.CONTENT_URI, "current"), APN_PROJECTION, null, null, null);

The SQLiteWrapperClass is hidden (found this class in internet)

import android.database.sqlite.SqliteWrapper;

My English is not quite good, sorry for this.

Nir Duan
  • 5,310
  • 4
  • 20
  • 38
vincent091
  • 2,245
  • 4
  • 15
  • 21
  • Hi. I'm having trouble importing android.provider.Telephony.Carriers even when Android documentation says it's public since API 19. How could I import it? – Narseo Jan 23 '14 at 04:26
  • 2
    In api 19 it's not a problem. The Carriers class is available with this import import android.provider.Telephony; If this not work take the java class in the source code and import into the src folder. – vincent091 Jan 23 '14 at 11:06
  • 1
    I had to update the sdk and then it worked. However, I'm having trouble reading certain fields in addition to the ones you reported using the SqliteWrapper (The first method hasn't worked for me though) Out of the fields reported in http://developer.android.com/reference/android/provider/Telephony.Carriers.html, only the following ones seem be readable: Telephony.Carriers.APN, Telephony.Carriers.MMSPROXY, Telephony.Carriers.MMSPORT, Telephony.Carriers.MMSC, Telephony.Carriers.TYPE Am I missing a permission (I have read_apn_settings) or doing something wrong? – Narseo Jan 23 '14 at 21:04
  • @ashish did you find a solution? – Dakait Aug 12 '14 at 10:15
  • Yuppeerr. This worked. Tested in Samsung Galaxy S4 having 5.0.1. Thanks mate :) :D :D – Hardik Joshi May 28 '15 at 05:26
  • For older devices, see the answer http://stackoverflow.com/questions/7257567/create-network-access-point-name-with-code – Jaco Apr 12 '17 at 12:47
  • Android 11(R) will not allow any APN info read. https://github.com/aosp-mirror/platform_packages_providers_telephonyprovider/commit/5e91108eeafdc37018fff82881a941d6dbb3cb4c?diff=split https://developer.android.com/preview/behavior-changes-11#apn-database-restrictions – Pavel Machala Apr 14 '20 at 15:49
8

This appears to be an intentional change. The git commit where they added this defense includes the following comment:

Since the DB may contain corp passwords, we should secure it. Using the same permission as writing to the DB as the read is potentially as damaging as a write.

It is conceivable that your issue will cause them to consider adding a separate read permission, but at least for the time being, this is a regression in 4.2.

CommonsWare
  • 910,778
  • 176
  • 2,215
  • 2,253
  • What is the alternative for all those application which uses mobile data to perform operations(like sending MMS) and can not get to know what is the default APN setting present in the device? – toobsco42 Feb 28 '13 at 06:38
  • 1
    @toobsco42: Beats me. You may want to open a fresh StackOverflow question, to see if anyone has a solution. – CommonsWare Feb 28 '13 at 12:43
3

You can read default settings from /etc/apns-conf.xml:

private boolean getSettingsFromApnsFile(Context context, String apnName) {
    FileReader reader = null;
    boolean sawValidApn = false;

    try {
        reader = new FileReader("/etc/apns-conf.xml");

        XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
        factory.setNamespaceAware(true);
        XmlPullParser xpp = factory.newPullParser();
        xpp.setInput(reader);

        TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
        String simOperator = telephonyManager.getSimOperator();
        if (TextUtils.isEmpty(simOperator)) {
            logger.warn("unable to get sim operator - so unable to get mms config");
            return false;
        }

        int eventType = xpp.getEventType();
        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG && xpp.getName().equals("apn")) {
                HashMap<String, String> attributes = new HashMap<String, String>();
                for (int i=0; i<xpp.getAttributeCount(); i++) {
                    attributes.put(xpp.getAttributeName(i), xpp.getAttributeValue(i));
                }
                if (attributes.containsKey("mcc") && attributes.containsKey("mnc") && simOperator.equals(attributes.get("mcc")+attributes.get("mnc"))) {
                    if (!TextUtils.isEmpty(apnName) && !apnName.trim().equals(attributes.get("apn"))) {
                        eventType = xpp.next();
                        continue;
                    }

                    if (isValidApnType(attributes.get("type"), PhoneConstants.APN_TYPE_MMS)) {
                        sawValidApn = true;

                        String mmsc = attributes.get("mmsc");
                        if (mmsc == null) {
                            eventType = xpp.next();
                            continue;
                        }

                        mServiceCenter = NetworkUtil.trimV4AddrZeros(mmsc.trim());
                        mProxyAddress = NetworkUtil.trimV4AddrZeros(
                                attributes.get("mmsproxy"));
                        if (isProxySet()) {
                            String portString = attributes.get("mmsport");
                            try {
                                mProxyPort = Integer.parseInt(portString);
                            } catch (NumberFormatException e) {
                                if (TextUtils.isEmpty(portString)) {
                                    logger.warn("mms port not set!");
                                } else {
                                    logger.error("Bad port number format: " + portString, e);
                                }
                            }
                        }
                    }

                }
            }
            eventType = xpp.next();
        }
    } catch (Exception e) {
        logger.warn("unable to get mmsc config from apns-conf file", e);
    } finally {
        if (reader != null) {
            try {
                reader.close();
            } catch (Exception e) {
            }
        }
    }
    return sawValidApn;
}
notz
  • 2,428
  • 2
  • 13
  • 10
  • but this is not part of the sdk, it might not work on all android devices dont you think? – Shatazone Dec 11 '13 at 12:41
  • Yes, now i know that HTC has removed the file at least on one device. – notz Dec 16 '13 at 14:54
  • That's just the list of default APN configurations on Android. As @Shatazone mentions, it's handset dependent – Narseo Jan 23 '14 at 04:34
  • Yes, it is. Configuration is not handset dependent. Only file is different on every ROM (it changes very often in aosp git). It's only a workaround for an android bug. You can also deliver a more up-to-date version within your app. Like we do. – notz Jan 23 '14 at 15:14
-6

I have the situation too, my solution is don't access android_assets in AsyncTask. "Make sure that only your main thread have the permission to access you app's assets dir"

I got the problem when I coding like this:

@Override
protected void onResume() {
    super.onResume();
    //mWebView.loadUrl("file:///android_asset/95306.html");
    new LoadUrlTask().execute("file:///android_asset/95306.html");
}

...

class LoadUrlTask extends AsyncTask<String, Integer , String> {
    // progressDialog = new ProgressDialog(LoadActivity.this);

    @Override
    protected String doInBackground(String... strings) {
        mWebView.loadUrl(strings[0]);
        return "";
    }

    @Override
    protected void onPostExecute(String s) {
        super.onPostExecute(s);
        //progressDialog.dismiss();
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        //progressDialog.setMessage("loading...");
        //progressDialog.show();
    }
}

and I fix it by:

@Override
protected void onResume() {
    super.onResume();
    mWebView.loadUrl("file:///android_asset/95306.html");
    //new LoadUrlTask().execute("file:///android_asset/95306.html");
}

hope that will help you!

  • 3
    How is this supposed to help. Your answer is way out of scope of the question and has nothing to do with accessing APN settings. – ar34z Nov 04 '14 at 08:08