Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3357f4d7 authored by Ling Ma's avatar Ling Ma
Browse files

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
parent f38bf26b
Loading
Loading
Loading
Loading
+61 −40
Original line number Diff line number Diff line
@@ -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;
+15 −0
Original line number Diff line number Diff line
@@ -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) {
+16 −0
Original line number Diff line number Diff line
@@ -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) {
+55 −0
Original line number Diff line number Diff line
@@ -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
+41 −0
Original line number Diff line number Diff line
@@ -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);
    }
}