Loading src/java/com/android/internal/telephony/data/DataNetwork.java +36 −16 Original line number Diff line number Diff line Loading @@ -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."); Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -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 Loading Loading @@ -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); } } Loading Loading @@ -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)); Loading @@ -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. Loading tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +79 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); } } Loading
src/java/com/android/internal/telephony/data/DataNetwork.java +36 −16 Original line number Diff line number Diff line Loading @@ -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."); Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -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 Loading Loading @@ -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); } } Loading Loading @@ -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)); Loading @@ -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. Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +79 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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 Loading Loading @@ -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); } }