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

Commit 22140d37 authored by Ling Ma's avatar Ling Ma Committed by Jack Yu
Browse files

Cancel HandoverRetry when it's in wrong network state

Race condition occurs when two same handover retries that are scheduled very close(e.g. modem unthrottles an APN which triggers a retry coincides a retry after handover failure) that both of them passed `!dataNetwork.isConnected()` check at `onDataNetworkHandoverRetry`, and sent two EVENT_START_HANDOVER in DN. One of them successfully starts the handover while the other one is ignored because it's already in handover state, but the ignored retry entry is always set as "not_retried", so in future when we attempt to start another handover, it will be disallowed due to the obsolete retry entry "not_retried".

Bug: 235567654
Test: manual verified
Merged-In: Ief834becf215ab843957f5f9ecf70f28273db0e5
Change-Id: Ief834becf215ab843957f5f9ecf70f28273db0e5
parent 5de75c7d
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -1109,7 +1109,14 @@ public class DataNetwork extends StateMachine {
                    log("Ignored " + eventToString(msg.what));
                    break;
                case EVENT_START_HANDOVER:
                    log("Ignore the handover to " + AccessNetworkConstants
                    // We reach here if network is not in the connected/connecting state.
                    if (msg.obj != null) {
                        // Cancel it because it's either HO in progress or will soon disconnect.
                        // Either case we want to clean up obsolete retry attempts.
                        DataHandoverRetryEntry retryEntry = (DataHandoverRetryEntry) msg.obj;
                        retryEntry.setState(DataRetryEntry.RETRY_STATE_CANCELLED);
                    }
                    log("Ignore retry for the handover to " + AccessNetworkConstants
                            .transportTypeToString(msg.arg1) + " request.");
                    break;
                case EVENT_RADIO_NOT_AVAILABLE:
+1 −1
Original line number Diff line number Diff line
@@ -2645,7 +2645,7 @@ public class DataNetworkController extends Handler {
            return;
        }

        logl("Start handover " + dataNetwork + " to "
        logl("onDataNetworkHandoverRetry: Start handover " + dataNetwork + " to "
                + AccessNetworkConstants.transportTypeToString(preferredTransport)
                + ", " + dataHandoverRetryEntry);
        dataNetwork.startHandover(preferredTransport, dataHandoverRetryEntry);
+49 −0
Original line number Diff line number Diff line
@@ -1993,6 +1993,55 @@ public class DataNetworkControllerTest extends TelephonyTest {
                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
    }

    @Test
    public void testHandoverDataNetworkDuplicateRetry() throws Exception {
        testSetupImsDataNetwork();
        DataNetwork dataNetwork = getDataNetworks().get(0);
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
                .when(mAccessNetworksManager).getPreferredTransportByNetworkCapability(anyInt());

        DataRetryManager.DataHandoverRetryEntry retry1 =
                new DataRetryManager.DataHandoverRetryEntry.Builder<>()
                        .setDataNetwork(dataNetwork)
                        .build();
        DataRetryManager.DataHandoverRetryEntry retry2 =
                new DataRetryManager.DataHandoverRetryEntry.Builder<>()
                        .setDataNetwork(dataNetwork)
                        .build();
        final Message msg1 = new Message();
        msg1.what = 4 /*EVENT_DATA_HANDOVER_RETRY*/;
        msg1.obj = retry1;

        final Message msg2 = new Message();
        msg2.what = 4 /*EVENT_DATA_HANDOVER_RETRY*/;
        msg2.obj = retry2;

        Field field = DataRetryManager.class.getDeclaredField("mDataRetryEntries");
        field.setAccessible(true);
        List<DataRetryManager.DataRetryEntry> dataRetryEntries =
                (List<DataRetryManager.DataRetryEntry>)
                        field.get(mDataNetworkControllerUT.getDataRetryManager());
        dataRetryEntries.add(retry1);
        dataRetryEntries.add(retry2);

        mDataNetworkControllerUT.getDataRetryManager().sendMessageDelayed(msg1, 0);
        mDataNetworkControllerUT.getDataRetryManager().sendMessageDelayed(msg2, 0);

        processAllFutureMessages();

        setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 1);
        processAllMessages();

        dataNetwork = getDataNetworks().get(0);
        assertThat(dataNetwork.getTransport()).isEqualTo(
                AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
        verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class),
                anyBoolean(), anyBoolean(), eq(DataService.REQUEST_REASON_HANDOVER), any(),
                anyInt(), any(), any(), anyBoolean(), any(Message.class));
        assertThat(mDataNetworkControllerUT.getDataRetryManager()
                .isAnyHandoverRetryScheduled(dataNetwork)).isFalse();
    }

    @Test
    public void testHandoverDataNetworkRetryReachedMaximum() throws Exception {
        testSetupImsDataNetwork();