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

Commit 022fbe9d authored by Nathan Harold's avatar Nathan Harold
Browse files

Set Cell Bandwidth Correctly By RegState

During the PollState procedure, The Voice and Data
RegState Results provide an initial cell bandwidth,
which is not being properly set in cases where the
device already has CarrierAggregation by the time
the poll state finishes, or when the radio has
returned to idle but we have a new serving cell.

-Cache the last PhyChanConfig in ServiceStateTracker.

-Add support to populate the SS Bandwith in poll state
 by first seeing if there is a list of phychan configs.
 If it exists and is valid, use it. If not but there is
 a valid bandwidth in the cell identity use that.

-Fix the RatRatcheter.isSameRatFamily() so that RATs
 that lack a mapping to a family do not compare to
 equal.

-Fix the Ratcheting logic so that bandwidths are only
 ratcheted when there is no location change detected.

Bug: 80004809
Test: manual
Merged-In: Ibbcb8556cd4b64f12c57353b00c2c38116b31c70
Change-Id: Ibbcb8556cd4b64f12c57353b00c2c38116b31c70
parent c335dae7
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -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.
@@ -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());
        }
+70 −3
Original line number Diff line number Diff line
@@ -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;

@@ -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)) {
@@ -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();
@@ -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()) {

@@ -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");
@@ -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.");
        }
    }

    /**
+97 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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()));
    }
}