Loading src/java/com/android/internal/telephony/RIL.java +5 −3 Original line number Diff line number Diff line Loading @@ -1982,10 +1982,11 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) { riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + ",reason=" + RILUtils.setupDataReasonToString(reason) + ",accessNetworkType=" + AccessNetworkType.toString(accessNetworkType) + ",dataProfile=" + dataProfile + ",isRoaming=" + isRoaming + ",allowRoaming=" + allowRoaming + ",reason" + reason + ",linkProerties=" + linkProperties + ",pduSessionId=" + pduSessionId + ",allowRoaming=" + allowRoaming + ",linkProperties=" + linkProperties + ",pduSessionId=" + pduSessionId + ",sliceInfo=" + sliceInfo + ",trafficDescriptor=" + trafficDescriptor + ",matchAllRuleAllowed=" + matchAllRuleAllowed); } Loading Loading @@ -2249,7 +2250,8 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) { riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + " cid = " + cid + " reason = " + reason); + " cid = " + cid + " reason = " + RILUtils.deactivateDataReasonToString(reason)); } try { Loading src/java/com/android/internal/telephony/RILUtils.java +43 −0 Original line number Diff line number Diff line Loading @@ -313,6 +313,9 @@ import android.telephony.UiccSlotMapping; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.DataService; import android.telephony.data.DataService.DeactivateDataReason; import android.telephony.data.DataService.SetupDataReason; import android.telephony.data.EpsQos; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.NetworkSlicingConfig; Loading Loading @@ -4626,6 +4629,46 @@ public class RILUtils { return string != null ? string : ""; } /** * Convert setup data reason to string. * * @param reason The reason for setup data call. * @return The reason in string format. */ public static String setupDataReasonToString(@SetupDataReason int reason) { switch (reason) { case DataService.REQUEST_REASON_NORMAL: return "NORMAL"; case DataService.REQUEST_REASON_HANDOVER: return "HANDOVER"; case DataService.REQUEST_REASON_UNKNOWN: return "UNKNOWN"; default: return "UNKNOWN(" + reason + ")"; } } /** * Convert deactivate data reason to string. * * @param reason The reason for deactivate data call. * @return The reason in string format. */ public static String deactivateDataReasonToString(@DeactivateDataReason int reason) { switch (reason) { case DataService.REQUEST_REASON_NORMAL: return "NORMAL"; case DataService.REQUEST_REASON_HANDOVER: return "HANDOVER"; case DataService.REQUEST_REASON_SHUTDOWN: return "SHUTDOWN"; case DataService.REQUEST_REASON_UNKNOWN: return "UNKNOWN"; default: return "UNKNOWN(" + reason + ")"; } } /** * RIL request to String * @param request request Loading src/java/com/android/internal/telephony/data/DataNetwork.java +15 −23 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; Loading Loading @@ -973,14 +974,18 @@ public class DataNetwork extends StateMachine { mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); break; } case EVENT_START_HANDOVER: case EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED: case EVENT_BANDWIDTH_ESTIMATE_FROM_BANDWIDTH_ESTIMATOR_CHANGED: case EVENT_TEAR_DOWN_NETWORK: case EVENT_PCO_DATA_RECEIVED: case EVENT_STUCK_IN_TRANSIENT_STATE: case EVENT_DISPLAY_INFO_CHANGED: // Ignore the events when not in the correct state. break; case EVENT_START_HANDOVER: log("Ignore the handover to " + AccessNetworkConstants .transportTypeToString(msg.arg1) + " request."); break; default: loge("Unhandled event " + eventToString(msg.what)); break; Loading Loading @@ -1206,7 +1211,6 @@ public class DataNetwork extends StateMachine { deferMessage(msg); } break; case EVENT_START_HANDOVER: case EVENT_TEAR_DOWN_NETWORK: // Defer the request until handover succeeds or fails. deferMessage(msg); Loading Loading @@ -2440,28 +2444,16 @@ public class DataNetwork extends StateMachine { } /** * Get the highest priority network capability from the network request. This is used to get * the representative APN-type capability for different purposes. It will never return a * non-APN-type capability. * Get the APN type network capability. If there are more than one capabilities that are * APN-types, then return the highest priority one. * * @return The highest priority network capability from this network. * @return The APN type network capability from this network. */ public @NetCapability int getHighestPriorityNetworkCapability() { int highestPriority = 0; int highestPriorityCapability = -1; for (int capability : getNetworkCapabilities().getCapabilities()) { // Convert the capability to APN type. For non-APN-type capabilities, TYPE_NONE is // returned. int apnType = DataUtils.networkCapabilityToApnType(capability); if (apnType != ApnSetting.TYPE_NONE) { int priority = mDataConfigManager.getNetworkCapabilityPriority(capability); if (priority > highestPriority) { highestPriority = priority; highestPriorityCapability = capability; } } } return highestPriorityCapability; public @NetCapability int getApnTypeNetworkCapability() { return Arrays.stream(getNetworkCapabilities().getCapabilities()).boxed() .filter(cap -> DataUtils.networkCapabilityToApnType(cap) != ApnSetting.TYPE_NONE) .max(Comparator.comparingInt(mDataConfigManager::getNetworkCapabilityPriority)) .orElse(-1); } /** Loading src/java/com/android/internal/telephony/data/DataNetworkController.java +38 −20 Original line number Diff line number Diff line Loading @@ -178,8 +178,8 @@ public class DataNetworkController extends Handler { /** Event for emergency call started or ended. */ private static final int EVENT_EMERGENCY_CALL_CHANGED = 20; /** Event for preferred transport changed. */ private static final int EVENT_PREFERRED_TRANSPORT_CHANGED = 21; /** Event for evaluating preferred transport. */ private static final int EVENT_EVALUATE_PREFERRED_TRANSPORT = 21; /** Event for subscription plans changed. */ private static final int EVENT_SUBSCRIPTION_PLANS_CHANGED = 22; Loading Loading @@ -821,7 +821,12 @@ public class DataNetworkController extends Handler { mAccessNetworksManager.registerCallback(new AccessNetworksManagerCallback(this::post) { @Override public void onPreferredTransportChanged(@NetCapability int capability) { DataNetworkController.this.onPreferredTransportChanged(capability); int preferredTransport = mAccessNetworksManager .getPreferredTransportByNetworkCapability(capability); logl("onPreferredTransportChanged: " + DataUtils.networkCapabilityToString(capability) + " preferred on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); DataNetworkController.this.onEvaluatePreferredTransport(capability); sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED)); } Loading Loading @@ -963,8 +968,8 @@ public class DataNetworkController extends Handler { DataEvaluationReason.EMERGENCY_CALL_CHANGED)); } break; case EVENT_PREFERRED_TRANSPORT_CHANGED: onPreferredTransportChanged(msg.arg1); case EVENT_EVALUATE_PREFERRED_TRANSPORT: onEvaluatePreferredTransport(msg.arg1); break; case EVENT_SUBSCRIPTION_PLANS_CHANGED: SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj; Loading Loading @@ -2182,7 +2187,7 @@ public class DataNetworkController extends Handler { } int preferredTransport = mAccessNetworksManager.getPreferredTransportByNetworkCapability( dataNetwork.getHighestPriorityNetworkCapability()); dataNetwork.getApnTypeNetworkCapability()); if (dataNetwork.getTransport() == preferredTransport) { log("onDataNetworkHandoverRetry: " + dataNetwork + " is already on the preferred " + "transport " + AccessNetworkConstants.transportTypeToString( Loading Loading @@ -2295,8 +2300,13 @@ public class DataNetworkController extends Handler { * @param dataNetwork The data network. */ private void onDataNetworkHandoverSucceeded(@NonNull DataNetwork dataNetwork) { logl("Successfully handover " + dataNetwork + " to " + AccessNetworkConstants.transportTypeToString(dataNetwork.getTransport())); logl("Handover successfully. " + dataNetwork + " to " + AccessNetworkConstants .transportTypeToString(dataNetwork.getTransport())); // The preferred transport might be changed when handover was in progress. We need to // evaluate again to make sure we are not out-of-sync with the input from access network // manager. sendMessage(obtainMessage(EVENT_EVALUATE_PREFERRED_TRANSPORT, dataNetwork.getApnTypeNetworkCapability(), 0)); } /** Loading @@ -2314,9 +2324,9 @@ public class DataNetworkController extends Handler { private void onDataNetworkHandoverFailed(@NonNull DataNetwork dataNetwork, @DataFailureCause int cause, long retryDelayMillis, @HandoverFailureMode int handoverFailureMode) { logl("onDataNetworkHandoverFailed: " + dataNetwork + ", cause=" + DataFailCause.toString(cause) + "(0x" + Integer.toHexString(cause) + "), retryDelayMillis=" + retryDelayMillis + "ms, handoverFailureMode=" logl("Handover failed. " + dataNetwork + ", cause=" + DataFailCause.toString(cause) + "(0x" + Integer.toHexString(cause) + "), retryDelayMillis=" + retryDelayMillis + "ms, handoverFailureMode=" + DataCallResponse.failureModeToString(handoverFailureMode)); if (handoverFailureMode == DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK || (handoverFailureMode == DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY Loading @@ -2325,8 +2335,8 @@ public class DataNetworkController extends Handler { // to the original one, but we should re-evaluate the preferred transport again to // make sure QNS does change it back, if not, we still need to perform handover at that // time. sendMessageDelayed(obtainMessage(EVENT_PREFERRED_TRANSPORT_CHANGED, dataNetwork.getHighestPriorityNetworkCapability(), 0), sendMessageDelayed(obtainMessage(EVENT_EVALUATE_PREFERRED_TRANSPORT, dataNetwork.getApnTypeNetworkCapability(), 0), REEVALUATE_PREFERRED_TRANSPORT_DELAY_MILLIS); } else if (handoverFailureMode == DataCallResponse .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL || handoverFailureMode Loading Loading @@ -2422,26 +2432,34 @@ public class DataNetworkController extends Handler { } /** * Called when preferred transport changed for certain capability. * Called when needed to evaluate the preferred transport for certain capability. * * @param capability The network capability that has preferred transport changed. * @param capability The network capability to evaluate. */ private void onPreferredTransportChanged(@NetCapability int capability) { private void onEvaluatePreferredTransport(@NetCapability int capability) { int preferredTransport = mAccessNetworksManager .getPreferredTransportByNetworkCapability(capability); logl("onPreferredTransportChanged: " + DataUtils.networkCapabilityToString(capability) log("evaluatePreferredTransport: " + DataUtils.networkCapabilityToString(capability) + " preferred on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); for (DataNetwork dataNetwork : mDataNetworkList) { if (dataNetwork.getHighestPriorityNetworkCapability() == capability) { if (dataNetwork.getApnTypeNetworkCapability() == capability) { // Check if the data network's current transport is different than from the // preferred transport. If it's different, then handover is needed. if (dataNetwork.getTransport() == preferredTransport) { log("onPreferredTransportChanged:" + dataNetwork + " already on " log("evaluatePreferredTransport:" + dataNetwork + " already on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); continue; } // If handover is ongoing, ignore the preference change for now. After handover // succeeds or fails, preferred transport will be re-evaluate again. Handover will // be performed at that time if needed. if (dataNetwork.isHandoverInProgress()) { log("evaluatePreferredTransport: " + dataNetwork + " handover in progress."); continue; } DataEvaluation dataEvaluation = evaluateDataNetworkHandover(dataNetwork); if (!dataEvaluation.containsDisallowedReasons()) { logl("Start handover " + dataNetwork + " to " Loading @@ -2449,7 +2467,7 @@ public class DataNetworkController extends Handler { dataNetwork.startHandover(preferredTransport, null); } else if (dataEvaluation.containsOnly( DataDisallowedReason.NOT_ALLOWED_BY_POLICY)) { logl("onPreferredTransportChanged: Handover not allowed by policy. Tear " logl("evaluatePreferredTransport: Handover not allowed by policy. Tear " + "down the network so a new network can be setup on " + AccessNetworkConstants.transportTypeToString(preferredTransport) + "."); Loading tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +61 −5 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ import com.android.internal.telephony.ISub; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; import com.android.internal.telephony.data.DataNetworkController.HandoverRule; import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback; Loading Loading @@ -126,6 +127,8 @@ public class DataNetworkControllerTest extends TelephonyTest { private DataNetworkController mDataNetworkControllerUT; private PersistableBundle mCarrierConfig; private AccessNetworksManagerCallback mAccessNetworksManagerCallback; private final DataProfile mGeneralPurposeDataProfile = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setId(2163) Loading Loading @@ -501,6 +504,11 @@ public class DataNetworkControllerTest extends TelephonyTest { replaceInstance(DataNetworkController.class, "mAccessNetworksManager", mDataNetworkControllerUT, mAccessNetworksManager); ArgumentCaptor<AccessNetworksManagerCallback> callbackCaptor = ArgumentCaptor.forClass(AccessNetworksManagerCallback.class); verify(mAccessNetworksManager).registerCallback(callbackCaptor.capture()); mAccessNetworksManagerCallback = callbackCaptor.getValue(); doAnswer(invocation -> { TelephonyNetworkRequest networkRequest = (TelephonyNetworkRequest) invocation.getArguments()[0]; Loading Loading @@ -1027,7 +1035,7 @@ public class DataNetworkControllerTest extends TelephonyTest { .getPreferredTransportByNetworkCapability( eq(NetworkCapabilities.NET_CAPABILITY_INTERNET)); // Data remain disabled, but trigger the preference evaluation. mDataNetworkControllerUT.obtainMessage(21 /*EVENT_PREFERRED_TRANSPORT_CHANGED*/, mDataNetworkControllerUT.obtainMessage(21 /*EVENT_EVALUATE_PREFERRED_TRANSPORT*/, NetworkCapabilities.NET_CAPABILITY_INTERNET, 0).sendToTarget(); mDataNetworkControllerUT.obtainMessage(5 /*EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS*/, DataEvaluation.DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED).sendToTarget(); Loading Loading @@ -1295,8 +1303,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mDataNetworkControllerUT.obtainMessage(21/*EVENT_EVALUATE_PREFERRED_TRANSPORT*/, NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); DataNetwork dataNetwork = getDataNetworks().get(0); Loading @@ -1305,6 +1313,54 @@ public class DataNetworkControllerTest extends TelephonyTest { AccessNetworkConstants.TRANSPORT_TYPE_WLAN); } @Test public void testHandoverDataNetworkBackToBackPreferenceChanged() throws Exception { testSetupImsDataNetwork(); Mockito.reset(mMockedWlanDataServiceManager); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); // Capture the message for setup data call response. We want to delay it. ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), messageCaptor.capture()); // Before setup data call response, change the preference back to cellular. doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); // Before setup data call response, change the preference back to IWLAN. doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); // Finally handover is completed. Message msg = messageCaptor.getValue(); DataCallResponse response = new DataCallResponse.Builder() .setCause(DataFailCause.NONE) .build(); msg.getData().putParcelable("data_call_response", response); msg.arg1 = DataServiceCallback.RESULT_SUCCESS; msg.sendToTarget(); processAllMessages(); // Make sure handover request is only sent once. verify(mMockedWlanDataServiceManager, times(1)).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), messageCaptor.capture()); } @Test public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, Loading @@ -1318,8 +1374,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mDataNetworkControllerUT.obtainMessage(21/*EVENT_PREFERRED_TRANSPORT_CHANGED*/, NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); // After this, IMS data network should be disconnected, and DNC should attempt to // establish a new one on IWLAN processAllMessages(); Loading Loading
src/java/com/android/internal/telephony/RIL.java +5 −3 Original line number Diff line number Diff line Loading @@ -1982,10 +1982,11 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) { riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + ",reason=" + RILUtils.setupDataReasonToString(reason) + ",accessNetworkType=" + AccessNetworkType.toString(accessNetworkType) + ",dataProfile=" + dataProfile + ",isRoaming=" + isRoaming + ",allowRoaming=" + allowRoaming + ",reason" + reason + ",linkProerties=" + linkProperties + ",pduSessionId=" + pduSessionId + ",allowRoaming=" + allowRoaming + ",linkProperties=" + linkProperties + ",pduSessionId=" + pduSessionId + ",sliceInfo=" + sliceInfo + ",trafficDescriptor=" + trafficDescriptor + ",matchAllRuleAllowed=" + matchAllRuleAllowed); } Loading Loading @@ -2249,7 +2250,8 @@ public class RIL extends BaseCommands implements CommandsInterface { if (RILJ_LOGD) { riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest) + " cid = " + cid + " reason = " + reason); + " cid = " + cid + " reason = " + RILUtils.deactivateDataReasonToString(reason)); } try { Loading
src/java/com/android/internal/telephony/RILUtils.java +43 −0 Original line number Diff line number Diff line Loading @@ -313,6 +313,9 @@ import android.telephony.UiccSlotMapping; import android.telephony.data.ApnSetting; import android.telephony.data.DataCallResponse; import android.telephony.data.DataProfile; import android.telephony.data.DataService; import android.telephony.data.DataService.DeactivateDataReason; import android.telephony.data.DataService.SetupDataReason; import android.telephony.data.EpsQos; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.NetworkSlicingConfig; Loading Loading @@ -4626,6 +4629,46 @@ public class RILUtils { return string != null ? string : ""; } /** * Convert setup data reason to string. * * @param reason The reason for setup data call. * @return The reason in string format. */ public static String setupDataReasonToString(@SetupDataReason int reason) { switch (reason) { case DataService.REQUEST_REASON_NORMAL: return "NORMAL"; case DataService.REQUEST_REASON_HANDOVER: return "HANDOVER"; case DataService.REQUEST_REASON_UNKNOWN: return "UNKNOWN"; default: return "UNKNOWN(" + reason + ")"; } } /** * Convert deactivate data reason to string. * * @param reason The reason for deactivate data call. * @return The reason in string format. */ public static String deactivateDataReasonToString(@DeactivateDataReason int reason) { switch (reason) { case DataService.REQUEST_REASON_NORMAL: return "NORMAL"; case DataService.REQUEST_REASON_HANDOVER: return "HANDOVER"; case DataService.REQUEST_REASON_SHUTDOWN: return "SHUTDOWN"; case DataService.REQUEST_REASON_UNKNOWN: return "UNKNOWN"; default: return "UNKNOWN(" + reason + ")"; } } /** * RIL request to String * @param request request Loading
src/java/com/android/internal/telephony/data/DataNetwork.java +15 −23 Original line number Diff line number Diff line Loading @@ -104,6 +104,7 @@ import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Objects; Loading Loading @@ -973,14 +974,18 @@ public class DataNetwork extends StateMachine { mAdministratorUids = Arrays.copyOf(administratorUids, administratorUids.length); break; } case EVENT_START_HANDOVER: case EVENT_BANDWIDTH_ESTIMATE_FROM_MODEM_CHANGED: case EVENT_BANDWIDTH_ESTIMATE_FROM_BANDWIDTH_ESTIMATOR_CHANGED: case EVENT_TEAR_DOWN_NETWORK: case EVENT_PCO_DATA_RECEIVED: case EVENT_STUCK_IN_TRANSIENT_STATE: case EVENT_DISPLAY_INFO_CHANGED: // Ignore the events when not in the correct state. break; case EVENT_START_HANDOVER: log("Ignore the handover to " + AccessNetworkConstants .transportTypeToString(msg.arg1) + " request."); break; default: loge("Unhandled event " + eventToString(msg.what)); break; Loading Loading @@ -1206,7 +1211,6 @@ public class DataNetwork extends StateMachine { deferMessage(msg); } break; case EVENT_START_HANDOVER: case EVENT_TEAR_DOWN_NETWORK: // Defer the request until handover succeeds or fails. deferMessage(msg); Loading Loading @@ -2440,28 +2444,16 @@ public class DataNetwork extends StateMachine { } /** * Get the highest priority network capability from the network request. This is used to get * the representative APN-type capability for different purposes. It will never return a * non-APN-type capability. * Get the APN type network capability. If there are more than one capabilities that are * APN-types, then return the highest priority one. * * @return The highest priority network capability from this network. * @return The APN type network capability from this network. */ public @NetCapability int getHighestPriorityNetworkCapability() { int highestPriority = 0; int highestPriorityCapability = -1; for (int capability : getNetworkCapabilities().getCapabilities()) { // Convert the capability to APN type. For non-APN-type capabilities, TYPE_NONE is // returned. int apnType = DataUtils.networkCapabilityToApnType(capability); if (apnType != ApnSetting.TYPE_NONE) { int priority = mDataConfigManager.getNetworkCapabilityPriority(capability); if (priority > highestPriority) { highestPriority = priority; highestPriorityCapability = capability; } } } return highestPriorityCapability; public @NetCapability int getApnTypeNetworkCapability() { return Arrays.stream(getNetworkCapabilities().getCapabilities()).boxed() .filter(cap -> DataUtils.networkCapabilityToApnType(cap) != ApnSetting.TYPE_NONE) .max(Comparator.comparingInt(mDataConfigManager::getNetworkCapabilityPriority)) .orElse(-1); } /** Loading
src/java/com/android/internal/telephony/data/DataNetworkController.java +38 −20 Original line number Diff line number Diff line Loading @@ -178,8 +178,8 @@ public class DataNetworkController extends Handler { /** Event for emergency call started or ended. */ private static final int EVENT_EMERGENCY_CALL_CHANGED = 20; /** Event for preferred transport changed. */ private static final int EVENT_PREFERRED_TRANSPORT_CHANGED = 21; /** Event for evaluating preferred transport. */ private static final int EVENT_EVALUATE_PREFERRED_TRANSPORT = 21; /** Event for subscription plans changed. */ private static final int EVENT_SUBSCRIPTION_PLANS_CHANGED = 22; Loading Loading @@ -821,7 +821,12 @@ public class DataNetworkController extends Handler { mAccessNetworksManager.registerCallback(new AccessNetworksManagerCallback(this::post) { @Override public void onPreferredTransportChanged(@NetCapability int capability) { DataNetworkController.this.onPreferredTransportChanged(capability); int preferredTransport = mAccessNetworksManager .getPreferredTransportByNetworkCapability(capability); logl("onPreferredTransportChanged: " + DataUtils.networkCapabilityToString(capability) + " preferred on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); DataNetworkController.this.onEvaluatePreferredTransport(capability); sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED)); } Loading Loading @@ -963,8 +968,8 @@ public class DataNetworkController extends Handler { DataEvaluationReason.EMERGENCY_CALL_CHANGED)); } break; case EVENT_PREFERRED_TRANSPORT_CHANGED: onPreferredTransportChanged(msg.arg1); case EVENT_EVALUATE_PREFERRED_TRANSPORT: onEvaluatePreferredTransport(msg.arg1); break; case EVENT_SUBSCRIPTION_PLANS_CHANGED: SubscriptionPlan[] plans = (SubscriptionPlan[]) msg.obj; Loading Loading @@ -2182,7 +2187,7 @@ public class DataNetworkController extends Handler { } int preferredTransport = mAccessNetworksManager.getPreferredTransportByNetworkCapability( dataNetwork.getHighestPriorityNetworkCapability()); dataNetwork.getApnTypeNetworkCapability()); if (dataNetwork.getTransport() == preferredTransport) { log("onDataNetworkHandoverRetry: " + dataNetwork + " is already on the preferred " + "transport " + AccessNetworkConstants.transportTypeToString( Loading Loading @@ -2295,8 +2300,13 @@ public class DataNetworkController extends Handler { * @param dataNetwork The data network. */ private void onDataNetworkHandoverSucceeded(@NonNull DataNetwork dataNetwork) { logl("Successfully handover " + dataNetwork + " to " + AccessNetworkConstants.transportTypeToString(dataNetwork.getTransport())); logl("Handover successfully. " + dataNetwork + " to " + AccessNetworkConstants .transportTypeToString(dataNetwork.getTransport())); // The preferred transport might be changed when handover was in progress. We need to // evaluate again to make sure we are not out-of-sync with the input from access network // manager. sendMessage(obtainMessage(EVENT_EVALUATE_PREFERRED_TRANSPORT, dataNetwork.getApnTypeNetworkCapability(), 0)); } /** Loading @@ -2314,9 +2324,9 @@ public class DataNetworkController extends Handler { private void onDataNetworkHandoverFailed(@NonNull DataNetwork dataNetwork, @DataFailureCause int cause, long retryDelayMillis, @HandoverFailureMode int handoverFailureMode) { logl("onDataNetworkHandoverFailed: " + dataNetwork + ", cause=" + DataFailCause.toString(cause) + "(0x" + Integer.toHexString(cause) + "), retryDelayMillis=" + retryDelayMillis + "ms, handoverFailureMode=" logl("Handover failed. " + dataNetwork + ", cause=" + DataFailCause.toString(cause) + "(0x" + Integer.toHexString(cause) + "), retryDelayMillis=" + retryDelayMillis + "ms, handoverFailureMode=" + DataCallResponse.failureModeToString(handoverFailureMode)); if (handoverFailureMode == DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK || (handoverFailureMode == DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY Loading @@ -2325,8 +2335,8 @@ public class DataNetworkController extends Handler { // to the original one, but we should re-evaluate the preferred transport again to // make sure QNS does change it back, if not, we still need to perform handover at that // time. sendMessageDelayed(obtainMessage(EVENT_PREFERRED_TRANSPORT_CHANGED, dataNetwork.getHighestPriorityNetworkCapability(), 0), sendMessageDelayed(obtainMessage(EVENT_EVALUATE_PREFERRED_TRANSPORT, dataNetwork.getApnTypeNetworkCapability(), 0), REEVALUATE_PREFERRED_TRANSPORT_DELAY_MILLIS); } else if (handoverFailureMode == DataCallResponse .HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL || handoverFailureMode Loading Loading @@ -2422,26 +2432,34 @@ public class DataNetworkController extends Handler { } /** * Called when preferred transport changed for certain capability. * Called when needed to evaluate the preferred transport for certain capability. * * @param capability The network capability that has preferred transport changed. * @param capability The network capability to evaluate. */ private void onPreferredTransportChanged(@NetCapability int capability) { private void onEvaluatePreferredTransport(@NetCapability int capability) { int preferredTransport = mAccessNetworksManager .getPreferredTransportByNetworkCapability(capability); logl("onPreferredTransportChanged: " + DataUtils.networkCapabilityToString(capability) log("evaluatePreferredTransport: " + DataUtils.networkCapabilityToString(capability) + " preferred on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); for (DataNetwork dataNetwork : mDataNetworkList) { if (dataNetwork.getHighestPriorityNetworkCapability() == capability) { if (dataNetwork.getApnTypeNetworkCapability() == capability) { // Check if the data network's current transport is different than from the // preferred transport. If it's different, then handover is needed. if (dataNetwork.getTransport() == preferredTransport) { log("onPreferredTransportChanged:" + dataNetwork + " already on " log("evaluatePreferredTransport:" + dataNetwork + " already on " + AccessNetworkConstants.transportTypeToString(preferredTransport)); continue; } // If handover is ongoing, ignore the preference change for now. After handover // succeeds or fails, preferred transport will be re-evaluate again. Handover will // be performed at that time if needed. if (dataNetwork.isHandoverInProgress()) { log("evaluatePreferredTransport: " + dataNetwork + " handover in progress."); continue; } DataEvaluation dataEvaluation = evaluateDataNetworkHandover(dataNetwork); if (!dataEvaluation.containsDisallowedReasons()) { logl("Start handover " + dataNetwork + " to " Loading @@ -2449,7 +2467,7 @@ public class DataNetworkController extends Handler { dataNetwork.startHandover(preferredTransport, null); } else if (dataEvaluation.containsOnly( DataDisallowedReason.NOT_ALLOWED_BY_POLICY)) { logl("onPreferredTransportChanged: Handover not allowed by policy. Tear " logl("evaluatePreferredTransport: Handover not allowed by policy. Tear " + "down the network so a new network can be setup on " + AccessNetworkConstants.transportTypeToString(preferredTransport) + "."); Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +61 −5 Original line number Diff line number Diff line Loading @@ -86,6 +86,7 @@ import com.android.internal.telephony.ISub; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyTest; import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback; import com.android.internal.telephony.data.DataNetworkController.HandoverRule; import com.android.internal.telephony.data.DataRetryManager.DataRetryManagerCallback; Loading Loading @@ -126,6 +127,8 @@ public class DataNetworkControllerTest extends TelephonyTest { private DataNetworkController mDataNetworkControllerUT; private PersistableBundle mCarrierConfig; private AccessNetworksManagerCallback mAccessNetworksManagerCallback; private final DataProfile mGeneralPurposeDataProfile = new DataProfile.Builder() .setApnSetting(new ApnSetting.Builder() .setId(2163) Loading Loading @@ -501,6 +504,11 @@ public class DataNetworkControllerTest extends TelephonyTest { replaceInstance(DataNetworkController.class, "mAccessNetworksManager", mDataNetworkControllerUT, mAccessNetworksManager); ArgumentCaptor<AccessNetworksManagerCallback> callbackCaptor = ArgumentCaptor.forClass(AccessNetworksManagerCallback.class); verify(mAccessNetworksManager).registerCallback(callbackCaptor.capture()); mAccessNetworksManagerCallback = callbackCaptor.getValue(); doAnswer(invocation -> { TelephonyNetworkRequest networkRequest = (TelephonyNetworkRequest) invocation.getArguments()[0]; Loading Loading @@ -1027,7 +1035,7 @@ public class DataNetworkControllerTest extends TelephonyTest { .getPreferredTransportByNetworkCapability( eq(NetworkCapabilities.NET_CAPABILITY_INTERNET)); // Data remain disabled, but trigger the preference evaluation. mDataNetworkControllerUT.obtainMessage(21 /*EVENT_PREFERRED_TRANSPORT_CHANGED*/, mDataNetworkControllerUT.obtainMessage(21 /*EVENT_EVALUATE_PREFERRED_TRANSPORT*/, NetworkCapabilities.NET_CAPABILITY_INTERNET, 0).sendToTarget(); mDataNetworkControllerUT.obtainMessage(5 /*EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS*/, DataEvaluation.DataEvaluationReason.PREFERRED_TRANSPORT_CHANGED).sendToTarget(); Loading Loading @@ -1295,8 +1303,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mDataNetworkControllerUT.obtainMessage(21/*EVENT_EVALUATE_PREFERRED_TRANSPORT*/, NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); DataNetwork dataNetwork = getDataNetworks().get(0); Loading @@ -1305,6 +1313,54 @@ public class DataNetworkControllerTest extends TelephonyTest { AccessNetworkConstants.TRANSPORT_TYPE_WLAN); } @Test public void testHandoverDataNetworkBackToBackPreferenceChanged() throws Exception { testSetupImsDataNetwork(); Mockito.reset(mMockedWlanDataServiceManager); doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); // Capture the message for setup data call response. We want to delay it. ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class); verify(mMockedWlanDataServiceManager).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), messageCaptor.capture()); // Before setup data call response, change the preference back to cellular. doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WWAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); // Before setup data call response, change the preference back to IWLAN. doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); processAllMessages(); // Finally handover is completed. Message msg = messageCaptor.getValue(); DataCallResponse response = new DataCallResponse.Builder() .setCause(DataFailCause.NONE) .build(); msg.getData().putParcelable("data_call_response", response); msg.arg1 = DataServiceCallback.RESULT_SUCCESS; msg.sendToTarget(); processAllMessages(); // Make sure handover request is only sent once. verify(mMockedWlanDataServiceManager, times(1)).setupDataCall(anyInt(), any(DataProfile.class), anyBoolean(), anyBoolean(), anyInt(), any(), anyInt(), any(), any(), anyBoolean(), messageCaptor.capture()); } @Test public void testHandoverDataNetworkNotAllowedByPolicy() throws Exception { mCarrierConfig.putStringArray(CarrierConfigManager.KEY_IWLAN_HANDOVER_POLICY_STRING_ARRAY, Loading @@ -1318,8 +1374,8 @@ public class DataNetworkControllerTest extends TelephonyTest { doReturn(AccessNetworkConstants.TRANSPORT_TYPE_WLAN).when(mAccessNetworksManager) .getPreferredTransportByNetworkCapability(NetworkCapabilities.NET_CAPABILITY_IMS); mDataNetworkControllerUT.obtainMessage(21/*EVENT_PREFERRED_TRANSPORT_CHANGED*/, NetworkCapabilities.NET_CAPABILITY_IMS, 0).sendToTarget(); mAccessNetworksManagerCallback.onPreferredTransportChanged( NetworkCapabilities.NET_CAPABILITY_IMS); // After this, IMS data network should be disconnected, and DNC should attempt to // establish a new one on IWLAN processAllMessages(); Loading