Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45955dc9 authored by Jack Yu's avatar Jack Yu Committed by Android (Google) Code Review
Browse files

Merge "Excluded certain APNs (e.g. IMS) from mobile data usage." into nyc-dev

parents a374c577 8b0a1cbd
Loading
Loading
Loading
Loading
+79 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package com.android.internal.telephony.dataconnection;

import android.content.Context;
import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.text.TextUtils;
@@ -26,6 +29,8 @@ import com.android.internal.telephony.uicc.IccRecords;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;

@@ -34,6 +39,10 @@ import java.util.Locale;
 */
public class ApnSetting {

    static final String LOG_TAG = "ApnSetting";

    private static final boolean DBG = false;

    static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
    static final String V3_FORMAT_REGEX = "^\\[ApnSettingV3\\]\\s*";

@@ -103,6 +112,12 @@ public class ApnSetting {
     * */
    public boolean permanentFailed = false;

    /**
     * Metered APN types which would be accounted for in data usage. This is a map of subId ->
     * set of metered apn strings for the carrier.
     */
    private static HashMap<Integer, HashSet<String>> sMeteredApnTypes = new HashMap<>();

    public ApnSetting(int id, String numeric, String carrier, String apn,
            String proxy, String port,
            String mmsc, String mmsProxy, String mmsPort,
@@ -389,6 +404,70 @@ public class ApnSetting {
        return false;
    }

    public boolean isMetered(Context context, int subId) {

        synchronized (sMeteredApnTypes) {
            HashSet<String> meteredApnSet = sMeteredApnTypes.get(subId);

            // In case of cache miss, we need to look up the settings from carrier config.
            if (meteredApnSet == null) {
                // Retrieve the metered APN types from carrier config
                CarrierConfigManager configManager = (CarrierConfigManager)
                        context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
                if (configManager == null) {
                    Rlog.e(LOG_TAG, "Carrier config service is not available");
                    return true;
                }

                PersistableBundle b = configManager.getConfig(subId);
                if (b == null) {
                    Rlog.e(LOG_TAG, "Can't get the config. subId = " + subId);
                    return true;
                }

                String[] meteredApnTypes = b.getStringArray(
                        CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS);
                if (meteredApnTypes == null) {
                    Rlog.e(LOG_TAG, "KEY_CARRIER_METERED_APN_TYPES_STRINGS is not available. " +
                            "subId = " + subId);
                    return true;
                }

                meteredApnSet = new HashSet<String>(Arrays.asList(meteredApnTypes));
                sMeteredApnTypes.put(subId, meteredApnSet);
            }

            if (DBG) {
                Rlog.d(LOG_TAG, "For subId = " + subId + ", metered APN types are " +
                        Arrays.toString(meteredApnSet.toArray()));
            }

            // If all types of APN are metered, then this APN setting must be metered.
            if (meteredApnSet.contains(PhoneConstants.APN_TYPE_ALL)) {
                if (DBG) Rlog.d(LOG_TAG, "All APN types are metered.");
                return true;
            }

            for (String type : types) {
                // If one of the APN type is metered, then this APN setting is metered.
                if (meteredApnSet.contains(type)) {
                    if (DBG) Rlog.d(LOG_TAG, type + " is metered.");
                    return true;
                } else if (type.equals(PhoneConstants.APN_TYPE_ALL)) {
                    // Assuming no configuration error, if at least one APN type is
                    // metered, then this APN setting is metered.
                    if (meteredApnSet.size() > 0) {
                        if (DBG) Rlog.d(LOG_TAG, "APN_TYPE_ALL APN is metered.");
                        return true;
                    }
                }
            }
        }

        if (DBG) Rlog.d(LOG_TAG, "Not metered. APN = " + toString());
        return false;
    }

    // TODO - if we have this function we should also have hashCode.
    // Also should handle changes in type order and perhaps case-insensitivity
    @Override
+7 −0
Original line number Diff line number Diff line
@@ -884,6 +884,13 @@ public class DataConnection extends StateMachine {
                    default:
                }
            }

            // If none of the APN types associated with this APN setting is metered,
            // then we apply NOT_METERED capability to the network.
            if (!mApnSetting.isMetered(mPhone.getContext(), mPhone.getSubId())) {
                result.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
            }

            result.maybeMarkCapabilitiesRestricted();
        }
        int up = 14;
+1 −0
Original line number Diff line number Diff line
@@ -467,6 +467,7 @@ public class ContextFixture implements TestFixture<Context> {
        }).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), anyInt());

        doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
        doReturn(mBundle).when(mCarrierConfigManager).getConfig(anyInt());

        mConfiguration.locale = Locale.US;
        doReturn(mConfiguration).when(mResources).getConfiguration();
+199 −18
Original line number Diff line number Diff line
@@ -16,25 +16,77 @@

package com.android.internal.telephony.dataconnection;

import android.os.PersistableBundle;
import android.telephony.CarrierConfigManager;
import android.test.suitebuilder.annotation.SmallTest;

import com.android.internal.telephony.dataconnection.ApnSetting;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyTest;

import junit.framework.TestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

public class ApnSettingTest extends TestCase {
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import static org.junit.Assert.assertEquals;

