diff options
author | Ling Ma <linggm@google.com> | 2024-02-13 21:42:25 -0800 |
---|---|---|
committer | Ling Ma <linggm@google.com> | 2024-02-16 13:42:23 -0800 |
commit | 3357f4d74602ecd980641c9fca02c0459e5ccedb (patch) | |
tree | 569473c1d1dcd49d13ce983e0ee2c1b69347a9f9 | |
parent | f38bf26b294304172477800325fe1790a2eba809 (diff) | |
download | telephony-3357f4d74602ecd980641c9fca02c0459e5ccedb.tar.gz |
Reset timers upon ims voice call
For VoLTE/VoNr/Emergencycall, if qos bearer session has available type "conversational voice", reset all timers.
Fix: 316425342
Test: Mock emergency call and confirm by log
Test: basic voice call and data browsing
Change-Id: I07aabdc55a215aeded09b949de9911f271264b3c
5 files changed, 188 insertions, 40 deletions
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index db4fd89c4c..deb8427385 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -37,6 +37,9 @@ import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.DataCallResponse; import android.telephony.data.DataCallResponse.LinkStatus; +import android.telephony.data.EpsQos; +import android.telephony.data.NrQos; +import android.telephony.data.QosBearerSession; import android.text.TextUtils; import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; @@ -112,8 +115,10 @@ public class NetworkTypeController extends StateMachine { private static final int EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED = 11; /** Event for device idle mode changed, when device goes to deep sleep and pauses all timers. */ private static final int EVENT_DEVICE_IDLE_MODE_CHANGED = 12; + /** Event for qos sessions changed. */ + private static final int EVENT_QOS_SESSION_CHANGED = 13; - private static final String[] sEvents = new String[EVENT_DEVICE_IDLE_MODE_CHANGED + 1]; + private static final String[] sEvents = new String[EVENT_QOS_SESSION_CHANGED + 1]; static { sEvents[EVENT_UPDATE] = "EVENT_UPDATE"; sEvents[EVENT_QUIT] = "EVENT_QUIT"; @@ -129,6 +134,7 @@ public class NetworkTypeController extends StateMachine { sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE"; sEvents[EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED"; sEvents[EVENT_DEVICE_IDLE_MODE_CHANGED] = "EVENT_DEVICE_IDLE_MODE_CHANGED"; + sEvents[EVENT_QOS_SESSION_CHANGED] = "EVENT_QOS_SESSION_CHANGED"; } @NonNull private final Phone mPhone; @@ -158,6 +164,31 @@ public class NetworkTypeController extends StateMachine { } }; + @NonNull private final DataNetworkControllerCallback mDataNetworkControllerCallback = + new DataNetworkControllerCallback(getHandler()::post) { + @Override + public void onQosSessionsChanged( + @NonNull List<QosBearerSession> qosBearerSessions) { + if (!mIsTimerResetEnabledOnVoiceQos) return; + sendMessage(obtainMessage(EVENT_QOS_SESSION_CHANGED, qosBearerSessions)); + } + + @Override + public void onNrAdvancedCapableByPcoChanged(boolean nrAdvancedCapable) { + if (mNrAdvancedCapablePcoId <= 0) return; + log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); + mIsNrAdvancedAllowedByPco = nrAdvancedCapable; + sendMessage(EVENT_UPDATE); + } + + @Override + public void onPhysicalLinkStatusChanged(@LinkStatus int status) { + if (isUsingPhysicalChannelConfigForRrcDetection()) return; + sendMessage(obtainMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, + new AsyncResult(null, status, null))); + } + }; + @NonNull private Map<String, OverrideTimerRule> mOverrideTimerRules = new HashMap<>(); @NonNull private String mLteEnhancedPattern = ""; @Annotation.OverrideNetworkType private int mOverrideNetworkType; @@ -165,7 +196,10 @@ public class NetworkTypeController extends StateMachine { private boolean mIsPrimaryTimerActive; private boolean mIsSecondaryTimerActive; private boolean mIsTimerResetEnabledForLegacyStateRrcIdle; + /** Carrier config to reset timers when mccmnc changes */ private boolean mIsTimerResetEnabledOnPlmnChanges; + /** Carrier config to reset timers when QCI(LTE) or 5QI(NR) is 1(conversational voice) */ + private boolean mIsTimerResetEnabledOnVoiceQos; private int mLtePlusThresholdBandwidth; private int mNrAdvancedThresholdBandwidth; private boolean mIncludeLteForNrAdvancedThresholdBandwidth; @@ -185,9 +219,6 @@ public class NetworkTypeController extends StateMachine { private boolean mIsDeviceIdleMode = false; private boolean mPrimaryCellChangedWhileIdle = false; - @Nullable private DataNetworkControllerCallback mNrAdvancedCapableByPcoChangedCallback = null; - @Nullable private DataNetworkControllerCallback mNrPhysicalLinkStatusChangedCallback = null; - // Cached copies below to prevent race conditions @NonNull private ServiceState mServiceState; @Nullable private List<PhysicalChannelConfig> mPhysicalChannelConfigs; @@ -276,6 +307,8 @@ public class NetworkTypeController extends StateMachine { TelephonyManager.CAPABILITY_PHYSICAL_CHANNEL_CONFIG_1_6_SUPPORTED); mPhone.getDeviceStateMonitor().registerForPhysicalChannelConfigNotifChanged(getHandler(), EVENT_PHYSICAL_CHANNEL_CONFIG_NOTIF_CHANGED, null); + mPhone.getDataNetworkController().registerDataNetworkControllerCallback( + mDataNetworkControllerCallback); IntentFilter filter = new IntentFilter(); filter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED); mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone); @@ -288,6 +321,8 @@ public class NetworkTypeController extends StateMachine { mPhone.unregisterForPreferredNetworkTypeChanged(getHandler()); mPhone.getServiceStateTracker().unregisterForServiceStateChanged(getHandler()); mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler()); + mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( + mDataNetworkControllerCallback); mPhone.getContext().unregisterReceiver(mIntentReceiver); CarrierConfigManager ccm = mPhone.getContext().getSystemService(CarrierConfigManager.class); if (mCarrierConfigChangeListener != null) { @@ -311,6 +346,8 @@ public class NetworkTypeController extends StateMachine { CarrierConfigManager.KEY_NR_TIMERS_RESET_IF_NON_ENDC_AND_RRC_IDLE_BOOL); mIsTimerResetEnabledOnPlmnChanges = config.getBoolean( CarrierConfigManager.KEY_NR_TIMERS_RESET_ON_PLMN_CHANGE_BOOL); + mIsTimerResetEnabledOnVoiceQos = config.getBoolean( + CarrierConfigManager.KEY_NR_TIMERS_RESET_ON_VOICE_QOS_BOOL); mLtePlusThresholdBandwidth = config.getInt( CarrierConfigManager.KEY_LTE_PLUS_THRESHOLD_BANDWIDTH_KHZ_INT); mNrAdvancedThresholdBandwidth = config.getInt( @@ -329,43 +366,8 @@ public class NetworkTypeController extends StateMachine { } mNrAdvancedCapablePcoId = config.getInt( CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT); - if (mNrAdvancedCapablePcoId > 0 && mNrAdvancedCapableByPcoChangedCallback == null) { - mNrAdvancedCapableByPcoChangedCallback = - new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onNrAdvancedCapableByPcoChanged(boolean nrAdvancedCapable) { - log("mIsNrAdvancedAllowedByPco=" + nrAdvancedCapable); - mIsNrAdvancedAllowedByPco = nrAdvancedCapable; - sendMessage(EVENT_UPDATE); - } - }; - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( - mNrAdvancedCapableByPcoChangedCallback); - } else if (mNrAdvancedCapablePcoId == 0 && mNrAdvancedCapableByPcoChangedCallback != null) { - mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mNrAdvancedCapableByPcoChangedCallback); - mNrAdvancedCapableByPcoChangedCallback = null; - } mIsUsingUserDataForRrcDetection = config.getBoolean( CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL); - if (!isUsingPhysicalChannelConfigForRrcDetection()) { - if (mNrPhysicalLinkStatusChangedCallback == null) { - mNrPhysicalLinkStatusChangedCallback = - new DataNetworkControllerCallback(getHandler()::post) { - @Override - public void onPhysicalLinkStatusChanged(@LinkStatus int status) { - sendMessage(obtainMessage(EVENT_PHYSICAL_LINK_STATUS_CHANGED, - new AsyncResult(null, status, null))); - } - }; - mPhone.getDataNetworkController().registerDataNetworkControllerCallback( - mNrPhysicalLinkStatusChangedCallback); - } - } else if (mNrPhysicalLinkStatusChangedCallback != null) { - mPhone.getDataNetworkController().unregisterDataNetworkControllerCallback( - mNrPhysicalLinkStatusChangedCallback); - mNrPhysicalLinkStatusChangedCallback = null; - } mNrAdvancedBandsSecondaryTimer = config.getInt( CarrierConfigManager.KEY_NR_ADVANCED_BANDS_SECONDARY_TIMER_SECONDS_INT); String nrIconConfiguration = config.getString( @@ -703,6 +705,24 @@ public class NetworkTypeController extends StateMachine { } transitionToCurrentState(); break; + case EVENT_QOS_SESSION_CHANGED: + List<QosBearerSession> qosBearerSessions = (List<QosBearerSession>) msg.obj; + boolean inVoiceCall = false; + for (QosBearerSession session : qosBearerSessions) { + // TS 23.203 23.501 - 1 means conversational voice + if (session.getQos() instanceof EpsQos qos) { + inVoiceCall = qos.getQci() == 1; + } else if (session.getQos() instanceof NrQos qos) { + inVoiceCall = qos.get5Qi() == 1; + } + if (inVoiceCall) { + if (DBG) log("Device in voice call, reset all timers"); + resetAllTimers(); + transitionToCurrentState(); + break; + } + } + break; default: throw new RuntimeException("Received invalid event: " + msg.what); } @@ -772,6 +792,7 @@ public class NetworkTypeController extends StateMachine { if (mIsTimerResetEnabledForLegacyStateRrcIdle && !isPhysicalLinkActive()) { if (DBG) log("Reset timers since timer reset is enabled for RRC idle."); resetAllTimers(); + updateOverrideNetworkType(); } } break; @@ -1338,7 +1359,7 @@ public class NetworkTypeController extends StateMachine { int duration = rule.getSecondaryTimer(currentName); if (mLastShownNrDueToAdvancedBand && mNrAdvancedBandsSecondaryTimer > 0) { duration = mNrAdvancedBandsSecondaryTimer; - if (DBG) log("secondary timer adjusted by nr_advanced_bands_secondary_timer_long"); + if (DBG) log("timer adjusted by nr_advanced_bands_secondary_timer_seconds_int"); } if (DBG) log(duration + "s secondary timer started for state: " + currentName); mSecondaryTimerState = currentName; diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index b99065b142..c1e61c6f08 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -122,6 +122,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -921,6 +922,14 @@ public class DataNetwork extends StateMachine { */ public abstract void onRetryUnsatisfiedNetworkRequest( @NonNull TelephonyNetworkRequest networkRequest); + + /** + * Called when QosBearerSessions bearer changed, which indicates VoNr or VoLte calls. + * + * @param qosBearerSessions The current qosBearerSessions. + */ + public abstract void onQosSessionsChanged( + @NonNull List<QosBearerSession> qosBearerSessions); } /** @@ -2676,6 +2685,12 @@ public class DataNetwork extends StateMachine { mDefaultQos = response.getDefaultQos(); + + Set<QosBearerSession> newSessions = new HashSet<>(response.getQosBearerSessions()); + if (newSessions.size() != mQosBearerSessions.size() + || !newSessions.containsAll(mQosBearerSessions)) { + mDataNetworkCallback.onQosSessionsChanged(response.getQosBearerSessions()); + } mQosBearerSessions.clear(); mQosBearerSessions.addAll(response.getQosBearerSessions()); if (mQosCallbackTracker != null) { diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 62449f5234..2fb23a738e 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -69,6 +69,7 @@ import android.telephony.data.DataCallResponse.HandoverFailureMode; import android.telephony.data.DataCallResponse.LinkStatus; import android.telephony.data.DataProfile; import android.telephony.data.DataServiceCallback; +import android.telephony.data.QosBearerSession; import android.telephony.ims.ImsException; import android.telephony.ims.ImsManager; import android.telephony.ims.ImsReasonInfo; @@ -647,6 +648,13 @@ public class DataNetworkController extends Handler { * @param simState The current SIM state */ public void onSimStateChanged(@SimState int simState) {} + + /** + * Called when QosBearerSessions changed. + * + * @param qosBearerSessions The latest QOS bearer sessions. + */ + public void onQosSessionsChanged(@NonNull List<QosBearerSession> qosBearerSessions) {} } /** @@ -2786,6 +2794,14 @@ public class DataNetworkController extends Handler { DataNetworkController.this.onRetryUnsatisfiedNetworkRequest( networkRequest); } + + @Override + public void onQosSessionsChanged( + @NonNull List<QosBearerSession> qosBearerSessions) { + mDataNetworkControllerCallbacks.forEach( + callback -> callback.invokeFromExecutor(() -> + callback.onQosSessionsChanged(qosBearerSessions))); + } } )); if (!mAnyDataNetworkExisting) { diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index 470902bb48..0ab3c0ecfb 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -43,6 +43,9 @@ import android.telephony.ServiceState; import android.telephony.TelephonyDisplayInfo; import android.telephony.TelephonyManager; import android.telephony.data.DataCallResponse; +import android.telephony.data.EpsQos; +import android.telephony.data.Qos; +import android.telephony.data.QosBearerSession; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -58,6 +61,7 @@ import org.mockito.ArgumentCaptor; import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @RunWith(AndroidTestingRunner.class) @@ -1893,6 +1897,57 @@ public class NetworkTypeControllerTest extends TelephonyTest { assertFalse(mNetworkTypeController.areAnyTimersActive()); } + @Test + public void testNrTimerResetWhenVoiceQos() throws Exception { + testTransitionToCurrentStateNrConnectedMmwave(); + mBundle.putBoolean(CarrierConfigManager.KEY_NR_TIMERS_RESET_ON_VOICE_QOS_BOOL, + true); + mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_GRACE_PERIOD_STRING, + "connected_mmwave,any,10;connected,any,10;not_restricted_rrc_con,any,10"); + mBundle.putString(CarrierConfigManager.KEY_5G_ICON_DISPLAY_SECONDARY_GRACE_PERIOD_STRING, + "connected_mmwave,any,30"); + sendCarrierConfigChanged(); + + // should trigger 10 second primary timer + doReturn(NetworkRegistrationInfo.NR_STATE_NONE).when(mServiceState).getNrState(); + doReturn(ServiceState.FREQUENCY_RANGE_UNKNOWN).when(mServiceState).getNrFrequencyRange(); + mNetworkTypeController.sendMessage(3 /* EVENT_SERVICE_STATE_CHANGED */); + processAllMessages(); + + assertEquals("legacy", getCurrentState().getName()); + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, + mNetworkTypeController.getOverrideNetworkType()); + assertTrue(mNetworkTypeController.areAnyTimersActive()); + + // Qos changed, but not in call, so no thing happens. + ArgumentCaptor<DataNetworkControllerCallback> dataNetworkControllerCallbackCaptor = + ArgumentCaptor.forClass(DataNetworkControllerCallback.class); + verify(mDataNetworkController).registerDataNetworkControllerCallback( + dataNetworkControllerCallbackCaptor.capture()); + DataNetworkControllerCallback callback = dataNetworkControllerCallbackCaptor.getValue(); + callback.onQosSessionsChanged(List.of( + new QosBearerSession(1, new EpsQos( + new Qos.QosBandwidth(1000, 1), + new Qos.QosBandwidth(1000, 0), + 9 /* QCI */), Collections.emptyList()))); + processAllMessages(); + + // Confirm if QCI not 1, timers are still active. + assertTrue(mNetworkTypeController.areAnyTimersActive()); + + // Send Voice QOS where QCI is 1, confirm timers are cancelled. + callback.onQosSessionsChanged(List.of( + new QosBearerSession(1, new EpsQos( + new Qos.QosBandwidth(1000, 1), + new Qos.QosBandwidth(1000, 0), + 1 /* QCI */), Collections.emptyList()))); + processAllMessages(); + + assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE, + mNetworkTypeController.getOverrideNetworkType()); + assertFalse(mNetworkTypeController.areAnyTimersActive()); + } + private void setPhysicalLinkStatus(boolean state) { List<PhysicalChannelConfig> lastPhysicalChannelConfigList = new ArrayList<>(); // If PhysicalChannelConfigList is empty, PhysicalLinkStatus is diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java index ad1ba61325..83c583b3e4 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java @@ -68,6 +68,7 @@ import android.telephony.data.DataServiceCallback; import android.telephony.data.EpsQos; import android.telephony.data.NetworkSliceInfo; import android.telephony.data.Qos; +import android.telephony.data.QosBearerSession; import android.telephony.data.TrafficDescriptor; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -2260,4 +2261,44 @@ public class DataNetworkTest extends TelephonyTest { assertThat(mDataNetworkUT.getNetworkCapabilities() .hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)).isTrue(); } + + @Test + public void testQosSessionsChanged() throws Exception { + createImsDataNetwork(false/*isMmtel*/); + List<QosBearerSession> newQosSessions = + List.of(new QosBearerSession(1, mDefaultQos, Collections.emptyList())); + DataCallResponse response = new DataCallResponse.Builder() + .setCause(0) + .setRetryDurationMillis(-1L) + .setId(123) + .setLinkStatus(DataCallResponse.LINK_STATUS_ACTIVE) + .setProtocolType(ApnSetting.PROTOCOL_IPV4V6) + .setInterfaceName("ifname") + .setAddresses(Arrays.asList( + new LinkAddress(InetAddresses.parseNumericAddress(IPV4_ADDRESS), 32), + new LinkAddress(IPV6_ADDRESS + "/64"))) + .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress("10.0.2.3"), + InetAddresses.parseNumericAddress("fd00:976a::9"))) + .setGatewayAddresses(Arrays.asList( + InetAddresses.parseNumericAddress("10.0.2.15"), + InetAddresses.parseNumericAddress("fe80::2"))) + .setPcscfAddresses(Arrays.asList( + InetAddresses.parseNumericAddress("fd00:976a:c305:1d::8"), + InetAddresses.parseNumericAddress("fd00:976a:c202:1d::7"), + InetAddresses.parseNumericAddress("fd00:976a:c305:1d::5"))) + .setMtuV4(1234) + .setPduSessionId(1) + .setQosBearerSessions(newQosSessions) + .setTrafficDescriptors(Collections.emptyList()) + .setDefaultQos(mDefaultQos) + .build(); + + // Qos sessions list changed + mDataNetworkUT.obtainMessage(8/*EVENT_DATA_STATE_CHANGED*/, + new AsyncResult(AccessNetworkConstants.TRANSPORT_TYPE_WWAN, + List.of(response), null)).sendToTarget(); + processAllMessages(); + + verify(mDataNetworkCallback).onQosSessionsChanged(newQosSessions); + } } |