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

Commit 9d1d82ae authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Support data profile merging"

parents 09477d88 0cf98f3e
Loading
Loading
Loading
Loading
+111 −0
Original line number Diff line number Diff line
@@ -253,6 +253,8 @@ public class DataProfileManager extends Handler {
            log("Added default EIMS data profile.");
        }

        dedupeDataProfiles(profiles);

        log("Found " + profiles.size() + " data profiles. profiles = " + profiles);

        boolean profilesChanged = false;
@@ -695,6 +697,115 @@ public class DataProfileManager extends Handler {
        return dataProfile.equals(mPreferredDataProfile);
    }

    /**
     * Dedupe the similar data profiles.
     */
    private void dedupeDataProfiles(@NonNull List<DataProfile> dataProfiles) {
        int i = 0;
        while (i < dataProfiles.size() - 1) {
            DataProfile first = dataProfiles.get(i);
            int j = i + 1;
            while (j < dataProfiles.size()) {
                DataProfile second = dataProfiles.get(j);
                DataProfile merged = mergeDataProfiles(first, second);
                if (merged != null) {
                    log("Created a merged profile " + merged + " from " + first + " and "
                            + second);
                    loge("Merging data profiles will not be supported anymore. Please "
                            + "directly configure the merged profile " + merged + " in the APN "
                            + "config.");
                    dataProfiles.set(i, merged);
                    dataProfiles.remove(j);
                } else {
                    j++;
                }
            }
            i++;
        }
    }

    /**
     * Merge two data profiles if possible.
     *
     * @param dp1 Data profile 1 to be merged.
     * @param dp2 Data profile 2 to be merged.
     *
     * @return The merged data profile. {@code null} if merging is not possible.
     */
    private static @Nullable DataProfile mergeDataProfiles(
            @NonNull DataProfile dp1, @NonNull DataProfile dp2) {
        Objects.requireNonNull(dp1);
        Objects.requireNonNull(dp2);

        // We don't merge data profiles that have different traffic descriptor.
        if (!Objects.equals(dp1.getTrafficDescriptor(), dp2.getTrafficDescriptor())) return null;

        // If one of the APN setting is null, we don't merge.
        if (dp1.getApnSetting() == null || dp2.getApnSetting() == null) return null;

        // If two APN settings are not similar, we don't merge.
        if (!dp1.getApnSetting().similar(dp2.getApnSetting())) return null;

        // Start to merge APN setting 1 and 2.
        ApnSetting apn1 = dp1.getApnSetting();
        ApnSetting apn2 = dp2.getApnSetting();
        ApnSetting.Builder apnBuilder = new ApnSetting.Builder();

        // Special handling id and entry name. We want to keep the default APN as it could be the
        // preferred APN.
        apnBuilder.setId(apn1.getId());
        apnBuilder.setEntryName(apn1.getEntryName());
        if (apn2.canHandleType(ApnSetting.TYPE_DEFAULT)
                && !apn1.canHandleType(ApnSetting.TYPE_DEFAULT)) {
            apnBuilder.setId(apn2.getId());
            apnBuilder.setEntryName(apn2.getEntryName());
        }

        // Merge the following fields from apn1 and apn2.
        apnBuilder.setProxyAddress(TextUtils.isEmpty(apn2.getProxyAddressAsString())
                ? apn1.getProxyAddressAsString() : apn2.getProxyAddressAsString());
        apnBuilder.setProxyPort(apn2.getProxyPort() == -1
                ? apn1.getProxyPort() : apn2.getProxyPort());
        apnBuilder.setMmsc(apn2.getMmsc() == null ? apn1.getMmsc() : apn2.getMmsc());
        apnBuilder.setMmsProxyAddress(TextUtils.isEmpty(apn2.getMmsProxyAddressAsString())
                ? apn1.getMmsProxyAddressAsString() : apn2.getMmsProxyAddressAsString());
        apnBuilder.setMmsProxyPort(apn2.getMmsProxyPort() == -1
                ? apn1.getMmsProxyPort() : apn2.getMmsProxyPort());
        apnBuilder.setUser(TextUtils.isEmpty(apn2.getUser()) ? apn1.getUser() : apn2.getUser());
        apnBuilder.setPassword(TextUtils.isEmpty(apn2.getPassword())
                ? apn1.getPassword() : apn2.getPassword());
        apnBuilder.setAuthType(apn2.getAuthType() == -1
                ? apn1.getAuthType() : apn2.getAuthType());
        apnBuilder.setApnTypeBitmask(apn1.getApnTypeBitmask() | apn2.getApnTypeBitmask());
        apnBuilder.setMtuV4(apn2.getMtuV4() == -1 ? apn1.getMtuV4() : apn2.getMtuV4());
        apnBuilder.setMtuV6(apn2.getMtuV6() == -1 ? apn1.getMtuV6() : apn2.getMtuV6());

        // The following fields in apn1 and apn2 should be the same, otherwise ApnSetting.similar()
        // should fail earlier.
        apnBuilder.setApnName(apn1.getApnName());
        apnBuilder.setProtocol(apn1.getProtocol());
        apnBuilder.setRoamingProtocol(apn1.getRoamingProtocol());
        apnBuilder.setCarrierEnabled(apn1.isEnabled());
        apnBuilder.setNetworkTypeBitmask(apn1.getNetworkTypeBitmask());
        apnBuilder.setLingeringNetworkTypeBitmask(apn1.getLingeringNetworkTypeBitmask());
        apnBuilder.setProfileId(apn1.getProfileId());
        apnBuilder.setPersistent(apn1.isPersistent());
        apnBuilder.setMaxConns(apn1.getMaxConns());
        apnBuilder.setWaitTime(apn1.getWaitTime());
        apnBuilder.setMaxConnsTime(apn1.getMaxConnsTime());
        apnBuilder.setMvnoType(apn1.getMvnoType());
        apnBuilder.setMvnoMatchData(apn1.getMvnoMatchData());
        apnBuilder.setApnSetId(apn1.getApnSetId());
        apnBuilder.setCarrierId(apn1.getCarrierId());
        apnBuilder.setSkip464Xlat(apn1.getSkip464Xlat());
        apnBuilder.setAlwaysOn(apn1.isAlwaysOn());

        return new DataProfile.Builder()
                .setApnSetting(apnBuilder.build())
                .setTrafficDescriptor(dp1.getTrafficDescriptor())
                .build();
    }

    /**
     * Register the callback for receiving information from {@link DataProfileManager}.
     *
+132 −3
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.verify;

import android.annotation.NonNull;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.MatrixCursor;
@@ -57,6 +58,8 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
@@ -139,9 +142,9 @@ public class DataProfileManagerTest extends TelephonyTest {
                        0,                      // max_conns
                        0,                      // wait_time
                        0,                      // max_conns_time
                        0,                      // mtu
                        0,                      // mtu_v4
                        0,                      // mtu_v6
                        -1,                     // mtu
                        1280,                   // mtu_v4
                        1280,                   // mtu_v6
                        "",                     // mvno_type
                        "",                     // mnvo_match_data
                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
@@ -254,6 +257,42 @@ public class DataProfileManagerTest extends TelephonyTest {
                        -1,                     // carrier_id
                        -1,                     // skip_464xlat
                        0                       // always_on
                },
                // This APN entry is created to test de-duping.
                new Object[]{
                        5,                      // id
                        PLMN,                   // numeric
                        GENERAL_PURPOSE_APN,    // name
                        GENERAL_PURPOSE_APN,    // apn
                        "",                     // proxy
                        "",                     // port
                        "",                     // mmsc
                        "",                     // mmsproxy
                        "",                     // mmsport
                        "",                     // user
                        "",                     // password
                        -1,                     // authtype
                        "fota",                 // types
                        "IPV4V6",               // protocol
                        "IPV4V6",               // roaming_protocol
                        1,                      // carrier_enabled
                        0,                      // profile_id
                        1,                      // modem_cognitive
                        0,                      // max_conns
                        0,                      // wait_time
                        0,                      // max_conns_time
                        -1,                     // mtu
                        -1,                     // mtu_v4
                        -1,                     // mtu_v6
                        "",                     // mvno_type
                        "",                     // mnvo_match_data
                        TelephonyManager.NETWORK_TYPE_BITMASK_LTE
                                | TelephonyManager.NETWORK_TYPE_BITMASK_NR, // network_type_bitmask
                        0,                      // lingering_network_type_bitmask
                        0,                      // apn_set_id
                        -1,                     // carrier_id
                        -1,                     // skip_464xlat
                        0                       // always_on
                }
        );

@@ -352,6 +391,14 @@ public class DataProfileManagerTest extends TelephonyTest {
        return true;
    }

    private void dedupeDataProfiles(@NonNull List<DataProfile> dataProfiles) throws Exception {
        Class[] cArgs = new Class[1];
        cArgs[0] = List.class;
        Method method = DataProfileManager.class.getDeclaredMethod("dedupeDataProfiles", cArgs);
        method.setAccessible(true);
        method.invoke(mDataProfileManagerUT, dataProfiles);
    }

    @Before
    public void setUp() throws Exception {
        logd("DataProfileManagerTest +Setup!");
@@ -615,4 +662,86 @@ public class DataProfileManagerTest extends TelephonyTest {
                TelephonyManager.NETWORK_TYPE_LTE);
        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(IMS_APN);
    }

    @Test
    public void testDedupeDataProfiles() {
        NetworkRequest request = new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)
                .build();
        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(request, mPhone);
        // This should get the merged data profile after deduping.
        DataProfile dp = mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr,
                TelephonyManager.NETWORK_TYPE_LTE);
        assertThat(dp.canSatisfy(NetworkCapabilities.NET_CAPABILITY_INTERNET)).isTrue();
    }

    @Test
    public void testDedupeDataProfiles2() throws Exception {

        DataProfile dataProfile1 = new DataProfile.Builder()
                .setApnSetting(new ApnSetting.Builder()
                        .setEntryName("general")
                        .setApnName("apn")
                        .setApnTypeBitmask(ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS
                                | ApnSetting.TYPE_SUPL | ApnSetting.TYPE_HIPRI)
                        .setUser("user")
                        .setPassword("password")
                        .setAuthType(ApnSetting.AUTH_TYPE_CHAP)
                        .setMmsc(Uri.parse("http://mms-s"))
                        .setMmsProxyAddress("mmsc.proxy")
                        .setMmsProxyPort(8080)
                        .setProtocol(ApnSetting.PROTOCOL_IPV4V6)
                        .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6)
                        .setCarrierEnabled(true)
                        .build())
                .build();

        DataProfile dataProfile2 = new DataProfile.Builder()
                .setApnSetting(new ApnSetting.Builder()
                        .setEntryName("XCAP")
                        .setApnName("apn")
                        .setApnTypeBitmask(ApnSetting.TYPE_XCAP)
                        .setUser("user")
                        .setPassword("password")
                        .setAuthType(ApnSetting.AUTH_TYPE_CHAP)
                        .setProtocol(ApnSetting.PROTOCOL_IPV4V6)
                        .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6)
                        .setCarrierEnabled(true)
                        .build())
                .build();

        logd("apn1=" + dataProfile1.getApnSetting());
        logd("apn2=" + dataProfile2.getApnSetting());
        logd("apn1 can handle default=" + dataProfile1.getApnSetting()
                .canHandleType(ApnSetting.TYPE_DEFAULT));
        logd("apn2 can handle default=" + dataProfile2.getApnSetting()
                .canHandleType(ApnSetting.TYPE_DEFAULT));
        assertThat(dataProfile1.getApnSetting().similar(dataProfile2.getApnSetting())).isTrue();

        List<DataProfile> dataProfiles = new ArrayList<>(Arrays.asList(dataProfile2, dataProfile1));

        dedupeDataProfiles(dataProfiles);
        // After deduping, there should be only one.
        assertThat(dataProfiles).hasSize(1);

        DataProfile dataProfile = dataProfiles.get(0);
        assertThat(dataProfile.getApnSetting()).isNotNull();

        logd("Merged profile=" + dataProfile);
        assertThat(dataProfile.getApnSetting().getEntryName()).isEqualTo("general");
        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo("apn");
        assertThat(dataProfile.getApnSetting().getApnTypeBitmask()).isEqualTo(
                ApnSetting.TYPE_DEFAULT | ApnSetting.TYPE_MMS | ApnSetting.TYPE_SUPL
                        | ApnSetting.TYPE_HIPRI | ApnSetting.TYPE_XCAP);
        assertThat(dataProfile.getApnSetting().getUser()).isEqualTo("user");
        assertThat(dataProfile.getApnSetting().getPassword()).isEqualTo("password");
        assertThat(dataProfile.getApnSetting().getAuthType()).isEqualTo(ApnSetting.AUTH_TYPE_CHAP);
        assertThat(dataProfile.getApnSetting().getMmsc()).isEqualTo(Uri.parse("http://mms-s"));
        assertThat(dataProfile.getApnSetting().getMmsProxyAddressAsString())
                .isEqualTo("mmsc.proxy");
        assertThat(dataProfile.getApnSetting().getMmsProxyPort()).isEqualTo(8080);
        assertThat(dataProfile.getApnSetting().getProtocol()).isEqualTo(ApnSetting.PROTOCOL_IPV4V6);
        assertThat(dataProfile.getApnSetting().getRoamingProtocol())
                .isEqualTo(ApnSetting.PROTOCOL_IPV4V6);
    }
}