    public static void assertApnSettingsEqual(List<ApnSetting> a1, List<ApnSetting> a2) {
public class ApnSettingTest extends TelephonyTest {

    private PersistableBundle mBundle;

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
        mBundle = mContextFixture.getCarrierConfigBundle();
    }

    @After
    public void tearDown() throws Exception {
        super.tearDown();
    }

    private ApnSetting createApnSetting(String[] apnTypes) {
        return new ApnSetting(
                2163,                   // id
                "44010",                // numeric
                "sp-mode",              // name
                "spmode.ne.jp",         // apn
                "",                     // proxy
                "",                     // port
                "",                     // mmsc
                "",                     // mmsproxy
                "",                     // mmsport
                "",                     // user
                "",                     // password
                -1,                     // authtype
                apnTypes,               // types
                "IP",                   // protocol
                "IP",                   // roaming_protocol
                true,                   // carrier_enabled
                0,                      // bearer
                0,                      // bearer_bitmask
                0,                      // profile_id
                false,                  // modem_cognitive
                0,                      // max_conns
                0,                      // wait_time
                0,                      // max_conns_time
                0,                      // mtu
                "",                     // mvno_type
                "");                    // mnvo_match_data
    }

    private static void assertApnSettingsEqual(List<ApnSetting> a1, List<ApnSetting> a2) {
        assertEquals(a1.size(), a2.size());
        for (int i = 0; i < a1.size(); ++i) {
            assertApnSettingEqual(a1.get(i), a2.get(i));
        }
    }

    public static void assertApnSettingEqual(ApnSetting a1, ApnSetting a2) {
    private static void assertApnSettingEqual(ApnSetting a1, ApnSetting a2) {
        assertEquals(a1.carrier, a2.carrier);
        assertEquals(a1.apn, a2.apn);
        assertEquals(a1.proxy, a2.proxy);
@@ -66,6 +118,7 @@ public class ApnSettingTest extends TestCase {
        assertEquals(a1.mvnoMatchData, a2.mvnoMatchData);
    }

    @Test
    @SmallTest
    public void testFromString() throws Exception {
        String[] dunTypes = {"DUN"};
@@ -113,6 +166,7 @@ public class ApnSettingTest extends TestCase {
        assertEquals(null, ApnSetting.fromString(testString));
    }

    @Test
    @SmallTest
    public void testArrayFromString() throws Exception {
        // Test a multiple v3 string.
@@ -135,6 +189,7 @@ public class ApnSettingTest extends TestCase {
        assertApnSettingsEqual(expectedApns, ApnSetting.arrayFromString(testString));
    }

    @Test
    @SmallTest
    public void testToString() throws Exception {
        String[] types = {"default", "*"};
@@ -147,4 +202,130 @@ public class ApnSettingTest extends TestCase {
                "IPV6, IP, true, 14, 8192, 0, false, 0, 0, 0, 0, , , false";
        assertEquals(expected, apn.toString());
    }

    @Test
    @SmallTest
    public void testIsMetered() throws Exception {
        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS});

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_DEFAULT}).
                isMetered(mContext, 1));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
                isMetered(mContext, 1));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_MMS}).
                isMetered(mContext, 1));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_MMS, PhoneConstants.APN_TYPE_SUPL}).
                isMetered(mContext, 1));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_DUN}).
                isMetered(mContext, 1));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_ALL}).
                isMetered(mContext, 1));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_SUPL}).
                isMetered(mContext, 1));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_CBS}).
                isMetered(mContext, 1));
    }

    @Test
    @SmallTest
    public void testIsMeteredAnother() throws Exception {
        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS});

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_CBS}).
                isMetered(mContext, 2));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_SUPL}).
                isMetered(mContext, 2));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_CBS}).
                isMetered(mContext, 2));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
                isMetered(mContext, 2));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_SUPL, PhoneConstants.APN_TYPE_IA}).
                isMetered(mContext, 2));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_ALL}).
                isMetered(mContext, 2));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_IMS}).
                isMetered(mContext, 2));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_IMS}).
                isMetered(mContext, 2));

    }

    @Test
    @SmallTest
    public void testIsMeteredNothingCharged() throws Exception {
        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                new String[]{});

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_IMS}).
                isMetered(mContext, 3));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_IMS, PhoneConstants.APN_TYPE_MMS}).
                isMetered(mContext, 3));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_FOTA}).
                isMetered(mContext, 3));

        assertFalse(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_ALL}).
                isMetered(mContext, 3));
    }

    @Test
    @SmallTest
    public void testIsMeteredNothingFree() throws Exception {
        mBundle.putStringArray(CarrierConfigManager.KEY_CARRIER_METERED_APN_TYPES_STRINGS,
                new String[]{PhoneConstants.APN_TYPE_ALL});

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_ALL}).
                isMetered(mContext, 4));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_DEFAULT, PhoneConstants.APN_TYPE_MMS}).
                isMetered(mContext, 4));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_FOTA, PhoneConstants.APN_TYPE_CBS}).
                isMetered(mContext, 4));

        assertTrue(createApnSetting(
                new String[]{PhoneConstants.APN_TYPE_IA, PhoneConstants.APN_TYPE_DUN}).
                isMetered(mContext, 4));

    }
}
 No newline at end of file