diff options
-rw-r--r-- | src/java/com/android/internal/telephony/NetworkTypeController.java | 34 | ||||
-rw-r--r-- | tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java | 34 |
2 files changed, 62 insertions, 6 deletions
diff --git a/src/java/com/android/internal/telephony/NetworkTypeController.java b/src/java/com/android/internal/telephony/NetworkTypeController.java index 68d24a275d..67ca1e1aaf 100644 --- a/src/java/com/android/internal/telephony/NetworkTypeController.java +++ b/src/java/com/android/internal/telephony/NetworkTypeController.java @@ -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; @@ -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; @@ -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 @@ -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; @@ -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; @@ -1310,6 +1316,7 @@ public class NetworkTypeController extends StateMachine { + mLastAnchorNrCellId + " -> " + anchorNrCellId); mPrimaryCellChangedWhileIdle = true; mLastAnchorNrCellId = anchorNrCellId; + reduceSecondaryTimerIfNeeded(); return; } if (mRatchetPccFieldsForSameAnchorNrCell) { @@ -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) { @@ -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()); @@ -1434,6 +1464,7 @@ public class NetworkTypeController extends StateMachine { } removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsSecondaryTimerActive = false; + mSecondaryTimerExpireTimestamp = 0; mSecondaryTimerState = ""; transitionToCurrentState(); return; @@ -1464,6 +1495,7 @@ public class NetworkTypeController extends StateMachine { removeMessages(EVENT_SECONDARY_TIMER_EXPIRED); mIsPrimaryTimerActive = false; mIsSecondaryTimerActive = false; + mSecondaryTimerExpireTimestamp = 0; mPrimaryTimerState = ""; mSecondaryTimerState = ""; diff --git a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java index b8545350b7..e08abd98c9 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/NetworkTypeControllerTest.java @@ -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)); @@ -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(); - // secondary timer expired - moveTimeForward(15 * 1000); + // 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()); + + // Verify the timer has been reduced from 20 - 6s(advance band) to 5s(regular). + moveTimeForward(5 * 1000); processAllMessages(); assertEquals("connected_rrc_idle", getCurrentState().getName()); |