Loading src/java/com/android/internal/telephony/RatRatcheter.java +5 −1 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ public class RatRatcheter { /** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */ public void ratchet(ServiceState oldSS, ServiceState newSS, boolean locationChange) { if (isSameRatFamily(oldSS, newSS)) { if (!locationChange && isSameRatFamily(oldSS, newSS)) { updateBandwidths(oldSS.getCellBandwidths(), newSS); } // temporarily disable rat ratchet on location change. Loading Loading @@ -137,6 +137,10 @@ public class RatRatcheter { private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) { synchronized (mRatFamilyMap) { // Either the two technologies are the same or their families must be non-null // and the same. if (ss1.getRilDataRadioTechnology() == ss2.getRilDataRadioTechnology()) return true; if (mRatFamilyMap.get(ss1.getRilDataRadioTechnology()) == null) return false; return mRatFamilyMap.get(ss1.getRilDataRadioTechnology()) == mRatFamilyMap.get(ss2.getRilDataRadioTechnology()); } Loading src/java/com/android/internal/telephony/ServiceStateTracker.java +70 −3 Original line number Diff line number Diff line Loading @@ -130,6 +130,7 @@ public class ServiceStateTracker extends Handler { private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000; private long mLastCellInfoListTime; private List<CellInfo> mLastCellInfoList = null; private List<PhysicalChannelConfig> mLastPhysicalChannelConfigList = null; private SignalStrength mSignalStrength; Loading Loading @@ -1449,6 +1450,7 @@ public class ServiceStateTracker extends Handler { + list); } mPhone.notifyPhysicalChannelConfiguration(list); mLastPhysicalChannelConfigList = list; // only notify if bandwidths changed if (RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) { Loading Loading @@ -1788,7 +1790,7 @@ public class ServiceStateTracker extends Handler { mNewSS.setCssIndicator(cssIndicator); mNewSS.setRilVoiceRadioTechnology(newVoiceRat); mNewSS.addNetworkRegistrationState(networkRegState); setChannelNumberFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); //Denial reason if registrationState = 3 int reasonForDenial = networkRegState.getReasonForDenial(); Loading Loading @@ -1864,7 +1866,14 @@ public class ServiceStateTracker extends Handler { mNewSS.setDataRegState(serviceState); mNewSS.setRilDataRadioTechnology(newDataRat); mNewSS.addNetworkRegistrationState(networkRegState); setChannelNumberFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); // When we receive OOS reset the PhyChanConfig list so that non-return-to-idle // implementers of PhyChanConfig unsol will not carry forward a CA report // (2 or more cells) to a new cell if they camp for emergency service only. if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) { mLastPhysicalChannelConfigList = null; } setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); if (mPhone.isPhoneTypeGsm()) { Loading Loading @@ -2003,7 +2012,22 @@ public class ServiceStateTracker extends Handler { } } private void setChannelNumberFromCellIdentity(ServiceState ss, CellIdentity cellIdentity) { private static boolean isValidLteBandwidthKhz(int bandwidth) { // Valid bandwidths, see 3gpp 36.101 sec. 5.6 switch (bandwidth) { case 1400: case 3000: case 5000: case 10000: case 15000: case 20000: return true; default: return false; } } private void setPhyCellInfoFromCellIdentity(ServiceState ss, CellIdentity cellIdentity) { if (cellIdentity == null) { if (DBG) { log("Could not set ServiceState channel number. CellIdentity null"); Loading @@ -2015,6 +2039,49 @@ public class ServiceStateTracker extends Handler { if (VDBG) { log("Setting channel number: " + cellIdentity.getChannelNumber()); } if (cellIdentity instanceof CellIdentityLte) { CellIdentityLte cl = (CellIdentityLte) cellIdentity; int[] bandwidths = null; // Prioritize the PhysicalChannelConfig list because we might already be in carrier // aggregation by the time poll state is performed. if (!ArrayUtils.isEmpty(mLastPhysicalChannelConfigList)) { bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList); for (int bw : bandwidths) { if (!isValidLteBandwidthKhz(bw)) { loge("Invalid LTE Bandwidth in RegistrationState, " + bw); bandwidths = null; break; } } } // If we don't have a PhysicalChannelConfig[] list, then pull from CellIdentityLte. // This is normal if we're in idle mode and the PhysicalChannelConfig[] has already // been updated. This is also a fallback in case the PhysicalChannelConfig info // is invalid (ie, broken). // Also, for vendor implementations that do not report return-to-idle, we should // prioritize the bandwidth report in the CellIdentity, because the physical channel // config report may be stale in the case where a single carrier was used previously // and we transition to camped-for-emergency (since we never have a physical // channel active). In the normal case of single-carrier non-return-to-idle, the // values *must* be the same, so it doesn't matter which is chosen. if (bandwidths == null || bandwidths.length == 1) { final int cbw = cl.getBandwidth(); if (isValidLteBandwidthKhz(cbw)) { bandwidths = new int[] {cbw}; } else if (cbw == Integer.MAX_VALUE) { // Bandwidth is unreported; c'est la vie. This is not an error because // pre-1.2 HAL implementations do not support bandwidth reporting. } else { loge("Invalid LTE Bandwidth in RegistrationState, " + cbw); } } if (bandwidths != null) { ss.setCellBandwidths(bandwidths); } } else { if (VDBG) log("Skipping bandwidth update for Non-LTE cell."); } } /** Loading tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +97 −0 Original line number Diff line number Diff line Loading @@ -60,13 +60,16 @@ import android.support.test.filters.FlakyTest; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierConfigManager; import android.telephony.CellIdentityGsm; import android.telephony.CellIdentityLte; import android.telephony.CellInfo; import android.telephony.CellInfoGsm; import android.telephony.NetworkRegistrationState; import android.telephony.NetworkService; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; Loading @@ -88,6 +91,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; Loading Loading @@ -1627,4 +1631,97 @@ public class ServiceStateTrackerTest extends TelephonyTest { waitForMs(200); assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilVoiceRadioTechnology()); } private void sendPhyChanConfigChange(int[] bandwidths) { ArrayList<PhysicalChannelConfig> pc = new ArrayList<>(); int ssType = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING; for (int bw : bandwidths) { pc.add(new PhysicalChannelConfig(ssType, bw)); // All cells after the first are secondary serving cells. ssType = PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING; } sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_PHYSICAL_CHANNEL_CONFIG, new AsyncResult(null, pc, null))); waitForMs(100); } private void sendRegStateUpdateForLteCellId(CellIdentityLte cellId) { NetworkRegistrationState dataResult = new NetworkRegistrationState( 1, 2, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1); NetworkRegistrationState voiceResult = new NetworkRegistrationState( 1, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, false, 0, 0, 0); sst.mPollingContext[0] = 2; // update data reg state to be in service sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS, new AsyncResult(sst.mPollingContext, dataResult, null))); waitForMs(200); sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION, new AsyncResult(sst.mPollingContext, voiceResult, null))); waitForMs(200); } @Test public void testPhyChanBandwidthUpdatedOnDataRegState() throws Exception { // Cell ID change should trigger hasLocationChanged. CellIdentityLte cellIdentity5 = new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst"); sendPhyChanConfigChange(new int[] {10000}); sendRegStateUpdateForLteCellId(cellIdentity5); assertTrue(Arrays.equals(new int[] {5000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthNotUpdatedWhenInvalidInCellIdentity() throws Exception { // Cell ID change should trigger hasLocationChanged. CellIdentityLte cellIdentityInv = new CellIdentityLte(1, 1, 5, 1, 12345, "001", "01", "test", "tst"); sendPhyChanConfigChange(new int[] {10000}); sendRegStateUpdateForLteCellId(cellIdentityInv); assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthPrefersCarrierAggregationReport() throws Exception { // Cell ID change should trigger hasLocationChanged. CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 5, 1, 10000, "001", "01", "test", "tst"); sendPhyChanConfigChange(new int[] {10000, 5000}); sendRegStateUpdateForLteCellId(cellIdentity10); assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() throws Exception { // LTE Cell with bandwidth = 10000 CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 1, 1, 10000, "1", "1", "test", "tst"); sendRegStateUpdateForLteCellId(cellIdentity10); assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths())); sendPhyChanConfigChange(new int[] {10000, 5000}); assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthResetsOnOos() throws Exception { testPhyChanBandwidthRatchetedOnPhyChanBandwidth(); NetworkRegistrationState dataResult = new NetworkRegistrationState( 1, 2, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, 1); NetworkRegistrationState voiceResult = new NetworkRegistrationState( 1, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, false, 0, 0, 0); sst.mPollingContext[0] = 2; sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS, new AsyncResult(sst.mPollingContext, dataResult, null))); waitForMs(200); sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION, new AsyncResult(sst.mPollingContext, voiceResult, null))); waitForMs(200); assertTrue(Arrays.equals(new int[0], sst.mSS.getCellBandwidths())); } } Loading
src/java/com/android/internal/telephony/RatRatcheter.java +5 −1 Original line number Diff line number Diff line Loading @@ -102,7 +102,7 @@ public class RatRatcheter { /** Ratchets RATs and cell bandwidths if oldSS and newSS have the same RAT family. */ public void ratchet(ServiceState oldSS, ServiceState newSS, boolean locationChange) { if (isSameRatFamily(oldSS, newSS)) { if (!locationChange && isSameRatFamily(oldSS, newSS)) { updateBandwidths(oldSS.getCellBandwidths(), newSS); } // temporarily disable rat ratchet on location change. Loading Loading @@ -137,6 +137,10 @@ public class RatRatcheter { private boolean isSameRatFamily(ServiceState ss1, ServiceState ss2) { synchronized (mRatFamilyMap) { // Either the two technologies are the same or their families must be non-null // and the same. if (ss1.getRilDataRadioTechnology() == ss2.getRilDataRadioTechnology()) return true; if (mRatFamilyMap.get(ss1.getRilDataRadioTechnology()) == null) return false; return mRatFamilyMap.get(ss1.getRilDataRadioTechnology()) == mRatFamilyMap.get(ss2.getRilDataRadioTechnology()); } Loading
src/java/com/android/internal/telephony/ServiceStateTracker.java +70 −3 Original line number Diff line number Diff line Loading @@ -130,6 +130,7 @@ public class ServiceStateTracker extends Handler { private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000; private long mLastCellInfoListTime; private List<CellInfo> mLastCellInfoList = null; private List<PhysicalChannelConfig> mLastPhysicalChannelConfigList = null; private SignalStrength mSignalStrength; Loading Loading @@ -1449,6 +1450,7 @@ public class ServiceStateTracker extends Handler { + list); } mPhone.notifyPhysicalChannelConfiguration(list); mLastPhysicalChannelConfigList = list; // only notify if bandwidths changed if (RatRatcheter.updateBandwidths(getBandwidthsFromConfigs(list), mSS)) { Loading Loading @@ -1788,7 +1790,7 @@ public class ServiceStateTracker extends Handler { mNewSS.setCssIndicator(cssIndicator); mNewSS.setRilVoiceRadioTechnology(newVoiceRat); mNewSS.addNetworkRegistrationState(networkRegState); setChannelNumberFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); //Denial reason if registrationState = 3 int reasonForDenial = networkRegState.getReasonForDenial(); Loading Loading @@ -1864,7 +1866,14 @@ public class ServiceStateTracker extends Handler { mNewSS.setDataRegState(serviceState); mNewSS.setRilDataRadioTechnology(newDataRat); mNewSS.addNetworkRegistrationState(networkRegState); setChannelNumberFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); // When we receive OOS reset the PhyChanConfig list so that non-return-to-idle // implementers of PhyChanConfig unsol will not carry forward a CA report // (2 or more cells) to a new cell if they camp for emergency service only. if (serviceState == ServiceState.STATE_OUT_OF_SERVICE) { mLastPhysicalChannelConfigList = null; } setPhyCellInfoFromCellIdentity(mNewSS, networkRegState.getCellIdentity()); if (mPhone.isPhoneTypeGsm()) { Loading Loading @@ -2003,7 +2012,22 @@ public class ServiceStateTracker extends Handler { } } private void setChannelNumberFromCellIdentity(ServiceState ss, CellIdentity cellIdentity) { private static boolean isValidLteBandwidthKhz(int bandwidth) { // Valid bandwidths, see 3gpp 36.101 sec. 5.6 switch (bandwidth) { case 1400: case 3000: case 5000: case 10000: case 15000: case 20000: return true; default: return false; } } private void setPhyCellInfoFromCellIdentity(ServiceState ss, CellIdentity cellIdentity) { if (cellIdentity == null) { if (DBG) { log("Could not set ServiceState channel number. CellIdentity null"); Loading @@ -2015,6 +2039,49 @@ public class ServiceStateTracker extends Handler { if (VDBG) { log("Setting channel number: " + cellIdentity.getChannelNumber()); } if (cellIdentity instanceof CellIdentityLte) { CellIdentityLte cl = (CellIdentityLte) cellIdentity; int[] bandwidths = null; // Prioritize the PhysicalChannelConfig list because we might already be in carrier // aggregation by the time poll state is performed. if (!ArrayUtils.isEmpty(mLastPhysicalChannelConfigList)) { bandwidths = getBandwidthsFromConfigs(mLastPhysicalChannelConfigList); for (int bw : bandwidths) { if (!isValidLteBandwidthKhz(bw)) { loge("Invalid LTE Bandwidth in RegistrationState, " + bw); bandwidths = null; break; } } } // If we don't have a PhysicalChannelConfig[] list, then pull from CellIdentityLte. // This is normal if we're in idle mode and the PhysicalChannelConfig[] has already // been updated. This is also a fallback in case the PhysicalChannelConfig info // is invalid (ie, broken). // Also, for vendor implementations that do not report return-to-idle, we should // prioritize the bandwidth report in the CellIdentity, because the physical channel // config report may be stale in the case where a single carrier was used previously // and we transition to camped-for-emergency (since we never have a physical // channel active). In the normal case of single-carrier non-return-to-idle, the // values *must* be the same, so it doesn't matter which is chosen. if (bandwidths == null || bandwidths.length == 1) { final int cbw = cl.getBandwidth(); if (isValidLteBandwidthKhz(cbw)) { bandwidths = new int[] {cbw}; } else if (cbw == Integer.MAX_VALUE) { // Bandwidth is unreported; c'est la vie. This is not an error because // pre-1.2 HAL implementations do not support bandwidth reporting. } else { loge("Invalid LTE Bandwidth in RegistrationState, " + cbw); } } if (bandwidths != null) { ss.setCellBandwidths(bandwidths); } } else { if (VDBG) log("Skipping bandwidth update for Non-LTE cell."); } } /** Loading
tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java +97 −0 Original line number Diff line number Diff line Loading @@ -60,13 +60,16 @@ import android.support.test.filters.FlakyTest; import android.telephony.AccessNetworkConstants.AccessNetworkType; import android.telephony.CarrierConfigManager; import android.telephony.CellIdentityGsm; import android.telephony.CellIdentityLte; import android.telephony.CellInfo; import android.telephony.CellInfoGsm; import android.telephony.NetworkRegistrationState; import android.telephony.NetworkService; import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.test.suitebuilder.annotation.MediumTest; import android.test.suitebuilder.annotation.SmallTest; Loading @@ -88,6 +91,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; Loading Loading @@ -1627,4 +1631,97 @@ public class ServiceStateTrackerTest extends TelephonyTest { waitForMs(200); assertEquals(ServiceState.RIL_RADIO_TECHNOLOGY_GPRS, sst.mSS.getRilVoiceRadioTechnology()); } private void sendPhyChanConfigChange(int[] bandwidths) { ArrayList<PhysicalChannelConfig> pc = new ArrayList<>(); int ssType = PhysicalChannelConfig.CONNECTION_PRIMARY_SERVING; for (int bw : bandwidths) { pc.add(new PhysicalChannelConfig(ssType, bw)); // All cells after the first are secondary serving cells. ssType = PhysicalChannelConfig.CONNECTION_SECONDARY_SERVING; } sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_PHYSICAL_CHANNEL_CONFIG, new AsyncResult(null, pc, null))); waitForMs(100); } private void sendRegStateUpdateForLteCellId(CellIdentityLte cellId) { NetworkRegistrationState dataResult = new NetworkRegistrationState( 1, 2, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1); NetworkRegistrationState voiceResult = new NetworkRegistrationState( 1, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, false, 0, 0, 0); sst.mPollingContext[0] = 2; // update data reg state to be in service sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS, new AsyncResult(sst.mPollingContext, dataResult, null))); waitForMs(200); sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION, new AsyncResult(sst.mPollingContext, voiceResult, null))); waitForMs(200); } @Test public void testPhyChanBandwidthUpdatedOnDataRegState() throws Exception { // Cell ID change should trigger hasLocationChanged. CellIdentityLte cellIdentity5 = new CellIdentityLte(1, 1, 5, 1, 5000, "001", "01", "test", "tst"); sendPhyChanConfigChange(new int[] {10000}); sendRegStateUpdateForLteCellId(cellIdentity5); assertTrue(Arrays.equals(new int[] {5000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthNotUpdatedWhenInvalidInCellIdentity() throws Exception { // Cell ID change should trigger hasLocationChanged. CellIdentityLte cellIdentityInv = new CellIdentityLte(1, 1, 5, 1, 12345, "001", "01", "test", "tst"); sendPhyChanConfigChange(new int[] {10000}); sendRegStateUpdateForLteCellId(cellIdentityInv); assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthPrefersCarrierAggregationReport() throws Exception { // Cell ID change should trigger hasLocationChanged. CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 5, 1, 10000, "001", "01", "test", "tst"); sendPhyChanConfigChange(new int[] {10000, 5000}); sendRegStateUpdateForLteCellId(cellIdentity10); assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthRatchetedOnPhyChanBandwidth() throws Exception { // LTE Cell with bandwidth = 10000 CellIdentityLte cellIdentity10 = new CellIdentityLte(1, 1, 1, 1, 10000, "1", "1", "test", "tst"); sendRegStateUpdateForLteCellId(cellIdentity10); assertTrue(Arrays.equals(new int[] {10000}, sst.mSS.getCellBandwidths())); sendPhyChanConfigChange(new int[] {10000, 5000}); assertTrue(Arrays.equals(new int[] {10000, 5000}, sst.mSS.getCellBandwidths())); } @Test public void testPhyChanBandwidthResetsOnOos() throws Exception { testPhyChanBandwidthRatchetedOnPhyChanBandwidth(); NetworkRegistrationState dataResult = new NetworkRegistrationState( 1, 2, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, 1); NetworkRegistrationState voiceResult = new NetworkRegistrationState( 1, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, false, 0, 0, 0); sst.mPollingContext[0] = 2; sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS, new AsyncResult(sst.mPollingContext, dataResult, null))); waitForMs(200); sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_REGISTRATION, new AsyncResult(sst.mPollingContext, voiceResult, null))); waitForMs(200); assertTrue(Arrays.equals(new int[0], sst.mSS.getCellBandwidths())); } }