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

Commit 96932fec authored by Jack Yu's avatar Jack Yu
Browse files

DO NOT MERGE Provided temp solution for 5G+ icon not shown

This fix is for some carriers use PCO to indicate if the device
is using 5G+ bands.

1. Fixed the race condition between NetworkTypeController,
   DcTracker, and DcController, which run on different thread.
2. Fixed that PCO event was dropped when it does not arrive in
   NR connected state.
3. Fixed that network type controller only considers internet
   PDN's PCO. Per spec, it should be all PDNs'. If any one them
   indicates 5G+ capable, we should display 5G+.

Note this solution is only for S. In T the new data stack has
already supported this correctly.

Fix: 211682727
Fix: 213378567
Test: atest NetworkTypeControllerTest & carrier LE tests
Change-Id: I322a4ca6630e9c07aa072790e1e345bb1532d2b3
parent 84fd9813
Loading
Loading
Loading
Loading
+89 −31
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.telephony;

import android.annotation.NonNull;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -33,13 +34,14 @@ import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;

import com.android.internal.telephony.dataconnection.DataConnection;
import com.android.internal.telephony.dataconnection.DcController;
import com.android.internal.telephony.dataconnection.DcController.PhysicalLinkState;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.internal.util.IState;
import com.android.internal.util.IndentingPrintWriter;
@@ -54,6 +56,7 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.IntStream;
@@ -99,8 +102,9 @@ public class NetworkTypeController extends StateMachine {
    private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13;
    private static final int EVENT_PCO_DATA_CHANGED = 14;
    private static final int EVENT_BANDWIDTH_CHANGED = 15;
    private static final int EVENT_DATA_CALL_LIST_CHANGED = 16;

    private static final String[] sEvents = new String[EVENT_PCO_DATA_CHANGED + 1];
    private static final String[] sEvents = new String[EVENT_DATA_CALL_LIST_CHANGED + 1];
    static {
        sEvents[EVENT_UPDATE] = "EVENT_UPDATE";
        sEvents[EVENT_QUIT] = "EVENT_QUIT";
@@ -118,6 +122,7 @@ public class NetworkTypeController extends StateMachine {
        sEvents[EVENT_INITIALIZE] = "EVENT_INITIALIZE";
        sEvents[EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED] = "EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED";
        sEvents[EVENT_PCO_DATA_CHANGED] = "EVENT_PCO_DATA_CHANGED";
        sEvents[EVENT_DATA_CALL_LIST_CHANGED] = "EVENT_DATA_CALL_LIST_CHANGED";
    }

    private final Phone mPhone;
@@ -152,6 +157,10 @@ public class NetworkTypeController extends StateMachine {
    private boolean mIsPhysicalChannelConfig16Supported;
    private Boolean mIsNrAdvancedAllowedByPco = false;
    private int mNrAdvancedCapablePcoId = 0;
    /** The key is the cid, the value is the PCO data. */
    private final @NonNull Map<Integer, PcoData> mPcoDataMap = new ArrayMap<>();
    /** Active data connection cid set. */
    private final @NonNull Set<Integer> mActiveDcCidSet = new ArraySet<>();
    private boolean mIsUsingUserDataForRrcDetection = false;
    private boolean mEnableNrAdvancedWhileRoaming = true;

@@ -222,7 +231,13 @@ public class NetworkTypeController extends StateMachine {
        IntentFilter filter = new IntentFilter();
        filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);

        // TODO: This is a temporarily solution for S. Ideally PCO and data call list changed event
        //  should not be exposed outside of the data modules. PCO for 5G icon has been well
        //  supported in the new data architecture in T. This temp solution must be removed in T
        //  along with other old data modules.
        mPhone.mCi.registerForPcoData(getHandler(), EVENT_PCO_DATA_CHANGED, null);
        mPhone.mCi.registerForDataCallListChanged(getHandler(), EVENT_DATA_CALL_LIST_CHANGED, null);
    }

    private void unRegisterForAllEvents() {
@@ -235,6 +250,7 @@ public class NetworkTypeController extends StateMachine {
        mPhone.getDeviceStateMonitor().unregisterForPhysicalChannelConfigNotifChanged(getHandler());
        mPhone.getContext().unregisterReceiver(mIntentReceiver);
        mPhone.mCi.unregisterForPcoData(getHandler());
        mPhone.mCi.unregisterForDataCallListChanged(getHandler());
    }

    private void parseCarrierConfigs() {
@@ -518,10 +534,12 @@ public class NetworkTypeController extends StateMachine {
                    registerForAllEvents();
                    parseCarrierConfigs();
                    break;
                case EVENT_PCO_DATA_CHANGED:
                    handlePcoData((AsyncResult) msg.obj);
                    break;
                case EVENT_DATA_RAT_CHANGED:
                case EVENT_NR_STATE_CHANGED:
                case EVENT_NR_FREQUENCY_CHANGED:
                case EVENT_PCO_DATA_CHANGED:
                case EVENT_BANDWIDTH_CHANGED:
                    // ignored
                    break;
@@ -563,6 +581,10 @@ public class NetworkTypeController extends StateMachine {
                    resetAllTimers();
                    transitionTo(mLegacyState);
                    break;
                case EVENT_DATA_CALL_LIST_CHANGED:
                    ar = (AsyncResult) msg.obj;
                    handleDataCallList((List<DataCallResponse>) ar.result);
                    break;
                default:
                    throw new RuntimeException("Received invalid event: " + msg.what);
            }
@@ -855,6 +877,7 @@ public class NetworkTypeController extends StateMachine {
            if (DBG) log("NrConnectedState: process " + getEventName(msg.what));
            updateTimers();
            int rat = getDataNetworkType();
            AsyncResult ar;
            switch (msg.what) {
                case EVENT_DATA_RAT_CHANGED:
                    if (rat == TelephonyManager.NETWORK_TYPE_NR || isLte(rat) && isNrConnected()) {
@@ -876,6 +899,12 @@ public class NetworkTypeController extends StateMachine {
                    break;
                case EVENT_PCO_DATA_CHANGED:
                    handlePcoData((AsyncResult) msg.obj);
                    updateNrAdvancedState();
                    break;
                case EVENT_DATA_CALL_LIST_CHANGED:
                    ar = (AsyncResult) msg.obj;
                    handleDataCallList((List<DataCallResponse>) ar.result);
                    updateNrAdvancedState();
                    break;
                case EVENT_NR_FREQUENCY_CHANGED:
                case EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED:
@@ -885,7 +914,7 @@ public class NetworkTypeController extends StateMachine {
                    updateNrAdvancedState();
                    break;
                case EVENT_PHYSICAL_LINK_STATE_CHANGED:
                    AsyncResult ar = (AsyncResult) msg.obj;
                    ar = (AsyncResult) msg.obj;
                    mPhysicalLinkState = (int) ar.result;
                    if (!isNrConnected()) {
                        log("NR state changed. Sending EVENT_NR_STATE_CHANGED");
@@ -924,8 +953,40 @@ public class NetworkTypeController extends StateMachine {
            }
            mIsNrAdvanced = isNrAdvanced();
        }
    }

    private final NrConnectedState mNrConnectedState = new NrConnectedState();

    // TODO: This is a temporarily solution for S. Ideally PCO and data call list changed event
    //  should not be exposed outside of the data modules. PCO for 5G icon has been well
    //  supported in the new data architecture in T. This temp solution must be removed in T
    //  along with other old data modules.
    private void handleDataCallList(@NonNull List<DataCallResponse> dataCallResponseList) {
        if (mNrAdvancedCapablePcoId == 0) return;
        mActiveDcCidSet.clear();
        for (DataCallResponse response : dataCallResponseList) {
            if (response.getLinkStatus() == DataCallResponse.LINK_STATUS_ACTIVE
                    || response.getLinkStatus() == DataCallResponse.LINK_STATUS_DORMANT) {
                mActiveDcCidSet.add(response.getId());
            }
        }

        log("Active cids=" + mActiveDcCidSet);
        boolean nrAdvancedAllowedByPco = mPcoDataMap.values().stream()
                .anyMatch(pco -> pco.contents[pco.contents.length - 1] == 1
                        && mActiveDcCidSet.contains(pco.cid));
        if (mIsNrAdvancedAllowedByPco != nrAdvancedAllowedByPco) {
            mIsNrAdvancedAllowedByPco = nrAdvancedAllowedByPco;
            log("nrAdvancedAllowedByPco=" + nrAdvancedAllowedByPco);
        }
    }

    // TODO: This is a temporarily solution for S. Ideally PCO and data call list changed event
    //  should not be exposed outside of the data modules. PCO for 5G icon has been well
    //  supported in the new data architecture in T. This temp solution must be removed in T
    //  along with other old data modules.
    private void handlePcoData(AsyncResult ar) {
        if (mNrAdvancedCapablePcoId == 0) return;
        if (ar.exception != null) {
            loge("PCO_DATA exception: " + ar.exception);
            return;
@@ -934,27 +995,24 @@ public class NetworkTypeController extends StateMachine {
        if (pcodata == null) {
            return;
        }
            log("EVENT_PCO_DATA_CHANGED: pco data: " + pcodata);
            DcTracker dcTracker = mPhone.getDcTracker(
                    AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
            DataConnection dc =
                    dcTracker != null ? dcTracker.getDataConnectionByContextId(pcodata.cid) : null;
            ApnSetting apnSettings = dc != null ? dc.getApnSetting() : null;
            if (apnSettings != null && apnSettings.canHandleType(ApnSetting.TYPE_DEFAULT)
                    && mNrAdvancedCapablePcoId > 0
                    && pcodata.pcoId == mNrAdvancedCapablePcoId
            ) {
                log("EVENT_PCO_DATA_CHANGED: Nr Advanced is allowed by PCO. length:"
                        + pcodata.contents.length + ",value: " + Arrays.toString(pcodata.contents));
                mIsNrAdvancedAllowedByPco = (pcodata.contents.length > 0)
                        ? pcodata.contents[pcodata.contents.length - 1] == 1 : false;
                updateNrAdvancedState();
        log("EVENT_PCO_DATA_CHANGED: pco data: " + pcodata + ", "
                + IccUtils.bytesToHexString(pcodata.contents));
        if (pcodata.pcoId != mNrAdvancedCapablePcoId || pcodata.contents == null
                || pcodata.contents.length == 0) {
            log("Dropped irrelevant PCO data");
            return;
        }

        mPcoDataMap.put(pcodata.cid, pcodata);
        boolean nrAdvancedAllowedByPco = mPcoDataMap.values().stream()
                .anyMatch(pco -> pco.contents[pco.contents.length - 1] == 1
                        && mActiveDcCidSet.contains(pco.cid));
        if (mIsNrAdvancedAllowedByPco != nrAdvancedAllowedByPco) {
            mIsNrAdvancedAllowedByPco = nrAdvancedAllowedByPco;
            log("nrAdvancedAllowedByPco=" + nrAdvancedAllowedByPco);
        }
    }

    private final NrConnectedState mNrConnectedState = new NrConnectedState();

    private void transitionWithTimerTo(IState destState) {
        String destName = destState.getName();
        OverrideTimerRule rule = mOverrideTimerRules.get(mPreviousState);
+73 −17
Original line number Diff line number Diff line
@@ -16,13 +16,22 @@

package com.android.internal.telephony;

import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_ADDRESS;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_DNS;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_GATEWAY;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_IFNAME;
import static com.android.internal.telephony.dataconnection.DcTrackerTest.FAKE_PCSCF_ADDRESS;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn;

import android.annotation.NonNull;
import android.content.Intent;
import android.net.InetAddresses;
import android.net.LinkAddress;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
@@ -36,6 +45,7 @@ import android.telephony.ServiceState;
import android.telephony.TelephonyDisplayInfo;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.data.DataCallResponse;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;

@@ -52,6 +62,7 @@ import org.mockito.Mock;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@RunWith(AndroidTestingRunner.class)
@@ -71,6 +82,8 @@ public class NetworkTypeControllerTest extends TelephonyTest {
    private static final int EVENT_INITIALIZE = 12;
    private static final int EVENT_PHYSICAL_CHANNEL_CONFIG_CHANGED = 13;
    private static final int EVENT_PCO_DATA_CHANGED = 14;
    private static final int EVENT_BANDWIDTH_CHANGED = 15;
    private static final int EVENT_DATA_CALL_LIST_CHANGED = 16;

    private NetworkTypeController mNetworkTypeController;
    private PersistableBundle mBundle;
@@ -99,6 +112,25 @@ public class NetworkTypeControllerTest extends TelephonyTest {
        processAllMessages();
    }

    private @NonNull DataCallResponse getDataCallResponse(int cid) {
        return new DataCallResponse.Builder()
                .setCause(0)
                .setRetryDurationMillis(-1)
                .setId(cid)
                .setLinkStatus(DataCallResponse.LINK_STATUS_ACTIVE)
                .setProtocolType(ApnSetting.PROTOCOL_IP)
                .setInterfaceName(FAKE_IFNAME)
                .setAddresses(Arrays.asList(
                        new LinkAddress(InetAddresses.parseNumericAddress(FAKE_ADDRESS), 0)))
                .setDnsAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_DNS)))
                .setGatewayAddresses(Arrays.asList(InetAddresses.parseNumericAddress(FAKE_GATEWAY)))
                .setPcscfAddresses(
                        Arrays.asList(InetAddresses.parseNumericAddress(FAKE_PCSCF_ADDRESS)))
                .setMtuV4(1440)
                .setMtuV6(1440)
                .build();
    }

    @Before
    public void setUp() throws Exception {
        super.setUp(getClass().getSimpleName());
@@ -469,11 +501,12 @@ public class NetworkTypeControllerTest extends TelephonyTest {
        broadcastCarrierConfigs();
        int cid = 1;
        byte[] contents = new byte[]{0};
        doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid);
        doReturn(mApnSetting).when(mDataConnection).getApnSetting();
        doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT);
        mNetworkTypeController.sendMessage(EVENT_DATA_CALL_LIST_CHANGED,
                new AsyncResult(null, List.of(getDataCallResponse(cid)), null));
        processAllMessages();
        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03);
        broadcastCarrierConfigs();
        processAllMessages();


        mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED,
@@ -494,11 +527,12 @@ public class NetworkTypeControllerTest extends TelephonyTest {
        broadcastCarrierConfigs();
        int cid = 1;
        byte[] contents = new byte[]{31, 1, 84, 0};
        doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid);
        doReturn(mApnSetting).when(mDataConnection).getApnSetting();
        doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT);
        mNetworkTypeController.sendMessage(EVENT_DATA_CALL_LIST_CHANGED,
                new AsyncResult(null, List.of(getDataCallResponse(cid)), null));
        processAllMessages();
        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03);
        broadcastCarrierConfigs();
        processAllMessages();


        mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED,
@@ -519,9 +553,8 @@ public class NetworkTypeControllerTest extends TelephonyTest {
        broadcastCarrierConfigs();
        int cid = 1;
        byte[] contents = new byte[]{1};
        doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid);
        doReturn(mApnSetting).when(mDataConnection).getApnSetting();
        doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT);
        mNetworkTypeController.sendMessage(EVENT_DATA_CALL_LIST_CHANGED,
                new AsyncResult(null, List.of(getDataCallResponse(cid)), null));
        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF00);
        broadcastCarrierConfigs();

@@ -540,13 +573,37 @@ public class NetworkTypeControllerTest extends TelephonyTest {
        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
        doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03);
        broadcastCarrierConfigs();
        processAllMessages();

        int cid = 1;
        byte[] contents = new byte[]{1};
        doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid);
        doReturn(mApnSetting).when(mDataConnection).getApnSetting();
        doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT);
        mNetworkTypeController.sendMessage(EVENT_DATA_CALL_LIST_CHANGED,
                new AsyncResult(null, List.of(getDataCallResponse(cid)), null));

        mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED,
                new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null));
        mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
        processAllMessages();
        assertEquals("connected_mmwave", getCurrentState().getName());
    }

    @Test
    public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableAndPcoLength4()
            throws Exception {
        assertEquals("DefaultState", getCurrentState().getName());
        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
        doReturn(NetworkRegistrationInfo.NR_STATE_CONNECTED).when(mServiceState).getNrState();
        doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03);
        broadcastCarrierConfigs();
        processAllMessages();

        int cid = 1;
        byte[] contents = new byte[]{31, 1, 84, 1};
        mNetworkTypeController.sendMessage(EVENT_DATA_CALL_LIST_CHANGED,
                new AsyncResult(null, List.of(getDataCallResponse(cid)), null));

        mNetworkTypeController.sendMessage(EVENT_PCO_DATA_CHANGED,
                new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null));
@@ -556,7 +613,7 @@ public class NetworkTypeControllerTest extends TelephonyTest {
    }

    @Test
    public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableAndPcoLength4()
    public void testTransitionToCurrentStateNrConnectedWithNrAdvancedCapableButCidNotMatched()
            throws Exception {
        assertEquals("DefaultState", getCurrentState().getName());
        doReturn(TelephonyManager.NETWORK_TYPE_LTE).when(mServiceState).getDataNetworkType();
@@ -564,9 +621,8 @@ public class NetworkTypeControllerTest extends TelephonyTest {
        doReturn(ServiceState.FREQUENCY_RANGE_MMWAVE).when(mServiceState).getNrFrequencyRange();
        int cid = 1;
        byte[] contents = new byte[]{31, 1, 84, 1};
        doReturn(mDataConnection).when(mDcTracker).getDataConnectionByContextId(cid);
        doReturn(mApnSetting).when(mDataConnection).getApnSetting();
        doReturn(true).when(mApnSetting).canHandleType(ApnSetting.TYPE_DEFAULT);
        mNetworkTypeController.sendMessage(EVENT_DATA_CALL_LIST_CHANGED,
                new AsyncResult(null, List.of(getDataCallResponse(2)), null));
        mBundle.putInt(CarrierConfigManager.KEY_NR_ADVANCED_CAPABLE_PCO_ID_INT, 0xFF03);
        broadcastCarrierConfigs();

@@ -574,7 +630,7 @@ public class NetworkTypeControllerTest extends TelephonyTest {
                new AsyncResult(null, new PcoData(cid, "", 0xff03, contents), null));
        mNetworkTypeController.sendMessage(NetworkTypeController.EVENT_UPDATE);
        processAllMessages();
        assertEquals("connected_mmwave", getCurrentState().getName());
        assertEquals("connected", getCurrentState().getName());
    }

    @Test