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

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

Merge "Cancel pending retry upon data profile unthrottle"

parents b5b1ea3a dc3e5895
Loading
Loading
Loading
Loading
+58 −11
Original line number Diff line number Diff line
@@ -969,18 +969,16 @@ public class DataRetryManager extends Handler {
        switch (msg.what) {
            case EVENT_DATA_SETUP_RETRY:
                DataSetupRetryEntry dataSetupRetryEntry = (DataSetupRetryEntry) msg.obj;
                Objects.requireNonNull(dataSetupRetryEntry);
                if (!isRetryCancelled(dataSetupRetryEntry)) {
                    mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                            () -> callback.onDataNetworkSetupRetry(dataSetupRetryEntry)));
                }
                break;
            case EVENT_DATA_HANDOVER_RETRY:
                DataHandoverRetryEntry dataHandoverRetryEntry = (DataHandoverRetryEntry) msg.obj;
                Objects.requireNonNull(dataHandoverRetryEntry);
                if (mDataRetryEntries.contains(dataHandoverRetryEntry)) {
                if (!isRetryCancelled(dataHandoverRetryEntry)) {
                    mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                            () -> callback.onDataNetworkHandoverRetry(dataHandoverRetryEntry)));
                } else {
                    log("Handover was cancelled earlier. " + dataHandoverRetryEntry);
                }
                break;
            case EVENT_RADIO_ON:
@@ -1013,6 +1011,18 @@ public class DataRetryManager extends Handler {
        }
    }

    /**
     * @param retryEntry The retry entry to check.
     * @return {@code true} if the retry is null or not in RETRY_STATE_NOT_RETRIED state.
     */
    private boolean isRetryCancelled(@Nullable DataRetryEntry retryEntry) {
        if (retryEntry != null && retryEntry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) {
            return false;
        }
        log("Retry was removed earlier. " + retryEntry);
        return true;
    }

    /**
     * Called when carrier config is updated.
     */
@@ -1385,7 +1395,7 @@ public class DataRetryManager extends Handler {
     * @param remove Whether to remove unthrottled entries from the list of entries.
     */
    private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn,
            int transport, boolean remove) {
            @TransportType int transport, boolean remove) {
        log("onDataProfileUnthrottled: data profile=" + dataProfile + ", apn=" + apn
                + ", transport=" + AccessNetworkConstants.transportTypeToString(transport)
                + ", remove=" + remove);
@@ -1456,11 +1466,16 @@ public class DataRetryManager extends Handler {
        mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor(
                () -> callback.onThrottleStatusChanged(throttleStatusList)));

        if (unthrottledProfile != null) {
            // cancel pending retries since we will soon schedule an immediate retry
            cancelRetriesForDataProfile(unthrottledProfile, transport);
        }

        logl("onDataProfileUnthrottled: Removing the following throttling entries. "
                + dataUnthrottlingEntries);
        for (DataThrottlingEntry entry : dataUnthrottlingEntries) {
            if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) {
            // Immediately retry after unthrottling.
            if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) {
                schedule(new DataSetupRetryEntry.Builder<>()
                        .setDataProfile(entry.dataProfile)
                        .setTransport(entry.transport)
@@ -1480,6 +1495,34 @@ public class DataRetryManager extends Handler {
        }
    }

    /**
     * Cancel pending retries that uses the specified data profile, with specified target transport.
     *
     * @param dataProfile The data profile to cancel.
     * @param transport The target {@link TransportType} on which the retry to cancel.
     */
    private void cancelRetriesForDataProfile(@NonNull DataProfile dataProfile,
            @TransportType int transport) {
        logl("cancelRetriesForDataProfile: Canceling pending retries for " + dataProfile);
        mDataRetryEntries.stream()
                .filter(entry -> {
                    if (entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) {
                        if (entry instanceof DataSetupRetryEntry) {
                            DataSetupRetryEntry retryEntry = (DataSetupRetryEntry) entry;
                            return dataProfile.equals(retryEntry.dataProfile)
                                    && transport == retryEntry.transport;
                        } else if (entry instanceof DataHandoverRetryEntry) {
                            DataHandoverRetryEntry retryEntry = (DataHandoverRetryEntry) entry;
                            return dataProfile.equals(retryEntry.dataNetwork.getDataProfile());
                        }
                    }
                    return false;
                })
                .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED));
    }



    /**
     * Check if there is any similar network request scheduled to retry. The definition of similar
     * is that network requests have same APN capability and on the same transport.
@@ -1564,14 +1607,18 @@ public class DataRetryManager extends Handler {
     * @param dataNetwork The data network that was originally scheduled for handover retry.
     */
    private void onCancelPendingHandoverRetry(@NonNull DataNetwork dataNetwork) {
        mDataRetryEntries.removeIf(entry -> entry instanceof DataHandoverRetryEntry
                && ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork);
        mDataRetryEntries.stream()
                .filter(entry -> entry instanceof DataHandoverRetryEntry
                        && ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork
                        && entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED)
                .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED));
        mDataThrottlingEntries.removeIf(entry -> entry.dataNetwork == dataNetwork);
    }

    /**
     * Check if there is any data handover retry scheduled.
     *
     *
     * @param dataNetwork The network network to retry handover.
     * @return {@code true} if there is retry scheduled for this network capability.
     */
