Loading src/java/com/android/internal/telephony/data/DataRetryManager.java +58 −11 Original line number Diff line number Diff line Loading @@ -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: Loading Loading @@ -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. */ Loading Loading @@ -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); Loading Loading @@ -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) Loading @@ -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. Loading Loading @@ -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. */ Loading tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +93 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading @@ -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 Loading Loading @@ -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( Loading Loading @@ -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. Loading Loading
src/java/com/android/internal/telephony/data/DataRetryManager.java +58 −11 Original line number Diff line number Diff line Loading @@ -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: Loading Loading @@ -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. */ Loading Loading @@ -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); Loading Loading @@ -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) Loading @@ -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. Loading Loading @@ -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. */ Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataRetryManagerTest.java +93 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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( Loading @@ -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 Loading Loading @@ -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( Loading Loading @@ -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. Loading