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

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

Fixed IWLAN handover issues

1. Fixed that fail cause is not included in
   PreciseDataConnectionState when handover fails.
2. Re-organized events registering/unregistering
   logic. When handover to IWLAN, some cellular
   specific events needed to be unregister, and
   vice versa.

Fix: 214670260
Test: atest DataNetworkTest
Change-Id: I74781e2765f340eb776f7e1f671ac7d17547bc64
parent fcc91a29
Loading
Loading
Loading
Loading
+36 −16
Original line number Diff line number Diff line
@@ -883,6 +883,8 @@ public class DataNetwork extends StateMachine {
    private final class ConnectedState extends State {
        @Override
        public void enter() {
            // Note that reaching here could mean from connecting -> connected, or from
            // handover -> connected.
            if (!mEverConnected) {
                // Transited from ConnectingState
                log("network connected.");
@@ -895,20 +897,13 @@ public class DataNetwork extends StateMachine {
                mQosCallbackTracker.updateSessions(mQosBearerSessions);
                mKeepaliveTracker = new KeepaliveTracker(mPhone,
                        getHandler().getLooper(), DataNetwork.this, mNetworkAgent);
                if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                    registerForWwanEvents();
                }
            }

            notifyPreciseDataConnectionState();
            updateSuspendState();

            if (mTransport == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                // Reaching here means
                // 1. The network was first time connected on cellular.
                // 2. The network handover successfully from IWLAN to cellular.
                // 3. The network failed to handover to IWLAN and re-entered connected state.
                // TODO: Correctly support (3) later. We do not need to perform the following works.
                registerForBandwidthUpdate();
                mKeepaliveTracker.registerForKeepaliveStatus();
            }
        }

        @Override
@@ -1057,6 +1052,24 @@ public class DataNetwork extends StateMachine {
        }
    }

    /**
     * Register for events that can only happen on cellular networks.
     */
    private void registerForWwanEvents() {
        registerForBandwidthUpdate();
        mKeepaliveTracker.registerForKeepaliveStatus();
        // Todo: Register for PCO events.
    }

    /**
     * Unregister for events that can only happen on cellular networks.
     */
    private void unregisterForWwanEvents() {
        unregisterForBandwidthUpdate();
        mKeepaliveTracker.unregisterForKeepaliveStatus();
        // Todo: Unregister for PCO events.
    }

    @Override
    protected void unhandledMessage(Message msg) {
        IState state = getCurrentState();
@@ -1521,8 +1534,8 @@ public class DataNetwork extends StateMachine {
            @Nullable DataCallResponse response) {
        logl("onSetupResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode)
                + ", response=" + response);
        int failCause = getFailCauseFromDataCallResponse(resultCode, response);
        if (failCause == DataFailCause.NONE) {
        mFailCause = getFailCauseFromDataCallResponse(resultCode, response);
        if (mFailCause == DataFailCause.NONE) {
            updateDataNetwork(response);

            // TODO: Check if the cid already exists. If yes, should notify DNC and let it force
@@ -1553,7 +1566,7 @@ public class DataNetwork extends StateMachine {
            NetworkRequestList requestList = new NetworkRequestList(mAttachedNetworkRequestList);
            mDataNetworkCallback.invokeFromExecutor(()
                    -> mDataNetworkCallback.onSetupDataFailed(
                            DataNetwork.this, requestList, failCause, retryDelayMillis));
                            DataNetwork.this, requestList, mFailCause, retryDelayMillis));
            transitionTo(mDisconnectedState);
        }
    }
@@ -2092,14 +2105,21 @@ public class DataNetwork extends StateMachine {
            @Nullable DataCallResponse response, @Nullable DataHandoverRetryEntry retryEntry) {
        logl("onHandoverResponse: resultCode=" + DataServiceCallback.resultCodeToString(resultCode)
                + ", response=" + response);
        int failCause = getFailCauseFromDataCallResponse(resultCode, response);
        if (failCause == DataFailCause.NONE) {
        mFailCause = getFailCauseFromDataCallResponse(resultCode, response);
        if (mFailCause == DataFailCause.NONE) {
            // Clean up on the source transport.
            mDataServiceManagers.get(mTransport).deactivateDataCall(mCid.get(mTransport),
                    DataService.REQUEST_REASON_HANDOVER, null);
            // Switch the transport to the target.
            mTransport = DataUtils.getTargetTransport(mTransport);
            updateDataNetwork(response);
            if (mTransport != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
                // Handover from WWAN to WLAN
                unregisterForWwanEvents();
            } else {
                // Handover from WLAN to WWAN
                registerForWwanEvents();
            }
            if (retryEntry != null) retryEntry.setState(DataRetryEntry.RETRY_STATE_SUCCEEDED);
            mDataNetworkCallback.invokeFromExecutor(
                    () -> mDataNetworkCallback.onHandoverSucceeded(DataNetwork.this));
@@ -2112,7 +2132,7 @@ public class DataNetwork extends StateMachine {
            if (retryEntry != null) retryEntry.setState(DataRetryEntry.RETRY_STATE_FAILED);
            mDataNetworkCallback.invokeFromExecutor(
                    () -> mDataNetworkCallback.onHandoverFailed(DataNetwork.this,
                            failCause, retry, handoverFailureMode));
                            mFailCause, retry, handoverFailureMode));
        }

        // No matter handover succeeded or not, transit back to connected state.
+79 −0
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.Mockito;

import java.net.InetAddress;
import java.util.ArrayList;
@@ -202,6 +203,8 @@ public class DataNetworkTest extends TelephonyTest {
        doReturn(true).when(mSST).isConcurrentVoiceAndDataAllowed();
        doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager)
                .getPreferredTransportByNetworkCapability(anyInt());
        doReturn(DataNetwork.BANDWIDTH_SOURCE_BANDWIDTH_ESTIMATOR)
                .when(mDataConfigManager).getBandwidthEstimateSource();
    }

    @After
@@ -425,4 +428,80 @@ public class DataNetworkTest extends TelephonyTest {
        assertThat(pdcsList.get(3).getTransportType())
                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
    }

    @Test
    public void testHandover() {
        testCreateDataNetwork();

        setSuccessfulSetupDataResponse(mMockedWlanDataServiceManager, 456);
        // Now handover to IWLAN
        mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null);
        processAllMessages();

        verify(mLinkBandwidthEstimator).unregisterForBandwidthChanged(
                eq(mDataNetworkUT.getHandler()));
        assertThat(mDataNetworkUT.getTransport())
                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
        assertThat(mDataNetworkUT.getId()).isEqualTo(456);
        verify(mDataNetworkCallback).onHandoverSucceeded(eq(mDataNetworkUT));

        ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor =
                ArgumentCaptor.forClass(PreciseDataConnectionState.class);
        verify(mPhone, times(4)).notifyDataConnection(pdcsCaptor.capture());
        List<PreciseDataConnectionState> pdcsList = pdcsCaptor.getAllValues();

        assertThat(pdcsList).hasSize(4);
        assertThat(pdcsList.get(0).getState()).isEqualTo(TelephonyManager.DATA_CONNECTING);
        assertThat(pdcsList.get(1).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);
        assertThat(pdcsList.get(2).getState())
                .isEqualTo(TelephonyManager.DATA_HANDOVER_IN_PROGRESS);
        assertThat(pdcsList.get(3).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);

        // Now handover back to cellular
        Mockito.clearInvocations(mDataNetworkCallback);
        Mockito.clearInvocations(mLinkBandwidthEstimator);
        mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, null);
        processAllMessages();

        verify(mLinkBandwidthEstimator).registerForBandwidthChanged(
                eq(mDataNetworkUT.getHandler()), anyInt(), eq(null));
        assertThat(mDataNetworkUT.getTransport())
                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        assertThat(mDataNetworkUT.getId()).isEqualTo(123);
        verify(mDataNetworkCallback).onHandoverSucceeded(eq(mDataNetworkUT));
    }

    @Test
    public void testHandoverFailed() {
        testCreateDataNetwork();

        setFailedSetupDataResponse(mMockedWlanDataServiceManager,
                DataServiceCallback.RESULT_ERROR_TEMPORARILY_UNAVAILABLE);
        // Now attempt to handover to IWLAN but fail it.
        mDataNetworkUT.startHandover(AccessNetworkConstants.TRANSPORT_TYPE_WLAN, null);
        processAllMessages();

        verify(mDataNetworkCallback).onHandoverFailed(eq(mDataNetworkUT),
                eq(DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE), eq(-1L),
                eq(DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY));
        verify(mLinkBandwidthEstimator, never()).unregisterForBandwidthChanged(
                eq(mDataNetworkUT.getHandler()));
        assertThat(mDataNetworkUT.getTransport())
                .isEqualTo(AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
        assertThat(mDataNetworkUT.getId()).isEqualTo(123);

        ArgumentCaptor<PreciseDataConnectionState> pdcsCaptor =
                ArgumentCaptor.forClass(PreciseDataConnectionState.class);
        verify(mPhone, times(4)).notifyDataConnection(pdcsCaptor.capture());
        List<PreciseDataConnectionState> pdcsList = pdcsCaptor.getAllValues();

        assertThat(pdcsList).hasSize(4);
        assertThat(pdcsList.get(0).getState()).isEqualTo(TelephonyManager.DATA_CONNECTING);
        assertThat(pdcsList.get(1).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);
        assertThat(pdcsList.get(2).getState())
                .isEqualTo(TelephonyManager.DATA_HANDOVER_IN_PROGRESS);
        assertThat(pdcsList.get(3).getState()).isEqualTo(TelephonyManager.DATA_CONNECTED);
        assertThat(pdcsList.get(3).getLastCauseCode())
                .isEqualTo(DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE);
    }
}