+93 −2
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.internal.telephony.data;

import static com.android.internal.telephony.data.DataRetryManager.DataHandoverRetryEntry;
import static com.android.internal.telephony.data.DataRetryManager.DataRetryEntry;
import static com.android.internal.telephony.data.DataRetryManager.DataSetupRetryEntry;

import static com.google.common.truth.Truth.assertThat;
@@ -25,6 +27,7 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;

import android.net.NetworkCapabilities;
@@ -54,6 +57,7 @@ import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;

import java.lang.reflect.Field;
import java.util.Collections;
import java.util.List;

@@ -323,15 +327,38 @@ public class DataRetryManagerTest extends TelephonyTest {
    }

    @Test
    public void testDataSetupUnthrottling() {
    public void testDataSetupUnthrottling() throws Exception {
        testDataSetupRetryNetworkSuggestedNeverRetry();
        Mockito.clearInvocations(mDataRetryManagerCallbackMock);
        DataNetworkController.NetworkRequestList mockNrl = Mockito.mock(
                DataNetworkController.NetworkRequestList.class);
        Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries");
        field.setAccessible(true);
        List<DataRetryEntry> mDataRetryEntries =
                (List<DataRetryEntry>) field.get(mDataRetryManagerUT);

        // schedule 2 setup retries
        DataSetupRetryEntry scheduledRetry1 = new DataSetupRetryEntry.Builder<>()
                .setDataProfile(mDataProfile3)
                .setNetworkRequestList(mockNrl)
                .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                .setSetupRetryType(1)
                .build();
        DataSetupRetryEntry scheduledRetry2 = new DataSetupRetryEntry.Builder<>()
                .setNetworkRequestList(mockNrl)
                .setDataProfile(mDataProfile3)
                .setTransport(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
                .setSetupRetryType(1)
                .build();
        mDataRetryEntries.addAll(List.of(scheduledRetry1, scheduledRetry2));

        // unthrottle the data profile, expect previous retries of the same transport is cancelled
        mDataRetryManagerUT.obtainMessage(6/*EVENT_DATA_PROFILE_UNTHROTTLED*/,
                new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, mDataProfile3, null))
                .sendToTarget();
        processAllMessages();

        // check unthrottle
        ArgumentCaptor<List<ThrottleStatus>> throttleStatusCaptor =
                ArgumentCaptor.forClass(List.class);
        verify(mDataRetryManagerCallbackMock).onThrottleStatusChanged(
@@ -353,6 +380,10 @@ public class DataRetryManagerTest extends TelephonyTest {
        assertThat(entry.dataProfile).isEqualTo(mDataProfile3);
        assertThat(entry.retryDelayMillis).isEqualTo(0);
        assertThat(entry.transport).isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);

        // check mDataProfile3-WWAN retry is cancelled, but not the WLAN
        assertThat(scheduledRetry1.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED);
        assertThat(scheduledRetry2.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_NOT_RETRIED);
    }

    @Test
@@ -390,6 +421,66 @@ public class DataRetryManagerTest extends TelephonyTest {
        assertThat(entry.transport).isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
    }

    @Test
    public void testCancellingRetries() throws Exception {
        DataNetworkController.NetworkRequestList mockNrl = Mockito.mock(
                DataNetworkController.NetworkRequestList.class);

        // Test: setup retry
        DataRetryEntry retry = new DataSetupRetryEntry.Builder<>()
                .setSetupRetryType(1)
                .setNetworkRequestList(mockNrl)
                .setTransport(1)
                .build();
        retry.setState(DataRetryEntry.RETRY_STATE_CANCELLED);

        mDataRetryManagerUT.obtainMessage(3/*EVENT_DATA_SETUP_RETRY*/, retry).sendToTarget();
        processAllMessages();
        verify(mDataRetryManagerCallbackMock, never()).onDataNetworkSetupRetry(any());

        mDataRetryManagerUT.obtainMessage(3/*EVENT_DATA_SETUP_RETRY*/, null).sendToTarget();
        processAllMessages();
        verify(mDataRetryManagerCallbackMock, never()).onDataNetworkSetupRetry(any());

        retry.setState(DataRetryEntry.RETRY_STATE_NOT_RETRIED);
        mDataRetryManagerUT.obtainMessage(3/*EVENT_DATA_SETUP_RETRY*/, retry).sendToTarget();
        processAllMessages();
        verify(mDataRetryManagerCallbackMock, times(1)).onDataNetworkSetupRetry(any());

        // Test: handover retry
        retry = new DataHandoverRetryEntry.Builder<>().build();
        retry.setState(DataRetryEntry.RETRY_STATE_CANCELLED);
        mDataRetryManagerUT.obtainMessage(4/*EVENT_DATA_HANDOVER_RETRY*/, retry).sendToTarget();
        processAllMessages();
        verify(mDataRetryManagerCallbackMock, never()).onDataNetworkHandoverRetry(any());

        mDataRetryManagerUT.obtainMessage(4/*EVENT_DATA_HANDOVER_RETRY*/, null).sendToTarget();
        processAllMessages();
        verify(mDataRetryManagerCallbackMock, never()).onDataNetworkHandoverRetry(any());

        retry.setState(DataRetryEntry.RETRY_STATE_NOT_RETRIED);
        mDataRetryManagerUT.obtainMessage(4/*EVENT_DATA_HANDOVER_RETRY*/, retry).sendToTarget();
        processAllMessages();
        verify(mDataRetryManagerCallbackMock, times(1))
                .onDataNetworkHandoverRetry(any());

        // Test: cancelPendingHandoverRetry
        DataNetwork mockDn = Mockito.mock(DataNetwork.class);
        Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries");
        field.setAccessible(true);
        List<DataRetryEntry> mDataRetryEntries =
                (List<DataRetryEntry>) field.get(mDataRetryManagerUT);
        retry = new DataHandoverRetryEntry.Builder<>()
                .setDataNetwork(mockDn)
                .build();
        mDataRetryEntries.add(retry);
        mDataRetryManagerUT.cancelPendingHandoverRetry(mockDn);
        processAllMessages();

        assertThat(mDataRetryManagerUT.isAnyHandoverRetryScheduled(mockDn)).isFalse();
        assertThat(retry.getState()).isEqualTo(DataRetryEntry.RETRY_STATE_CANCELLED);
    }

    @Test
    public void testDataSetupRetryPermanentFailure() {
        DataSetupRetryRule retryRule = new DataSetupRetryRule(
@@ -584,7 +675,7 @@ public class DataRetryManagerTest extends TelephonyTest {
            assertThat(entry.networkRequestList).isEqualTo(networkRequestList);
            assertThat(entry.appliedDataRetryRule).isEqualTo(retryRule3);

            entry.setState(DataRetryManager.DataRetryEntry.RETRY_STATE_FAILED);
            entry.setState(DataRetryEntry.RETRY_STATE_FAILED);
        }

        // The last fail should not trigger any retry.