Loading src/java/com/android/internal/telephony/data/DataEvaluation.java +2 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,8 @@ public class DataEvaluation { PREFERRED_TRANSPORT_CHANGED(true), /** Slice config changed. */ SLICE_CONFIG_CHANGED(true), /** SRVCC state changed. */ SRVCC_STATE_CHANGED(true), /** * Single data network arbitration. On certain RATs, only one data network is allowed at the * same time. Loading src/java/com/android/internal/telephony/data/DataNetwork.java +1 −12 Original line number Diff line number Diff line Loading @@ -1332,17 +1332,6 @@ public class DataNetwork extends StateMachine { } int tearDownReason = msg.arg1; // If the tear down request is from upper layer, for example, IMS service // releases network request, we don't need to delay. The purpose of the delay // is to have IMS service have time to perform IMS de-registration, so if this // request is from IMS service itself, that means IMS service is already aware // of the tear down. So there is no need to delay in this case. if (tearDownReason != TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED && shouldDelayImsTearDown()) { logl("Delay IMS tear down until call ends. reason=" + tearDownReasonToString(tearDownReason)); break; } removeMessages(EVENT_TEAR_DOWN_NETWORK); removeDeferredMessages(EVENT_TEAR_DOWN_NETWORK); Loading Loading @@ -2583,7 +2572,7 @@ public class DataNetwork extends StateMachine { * @return {@code true} if this is an IMS network and tear down should be delayed until call * ends on this data network. */ public boolean shouldDelayImsTearDown() { public boolean shouldDelayImsTearDownDueToInCall() { return mDataConfigManager.isImsDelayTearDownEnabled() && mNetworkCapabilities != null && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL) Loading src/java/com/android/internal/telephony/data/DataNetworkController.java +42 −4 Original line number Diff line number Diff line Loading @@ -140,6 +140,9 @@ public class DataNetworkController extends Handler { /** Event for removing a network request. */ private static final int EVENT_REMOVE_NETWORK_REQUEST = 3; /** Event for SRVCC state changed. */ private static final int EVENT_SRVCC_STATE_CHANGED = 4; /** Re-evaluate all unsatisfied network requests. */ private static final int EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS = 5; Loading Loading @@ -302,6 +305,9 @@ public class DataNetworkController extends Handler { /** Indicates if NR advanced is allowed by PCO. */ private boolean mNrAdvancedCapableByPco = false; /** Indicates if srvcc is going on. */ private boolean mIsSrvccHandoverInProcess = false; /** * Indicates if the data services are bound. Key if the transport type, and value is the boolean * indicating service is bound or not. Loading Loading @@ -898,7 +904,7 @@ public class DataNetworkController extends Handler { preferredTransport)); return; } if (dataNetwork.shouldDelayImsTearDown()) { if (dataNetwork.shouldDelayImsTearDownDueToInCall()) { log("onDataNetworkHandoverRetryStopped: Delay IMS tear down until call " + "ends. " + dataNetwork); return; Loading Loading @@ -1010,6 +1016,7 @@ public class DataNetworkController extends Handler { this, EVENT_VOICE_CALL_ENDED, null); } mPhone.mCi.registerForSlicingConfigChanged(this, EVENT_SLICE_CONFIG_CHANGED, null); mPhone.mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); mPhone.getLinkBandwidthEstimator().registerCallback( new LinkBandwidthEstimatorCallback(this::post) { Loading @@ -1023,6 +1030,7 @@ public class DataNetworkController extends Handler { @Override public void handleMessage(@NonNull Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_REGISTER_ALL_EVENTS: onRegisterAllEvents(); Loading Loading @@ -1057,6 +1065,12 @@ public class DataNetworkController extends Handler { sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, DataEvaluationReason.SLICE_CONFIG_CHANGED)); break; case EVENT_SRVCC_STATE_CHANGED: ar = (AsyncResult) msg.obj; if (ar.exception == null) { onSrvccStateChanged((int[]) ar.result); } break; case EVENT_PS_RESTRICT_ENABLED: mPsRestricted = true; break; Loading @@ -1073,7 +1087,7 @@ public class DataNetworkController extends Handler { REEVALUATE_UNSATISFIED_NETWORK_REQUESTS_TAC_CHANGED_DELAY_MILLIS); break; case EVENT_DATA_SERVICE_BINDING_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; ar = (AsyncResult) msg.obj; int transport = (int) ar.userObj; boolean bound = (boolean) ar.result; onDataServiceBindingChanged(transport, bound); Loading Loading @@ -1735,13 +1749,15 @@ public class DataNetworkController extends Handler { } } boolean isMmtel = false; // If the data network is IMS that supports voice call, and has MMTEL request (client // specified VoPS is required.) if (dataNetwork.getAttachedNetworkRequestList().get( new int[]{NetworkCapabilities.NET_CAPABILITY_MMTEL}) != null) { // When reaching here, it means the network supports MMTEL, and also has MMTEL request // attached to it. if (!dataNetwork.shouldDelayImsTearDown()) { isMmtel = true; if (!dataNetwork.shouldDelayImsTearDownDueToInCall()) { if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, Loading Loading @@ -1788,7 +1804,9 @@ public class DataNetworkController extends Handler { // Sometimes network temporarily OOS and network type becomes UNKNOWN. We don't // tear down network in that case. if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType)) { && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType) // delay IMS tear down if SRVCC in progress && !(isMmtel && mIsSrvccHandoverInProcess)) { log("networkType=" + TelephonyManager.getNetworkTypeName(networkType) + ", networkTypeBitmask=" + TelephonyManager.convertNetworkTypeBitmaskToString( Loading Loading @@ -2955,6 +2973,25 @@ public class DataNetworkController extends Handler { DataNetwork.TEAR_DOWN_REASON_DATA_STALL)); } /** * Called when SRVCC handover state changes. To preserve the voice call, we don't tear down the * IMS network while handover in process. We reevaluate the network when handover ends. * * @param state The handover state of SRVCC */ private void onSrvccStateChanged(@NonNull int[] state) { if (state != null && state.length != 0) { log("onSrvccStateChanged: " + TelephonyManager.srvccStateToString(state[0])); mIsSrvccHandoverInProcess = state[0] == TelephonyManager.SRVCC_STATE_HANDOVER_STARTED; // Reevaluate networks if SRVCC ends. if (!mIsSrvccHandoverInProcess && !hasMessages(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)) { sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS, DataEvaluationReason.SRVCC_STATE_CHANGED)); } } } /** * Called when data service binding changed. * Loading Loading @@ -3707,6 +3744,7 @@ public class DataNetworkController extends Handler { pw.println("mImsDataNetworkState=" + TelephonyUtils.dataStateToString(mImsDataNetworkState)); pw.println("mDataServiceBound=" + mDataServiceBound); pw.println("mIsSrvccHandoverInProcess=" + mIsSrvccHandoverInProcess); pw.println("mSimState=" + TelephonyManager.simStateToString(mSimState)); pw.println("mDataNetworkControllerCallbacks=" + mDataNetworkControllerCallbacks); pw.println("Subscription plans:"); Loading tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -3153,6 +3153,33 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); } @Test public void testDelayImsTearDownDuringSrvcc() throws Exception { testSetupImsDataNetwork(); // SRVCC in progress, delay tear down mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, new AsyncResult(null, new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_STARTED}, null)) .sendToTarget(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_HSPAP, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); processAllMessages(); // Make sure IMS network is still connected. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_MMTEL); // SRVCC handover ends, tear down as normal mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, new AsyncResult(null, new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED}, null)) .sendToTarget(); processAllFutureMessages(); // Make sure IMS network is torn down verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); } @Test public void testUnmeteredMmsWhenDataDisabled() throws Exception { mCarrierConfig.putStringArray( Loading Loading
src/java/com/android/internal/telephony/data/DataEvaluation.java +2 −0 Original line number Diff line number Diff line Loading @@ -230,6 +230,8 @@ public class DataEvaluation { PREFERRED_TRANSPORT_CHANGED(true), /** Slice config changed. */ SLICE_CONFIG_CHANGED(true), /** SRVCC state changed. */ SRVCC_STATE_CHANGED(true), /** * Single data network arbitration. On certain RATs, only one data network is allowed at the * same time. Loading
src/java/com/android/internal/telephony/data/DataNetwork.java +1 −12 Original line number Diff line number Diff line Loading @@ -1332,17 +1332,6 @@ public class DataNetwork extends StateMachine { } int tearDownReason = msg.arg1; // If the tear down request is from upper layer, for example, IMS service // releases network request, we don't need to delay. The purpose of the delay // is to have IMS service have time to perform IMS de-registration, so if this // request is from IMS service itself, that means IMS service is already aware // of the tear down. So there is no need to delay in this case. if (tearDownReason != TEAR_DOWN_REASON_CONNECTIVITY_SERVICE_UNWANTED && shouldDelayImsTearDown()) { logl("Delay IMS tear down until call ends. reason=" + tearDownReasonToString(tearDownReason)); break; } removeMessages(EVENT_TEAR_DOWN_NETWORK); removeDeferredMessages(EVENT_TEAR_DOWN_NETWORK); Loading Loading @@ -2583,7 +2572,7 @@ public class DataNetwork extends StateMachine { * @return {@code true} if this is an IMS network and tear down should be delayed until call * ends on this data network. */ public boolean shouldDelayImsTearDown() { public boolean shouldDelayImsTearDownDueToInCall() { return mDataConfigManager.isImsDelayTearDownEnabled() && mNetworkCapabilities != null && mNetworkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL) Loading
src/java/com/android/internal/telephony/data/DataNetworkController.java +42 −4 Original line number Diff line number Diff line Loading @@ -140,6 +140,9 @@ public class DataNetworkController extends Handler { /** Event for removing a network request. */ private static final int EVENT_REMOVE_NETWORK_REQUEST = 3; /** Event for SRVCC state changed. */ private static final int EVENT_SRVCC_STATE_CHANGED = 4; /** Re-evaluate all unsatisfied network requests. */ private static final int EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS = 5; Loading Loading @@ -302,6 +305,9 @@ public class DataNetworkController extends Handler { /** Indicates if NR advanced is allowed by PCO. */ private boolean mNrAdvancedCapableByPco = false; /** Indicates if srvcc is going on. */ private boolean mIsSrvccHandoverInProcess = false; /** * Indicates if the data services are bound. Key if the transport type, and value is the boolean * indicating service is bound or not. Loading Loading @@ -898,7 +904,7 @@ public class DataNetworkController extends Handler { preferredTransport)); return; } if (dataNetwork.shouldDelayImsTearDown()) { if (dataNetwork.shouldDelayImsTearDownDueToInCall()) { log("onDataNetworkHandoverRetryStopped: Delay IMS tear down until call " + "ends. " + dataNetwork); return; Loading Loading @@ -1010,6 +1016,7 @@ public class DataNetworkController extends Handler { this, EVENT_VOICE_CALL_ENDED, null); } mPhone.mCi.registerForSlicingConfigChanged(this, EVENT_SLICE_CONFIG_CHANGED, null); mPhone.mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null); mPhone.getLinkBandwidthEstimator().registerCallback( new LinkBandwidthEstimatorCallback(this::post) { Loading @@ -1023,6 +1030,7 @@ public class DataNetworkController extends Handler { @Override public void handleMessage(@NonNull Message msg) { AsyncResult ar; switch (msg.what) { case EVENT_REGISTER_ALL_EVENTS: onRegisterAllEvents(); Loading Loading @@ -1057,6 +1065,12 @@ public class DataNetworkController extends Handler { sendMessage(obtainMessage(EVENT_REEVALUATE_UNSATISFIED_NETWORK_REQUESTS, DataEvaluationReason.SLICE_CONFIG_CHANGED)); break; case EVENT_SRVCC_STATE_CHANGED: ar = (AsyncResult) msg.obj; if (ar.exception == null) { onSrvccStateChanged((int[]) ar.result); } break; case EVENT_PS_RESTRICT_ENABLED: mPsRestricted = true; break; Loading @@ -1073,7 +1087,7 @@ public class DataNetworkController extends Handler { REEVALUATE_UNSATISFIED_NETWORK_REQUESTS_TAC_CHANGED_DELAY_MILLIS); break; case EVENT_DATA_SERVICE_BINDING_CHANGED: AsyncResult ar = (AsyncResult) msg.obj; ar = (AsyncResult) msg.obj; int transport = (int) ar.userObj; boolean bound = (boolean) ar.result; onDataServiceBindingChanged(transport, bound); Loading Loading @@ -1735,13 +1749,15 @@ public class DataNetworkController extends Handler { } } boolean isMmtel = false; // If the data network is IMS that supports voice call, and has MMTEL request (client // specified VoPS is required.) if (dataNetwork.getAttachedNetworkRequestList().get( new int[]{NetworkCapabilities.NET_CAPABILITY_MMTEL}) != null) { // When reaching here, it means the network supports MMTEL, and also has MMTEL request // attached to it. if (!dataNetwork.shouldDelayImsTearDown()) { isMmtel = true; if (!dataNetwork.shouldDelayImsTearDownDueToInCall()) { if (dataNetwork.getTransport() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) { NetworkRegistrationInfo nri = mServiceState.getNetworkRegistrationInfo( NetworkRegistrationInfo.DOMAIN_PS, Loading Loading @@ -1788,7 +1804,9 @@ public class DataNetworkController extends Handler { // Sometimes network temporarily OOS and network type becomes UNKNOWN. We don't // tear down network in that case. if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType)) { && !dataProfile.getApnSetting().canSupportLingeringNetworkType(networkType) // delay IMS tear down if SRVCC in progress && !(isMmtel && mIsSrvccHandoverInProcess)) { log("networkType=" + TelephonyManager.getNetworkTypeName(networkType) + ", networkTypeBitmask=" + TelephonyManager.convertNetworkTypeBitmaskToString( Loading Loading @@ -2955,6 +2973,25 @@ public class DataNetworkController extends Handler { DataNetwork.TEAR_DOWN_REASON_DATA_STALL)); } /** * Called when SRVCC handover state changes. To preserve the voice call, we don't tear down the * IMS network while handover in process. We reevaluate the network when handover ends. * * @param state The handover state of SRVCC */ private void onSrvccStateChanged(@NonNull int[] state) { if (state != null && state.length != 0) { log("onSrvccStateChanged: " + TelephonyManager.srvccStateToString(state[0])); mIsSrvccHandoverInProcess = state[0] == TelephonyManager.SRVCC_STATE_HANDOVER_STARTED; // Reevaluate networks if SRVCC ends. if (!mIsSrvccHandoverInProcess && !hasMessages(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS)) { sendMessage(obtainMessage(EVENT_REEVALUATE_EXISTING_DATA_NETWORKS, DataEvaluationReason.SRVCC_STATE_CHANGED)); } } } /** * Called when data service binding changed. * Loading Loading @@ -3707,6 +3744,7 @@ public class DataNetworkController extends Handler { pw.println("mImsDataNetworkState=" + TelephonyUtils.dataStateToString(mImsDataNetworkState)); pw.println("mDataServiceBound=" + mDataServiceBound); pw.println("mIsSrvccHandoverInProcess=" + mIsSrvccHandoverInProcess); pw.println("mSimState=" + TelephonyManager.simStateToString(mSimState)); pw.println("mDataNetworkControllerCallbacks=" + mDataNetworkControllerCallbacks); pw.println("Subscription plans:"); Loading
tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +27 −0 Original line number Diff line number Diff line Loading @@ -3153,6 +3153,33 @@ public class DataNetworkControllerTest extends TelephonyTest { verifyAllDataDisconnected(); } @Test public void testDelayImsTearDownDuringSrvcc() throws Exception { testSetupImsDataNetwork(); // SRVCC in progress, delay tear down mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, new AsyncResult(null, new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_STARTED}, null)) .sendToTarget(); serviceStateChanged(TelephonyManager.NETWORK_TYPE_HSPAP, NetworkRegistrationInfo.REGISTRATION_STATE_HOME); processAllMessages(); // Make sure IMS network is still connected. verifyConnectedNetworkHasCapabilities(NetworkCapabilities.NET_CAPABILITY_IMS, NetworkCapabilities.NET_CAPABILITY_MMTEL); // SRVCC handover ends, tear down as normal mDataNetworkControllerUT.obtainMessage(4 /*EVENT_SRVCC_STATE_CHANGED*/, new AsyncResult(null, new int[]{TelephonyManager.SRVCC_STATE_HANDOVER_CANCELED}, null)) .sendToTarget(); processAllFutureMessages(); // Make sure IMS network is torn down verifyNoConnectedNetworkHasCapability(NetworkCapabilities.NET_CAPABILITY_MMTEL); } @Test public void testUnmeteredMmsWhenDataDisabled() throws Exception { mCarrierConfig.putStringArray( Loading