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

Commit a0ca76e4 authored by Jack Yu's avatar Jack Yu
Browse files

Loosed data profile check

1. When APN database changes, if the existing data network's APN name
   is in one of the data profiles from database, do not tear down
   the data network.
2. When modem unthrottle a data profile, only use APN name and traffic
   descriptor to locate the data profile for unthrottling.

Fix: 227151768
Fix: 230727395
Test: Manual testing on live network. atest DataNetworkControllerTest
DataProfileManagerTest DataRetryManagerTest

Change-Id: I57712c2c357f535df0c90ea3fb0c5c3a3c524bbd
parent 8dee0d55
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -1698,8 +1698,12 @@ public class DataNetworkController extends Handler {
        }

        // Check if the data profile is still valid, sometimes the users can remove it from the APN
        // editor.
        if (!mDataProfileManager.isDataProfileValid(dataProfile)) {
        // editor. We use very loose check here because APN id can change after APN reset to
        // default
        if (mDataProfileManager.getDataProfile(
                dataProfile.getApnSetting() != null
                        ? dataProfile.getApnSetting().getApnName() : null,
                dataProfile.getTrafficDescriptor()) == null) {
            evaluation.addDataDisallowedReason(DataDisallowedReason.DATA_PROFILE_INVALID);
        }

+40 −19
Original line number Diff line number Diff line
@@ -422,9 +422,11 @@ public class DataProfileManager extends Handler {
            preferredDataProfile = null;
        }

        for (DataProfile dataProfile : mAllDataProfiles) {
            dataProfile.setPreferred(dataProfile.equals(preferredDataProfile));
        }

        if (!Objects.equals(mPreferredDataProfile, preferredDataProfile)) {
            // Replaced the data profile with preferred bit set.
            if (preferredDataProfile != null) preferredDataProfile.setPreferred(true);
            mPreferredDataProfile = preferredDataProfile;

            logl("Changed preferred data profile to " + mPreferredDataProfile);
@@ -629,23 +631,6 @@ public class DataProfileManager extends Handler {
        return dataProfiles.get(0).getApnSetting();
    }

    /**
     * Check if the data profile is valid. Profiles can change dynamically when users add/remove/
     * switch APNs in APN editors, when SIM refreshes, or when SIM swapped. This is used to check
     * if the data profile which is used for current data network is still valid. If the profile
     * is not valid anymore, the data network should be torn down.
     *
     * @param dataProfile The data profile to check.
     * @return {@code true} if the data profile is still valid for current environment.
     */
    public boolean isDataProfileValid(@NonNull DataProfile dataProfile) {
        return mAllDataProfiles.contains(dataProfile)
                && (dataProfile.getApnSetting() == null
                || dataProfile.getApnSetting().getApnSetId() == mPreferredDataProfileSetId
                || dataProfile.getApnSetting().getApnSetId()
                == Telephony.Carriers.MATCH_ALL_APN_SET_ID);
    }

    /**
     * Check if the data profile is the preferred data profile.
     *
@@ -793,6 +778,42 @@ public class DataProfileManager extends Handler {
                .build();
    }

    /**
     * Get data profile by APN name and/or traffic descriptor.
     *
     * @param apnName APN name.
     * @param trafficDescriptor Traffic descriptor.
     *
     * @return Data profile by APN name and/or traffic descriptor. Either one of APN name or
     * traffic descriptor should be provided. {@code null} if data profile is not found.
     */
    public @Nullable DataProfile getDataProfile(@Nullable String apnName,
            @Nullable TrafficDescriptor trafficDescriptor) {
        if (apnName == null && trafficDescriptor == null) return null;

        List<DataProfile> dataProfiles = mAllDataProfiles;

        // Check if any existing data profile has the same traffic descriptor.
        if (trafficDescriptor != null) {
            dataProfiles = mAllDataProfiles.stream()
                    .filter(dp -> trafficDescriptor.equals(dp.getTrafficDescriptor()))
                    .collect(Collectors.toList());
        }

        // Check if any existing data profile has the same APN name.
        if (apnName != null) {
            dataProfiles = dataProfiles.stream()
                    .filter(dp -> dp.getApnSetting() != null
                            && (dp.getApnSetting().getApnSetId()
                            == Telephony.Carriers.MATCH_ALL_APN_SET_ID
                            || dp.getApnSetting().getApnSetId() == mPreferredDataProfileSetId))
                    .filter(dp -> apnName.equals(dp.getApnSetting().getApnName()))
                    .collect(Collectors.toList());
        }

        return dataProfiles.isEmpty() ? null : dataProfiles.get(0);
    }

    /**
     * Register the callback for receiving information from {@link DataProfileManager}.
     *
+20 −5
Original line number Diff line number Diff line
@@ -1384,15 +1384,30 @@ public class DataRetryManager extends Handler {
     */
    private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn,
            int transport, boolean remove) {
        log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn
                + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)
                + ", remove=" + remove);

        long now = SystemClock.elapsedRealtime();
        List<DataThrottlingEntry> dataUnthrottlingEntries = new ArrayList<>();
        if (dataProfile != null) {
            // For AIDL-based HAL. There should be only one entry containing this data profile.
            // Note that the data profile reconstructed from DataProfileInfo.aidl will not be
            // equal to the data profiles kept in data profile manager (due to some fields missing
            // in DataProfileInfo.aidl), so we need to get the equivalent data profile from data
            // profile manager.
            final DataProfile dp = mDataProfileManager.getDataProfile(
                    dataProfile.getApnSetting() != null
                            ? dataProfile.getApnSetting().getApnName() : null,
                    dataProfile.getTrafficDescriptor());
            log("onDataProfileUnthrottled: getDataProfile=" + dp);
            if (dp != null) {
                dataUnthrottlingEntries = mDataThrottlingEntries.stream()
                        .filter(entry -> entry.expirationTimeMillis > now
                            && entry.dataProfile.equals(dataProfile)
                                && entry.dataProfile.equals(dp)
                                && entry.transport == transport)
                        .collect(Collectors.toList());
            }
        } else if (apn != null) {
            // For HIDL 1.6 or below
            dataUnthrottlingEntries = mDataThrottlingEntries.stream()
+28 −5
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -699,14 +700,16 @@ public class DataNetworkControllerTest extends TelephonyTest {
                linkBandwidthEstimatorCallbackCaptor.capture());
        mLinkBandwidthEstimatorCallback = linkBandwidthEstimatorCallbackCaptor.getValue();

        doAnswer(invocation -> {
            TelephonyNetworkRequest networkRequest =
                    (TelephonyNetworkRequest) invocation.getArguments()[0];
            int networkType = (int) invocation.getArguments()[1];
        List<DataProfile> profiles = List.of(mGeneralPurposeDataProfile,
                mImsCellularDataProfile,
                mImsIwlanDataProfile, mEmergencyDataProfile, mFotaDataProfile,
                mTetheringDataProfile);

        doAnswer(invocation -> {
            TelephonyNetworkRequest networkRequest =
                    (TelephonyNetworkRequest) invocation.getArguments()[0];
            int networkType = (int) invocation.getArguments()[1];

            for (DataProfile dataProfile : profiles) {
                if (dataProfile.canSatisfy(networkRequest.getCapabilities())
                        && (dataProfile.getApnSetting().getNetworkTypeBitmask() == 0
@@ -724,7 +727,27 @@ public class DataNetworkControllerTest extends TelephonyTest {
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(anyInt());
        doReturn(true).when(mDataProfileManager).isDataProfilePreferred(any(DataProfile.class));
        doReturn(true).when(mDataProfileManager).isDataProfileValid(any(DataProfile.class));
        doAnswer(invocation -> {
            String apnName = (String) invocation.getArguments()[0];
            TrafficDescriptor td = (TrafficDescriptor) invocation.getArguments()[1];

            List<DataProfile> dps = profiles;

            if (td != null) {
                dps = dps.stream()
                        .filter(dp -> td.equals(dp.getTrafficDescriptor()))
                        .collect(Collectors.toList());
            }

            if (apnName != null) {
                dps = dps.stream()
                        .filter(dp -> dp.getApnSetting() != null)
                        .filter(dp -> apnName.equals(dp.getApnSetting().getApnName()))
                        .collect(Collectors.toList());
            }

            return dps.isEmpty() ? null : dps.get(0);
        }).when(mDataProfileManager).getDataProfile(anyString(), any());

        doAnswer(invocation -> {
            ((Runnable) invocation.getArguments()[0]).run();
+31 −20
Original line number Diff line number Diff line
@@ -420,7 +420,7 @@ public class DataProfileManagerTest extends TelephonyTest {
        verify(mDataNetworkController).registerDataNetworkControllerCallback(
                        dataNetworkControllerCallbackCaptor.capture());
        mDataNetworkControllerCallback = dataNetworkControllerCallbackCaptor.getValue();
        mDataProfileManagerUT.obtainMessage(1).sendToTarget();
        mDataProfileManagerUT.obtainMessage(1 /*EVENT_DATA_CONFIG_UPDATED*/).sendToTarget();
        processAllMessages();

        logd("DataProfileManagerTest -Setup!");
@@ -810,35 +810,46 @@ public class DataProfileManagerTest extends TelephonyTest {
    }

    @Test
    public void testIsDataProfileValid() {
    public void testDefaultEmergencyDataProfileValid() {
        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                .build(), mPhone);
        DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                tnr, TelephonyManager.NETWORK_TYPE_LTE);
        assertThat(dataProfile.getApnSetting().getApnSetId()).isEqualTo(
                Telephony.Carriers.NO_APN_SET_ID);
        assertThat(mDataProfileManagerUT.isDataProfileValid(dataProfile)).isTrue();

        tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
                .build(), mPhone);
        dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                tnr, TelephonyManager.NETWORK_TYPE_LTE);
        assertThat(dataProfile.getApnSetting().getApnSetId()).isEqualTo(
                Telephony.Carriers.MATCH_ALL_APN_SET_ID);
        assertThat(mDataProfileManagerUT.isDataProfileValid(dataProfile)).isTrue();
        assertThat(dataProfile.getApn()).isEqualTo("sos");
        assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos");
    }

    @Test
    public void testDefaultEmergencyDataProfileValid() {
        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(new NetworkRequest.Builder()
                .addCapability(NetworkCapabilities.NET_CAPABILITY_EIMS)
    public void testResetApn() {
        mSimInserted = true;
        mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
        processAllMessages();

        TelephonyNetworkRequest tnr = new TelephonyNetworkRequest(
                new NetworkRequest.Builder()
                        .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                        .build(), mPhone);
        DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest(
                tnr, TelephonyManager.NETWORK_TYPE_LTE);
        assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN);
        dataProfile.setLastSetupTimestamp(SystemClock.elapsedRealtime());
        dataProfile.setPreferred(true);
        mDataNetworkControllerCallback.onInternetDataNetworkConnected(List.of(dataProfile));
        processAllMessages();

        assertThat(dataProfile.getApn()).isEqualTo("sos");
        assertThat(dataProfile.getTrafficDescriptor().getDataNetworkName()).isEqualTo("sos");
        // After internet connected, preferred APN should be set
        assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isTrue();
        assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isTrue();

        // APN reset
        mPreferredApnId = -1;
        mDataProfileManagerUT.obtainMessage(2 /*EVENT_APN_DATABASE_CHANGED*/).sendToTarget();
        processAllMessages();

        // There should be no preferred APN after APN reset
        assertThat(mDataProfileManagerUT.isAnyPreferredDataProfileExisting()).isFalse();
        assertThat(mDataProfileManagerUT.isDataProfilePreferred(dataProfile)).isFalse();
    }
}
Loading