Loading src/java/com/android/internal/telephony/NetworkTypeController.java +33 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.os.AsyncResult; import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.SystemClock; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.CarrierConfigManager; Loading Loading @@ -194,6 +195,7 @@ public class NetworkTypeController extends StateMachine { private boolean mIsPhysicalChannelConfigOn; private boolean mIsPrimaryTimerActive; private boolean mIsSecondaryTimerActive; private long mSecondaryTimerExpireTimestamp; private boolean mIsTimerResetEnabledForLegacyStateRrcIdle; /** Carrier config to reset timers when mccmnc changes */ private boolean mIsTimerResetEnabledOnPlmnChanges; Loading @@ -220,6 +222,7 @@ public class NetworkTypeController extends StateMachine { // Cached copies below to prevent race conditions @NonNull private ServiceState mServiceState; /** Used to track link status to be DORMANT or ACTIVE */ @Nullable private List<PhysicalChannelConfig> mPhysicalChannelConfigs; // Ratchet physical channel config fields to prevent 5G/5G+ flickering Loading Loading @@ -666,6 +669,7 @@ public class NetworkTypeController extends StateMachine { case EVENT_SECONDARY_TIMER_EXPIRED: if (DBG) log("Secondary timer expired for state: " + mSecondaryTimerState); mIsSecondaryTimerActive = false; mSecondaryTimerExpireTimestamp = 0; mSecondaryTimerState = ""; updateTimers(); mLastShownNrDueToAdvancedBand = false; Loading Loading @@ -1251,6 +1255,8 @@ public class NetworkTypeController extends StateMachine { private void updatePhysicalChannelConfigs(List<PhysicalChannelConfig> physicalChannelConfigs) { boolean isPccListEmpty = physicalChannelConfigs == null || physicalChannelConfigs.isEmpty(); if (isPccListEmpty && isUsingPhysicalChannelConfigForRrcDetection()) { // Clear mPrimaryCellChangedWhileIdle to allow later potential one-off PCI change. // Update link status to be DORMANT, but keep ratcheted bands. log("Physical channel configs updated: not updating PCC fields for empty PCC list " + "indicating RRC idle."); mPrimaryCellChangedWhileIdle = false; Loading Loading @@ -1310,6 +1316,7 @@ public class NetworkTypeController extends StateMachine { + mLastAnchorNrCellId + " -> " + anchorNrCellId); mPrimaryCellChangedWhileIdle = true; mLastAnchorNrCellId = anchorNrCellId; reduceSecondaryTimerIfNeeded(); return; } if (mRatchetPccFieldsForSameAnchorNrCell) { Loading @@ -1330,6 +1337,27 @@ public class NetworkTypeController extends StateMachine { } } /** * Called when PCI change, specifically during idle state. */ private void reduceSecondaryTimerIfNeeded() { if (!mIsSecondaryTimerActive || mNrAdvancedBandsSecondaryTimer <= 0) return; // Secondary timer is active, so we must have a valid secondary rule right now. OverrideTimerRule secondaryRule = mOverrideTimerRules.get(mPrimaryTimerState); if (secondaryRule != null) { int secondaryDuration = secondaryRule.getSecondaryTimer(mSecondaryTimerState); long durationMillis = secondaryDuration * 1000L; if ((mSecondaryTimerExpireTimestamp - SystemClock.uptimeMillis()) > durationMillis) { if (DBG) log("Due to PCI change, reduce the secondary timer to " + durationMillis); removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, mSecondaryTimerState, durationMillis); } } else { loge("!! Secondary timer is active, but found no rule for " + mPrimaryTimerState); } } private void transitionWithTimerTo(IState destState) { String destName = destState.getName(); if (mIsPrimaryTimerActive) { Loading Loading @@ -1369,7 +1397,9 @@ public class NetworkTypeController extends StateMachine { mSecondaryTimerState = currentName; mPreviousState = currentName; mIsSecondaryTimerActive = true; sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, duration * 1000L); long durationMillis = duration * 1000L; mSecondaryTimerExpireTimestamp = SystemClock.uptimeMillis() + durationMillis; sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, durationMillis); } mIsPrimaryTimerActive = false; transitionTo(getCurrentState()); Loading Loading @@ -1434,6 +1464,7 @@ public class NetworkTypeController extends StateMachine { } removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsSecondaryTimerActive = false; mSecondaryTimerExpireTimestamp = 0; mSecondaryTimerState = ""; transitionToCurrentState(); return; Loading Loading @@ -1464,6 +1495,7 @@ public class NetworkTypeController extends StateMachine { removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsPrimaryTimerActive = false; mIsSecondaryTimerActive = false; mSecondaryTimerExpireTimestamp = 0; mPrimaryTimerState = ""; mSecondaryTimerState = ""; Loading tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +29 −5 Original line number Diff line number Diff line Loading @@ -1550,7 +1550,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); // switch to connected_rrc_idle before primary timer expires // empty PCC, switch to connected_rrc_idle before primary timer expires physicalChannelConfigs.clear(); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */, new AsyncResult(null, physicalChannelConfigs, null)); Loading @@ -1571,16 +1571,40 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); // 5 seconds passed during connected_mmwave -> connected_rrc_idle secondary timer moveTimeForward(5 * 1000); // Verify secondary timer is still active after 6 seconds passed during // connected_mmwave -> connected_rrc_idle secondary timer, should still keep the primary // state icon. moveTimeForward((5 + 1) * 1000); processAllMessages(); assertEquals("connected_rrc_idle", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); } @Test public void testSecondaryTimerAdvanceBandReduceOnPciChange() throws Exception { // The advance band secondary timer has been running for 6 seconds, 20 - 6 seconds are left. testSecondaryTimerAdvanceBand(); // PCI changed from 1 to 2 for the first while the timer is running. mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */, new AsyncResult(null, List.of( new PhysicalChannelConfig.Builder() .setPhysicalCellId(2) .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) .setCellConnectionStatus(CellInfo.CONNECTION_PRIMARY_SERVING) .build()), null)); processAllMessages(); // Verify the first PCI change is exempted from triggering state change. assertEquals("connected_rrc_idle", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); // secondary timer expired moveTimeForward(15 * 1000); // Verify the timer has been reduced from 20 - 6s(advance band) to 5s(regular). moveTimeForward(5 * 1000); processAllMessages(); assertEquals("connected_rrc_idle", getCurrentState().getName()); Loading Loading
src/java/com/android/internal/telephony/NetworkTypeController.java +33 −1 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.os.AsyncResult; import android.os.Message; import android.os.PersistableBundle; import android.os.PowerManager; import android.os.SystemClock; import android.telephony.AccessNetworkConstants; import android.telephony.Annotation; import android.telephony.CarrierConfigManager; Loading Loading @@ -194,6 +195,7 @@ public class NetworkTypeController extends StateMachine { private boolean mIsPhysicalChannelConfigOn; private boolean mIsPrimaryTimerActive; private boolean mIsSecondaryTimerActive; private long mSecondaryTimerExpireTimestamp; private boolean mIsTimerResetEnabledForLegacyStateRrcIdle; /** Carrier config to reset timers when mccmnc changes */ private boolean mIsTimerResetEnabledOnPlmnChanges; Loading @@ -220,6 +222,7 @@ public class NetworkTypeController extends StateMachine { // Cached copies below to prevent race conditions @NonNull private ServiceState mServiceState; /** Used to track link status to be DORMANT or ACTIVE */ @Nullable private List<PhysicalChannelConfig> mPhysicalChannelConfigs; // Ratchet physical channel config fields to prevent 5G/5G+ flickering Loading Loading @@ -666,6 +669,7 @@ public class NetworkTypeController extends StateMachine { case EVENT_SECONDARY_TIMER_EXPIRED: if (DBG) log("Secondary timer expired for state: " + mSecondaryTimerState); mIsSecondaryTimerActive = false; mSecondaryTimerExpireTimestamp = 0; mSecondaryTimerState = ""; updateTimers(); mLastShownNrDueToAdvancedBand = false; Loading Loading @@ -1251,6 +1255,8 @@ public class NetworkTypeController extends StateMachine { private void updatePhysicalChannelConfigs(List<PhysicalChannelConfig> physicalChannelConfigs) { boolean isPccListEmpty = physicalChannelConfigs == null || physicalChannelConfigs.isEmpty(); if (isPccListEmpty && isUsingPhysicalChannelConfigForRrcDetection()) { // Clear mPrimaryCellChangedWhileIdle to allow later potential one-off PCI change. // Update link status to be DORMANT, but keep ratcheted bands. log("Physical channel configs updated: not updating PCC fields for empty PCC list " + "indicating RRC idle."); mPrimaryCellChangedWhileIdle = false; Loading Loading @@ -1310,6 +1316,7 @@ public class NetworkTypeController extends StateMachine { + mLastAnchorNrCellId + " -> " + anchorNrCellId); mPrimaryCellChangedWhileIdle = true; mLastAnchorNrCellId = anchorNrCellId; reduceSecondaryTimerIfNeeded(); return; } if (mRatchetPccFieldsForSameAnchorNrCell) { Loading @@ -1330,6 +1337,27 @@ public class NetworkTypeController extends StateMachine { } } /** * Called when PCI change, specifically during idle state. */ private void reduceSecondaryTimerIfNeeded() { if (!mIsSecondaryTimerActive || mNrAdvancedBandsSecondaryTimer <= 0) return; // Secondary timer is active, so we must have a valid secondary rule right now. OverrideTimerRule secondaryRule = mOverrideTimerRules.get(mPrimaryTimerState); if (secondaryRule != null) { int secondaryDuration = secondaryRule.getSecondaryTimer(mSecondaryTimerState); long durationMillis = secondaryDuration * 1000L; if ((mSecondaryTimerExpireTimestamp - SystemClock.uptimeMillis()) > durationMillis) { if (DBG) log("Due to PCI change, reduce the secondary timer to " + durationMillis); removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, mSecondaryTimerState, durationMillis); } } else { loge("!! Secondary timer is active, but found no rule for " + mPrimaryTimerState); } } private void transitionWithTimerTo(IState destState) { String destName = destState.getName(); if (mIsPrimaryTimerActive) { Loading Loading @@ -1369,7 +1397,9 @@ public class NetworkTypeController extends StateMachine { mSecondaryTimerState = currentName; mPreviousState = currentName; mIsSecondaryTimerActive = true; sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, duration * 1000L); long durationMillis = duration * 1000L; mSecondaryTimerExpireTimestamp = SystemClock.uptimeMillis() + durationMillis; sendMessageDelayed(EVENT_SECONDARY_TIMER_EXPIRED, destState, durationMillis); } mIsPrimaryTimerActive = false; transitionTo(getCurrentState()); Loading Loading @@ -1434,6 +1464,7 @@ public class NetworkTypeController extends StateMachine { } removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsSecondaryTimerActive = false; mSecondaryTimerExpireTimestamp = 0; mSecondaryTimerState = ""; transitionToCurrentState(); return; Loading Loading @@ -1464,6 +1495,7 @@ public class NetworkTypeController extends StateMachine { removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsPrimaryTimerActive = false; mIsSecondaryTimerActive = false; mSecondaryTimerExpireTimestamp = 0; mPrimaryTimerState = ""; mSecondaryTimerState = ""; Loading
tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +29 −5 Original line number Diff line number Diff line Loading @@ -1550,7 +1550,7 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); // switch to connected_rrc_idle before primary timer expires // empty PCC, switch to connected_rrc_idle before primary timer expires physicalChannelConfigs.clear(); mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */, new AsyncResult(null, physicalChannelConfigs, null)); Loading @@ -1571,16 +1571,40 @@ public class NetworkTypeControllerTest extends TelephonyTest { mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); // 5 seconds passed during connected_mmwave -> connected_rrc_idle secondary timer moveTimeForward(5 * 1000); // Verify secondary timer is still active after 6 seconds passed during // connected_mmwave -> connected_rrc_idle secondary timer, should still keep the primary // state icon. moveTimeForward((5 + 1) * 1000); processAllMessages(); assertEquals("connected_rrc_idle", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); } @Test public void testSecondaryTimerAdvanceBandReduceOnPciChange() throws Exception { // The advance band secondary timer has been running for 6 seconds, 20 - 6 seconds are left. testSecondaryTimerAdvanceBand(); // PCI changed from 1 to 2 for the first while the timer is running. mNetworkTypeController.sendMessage(11 /* EVENT_PHYSICAL_CHANNEL_CONFIGS_CHANGED */, new AsyncResult(null, List.of( new PhysicalChannelConfig.Builder() .setPhysicalCellId(2) .setNetworkType(TelephonyManager.NETWORK_TYPE_NR) .setCellConnectionStatus(CellInfo.CONNECTION_PRIMARY_SERVING) .build()), null)); processAllMessages(); // Verify the first PCI change is exempted from triggering state change. assertEquals("connected_rrc_idle", getCurrentState().getName()); assertEquals(TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED, mNetworkTypeController.getOverrideNetworkType()); assertTrue(mNetworkTypeController.areAnyTimersActive()); // secondary timer expired moveTimeForward(15 * 1000); // Verify the timer has been reduced from 20 - 6s(advance band) to 5s(regular). moveTimeForward(5 * 1000); processAllMessages(); assertEquals("connected_rrc_idle", getCurrentState().getName()); Loading