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

Commit 3df338f1 authored by Ling Ma's avatar Ling Ma
Browse files

Add anomaly reports for QNS input

If using T data stack(mDataConfig!=null) and detection is enabled from
the server side, check anormal QNS change preferred transport call

1) invalid network type or invalid Apn Type
2) frequent change of network type for a specific Apn

Fix: 232294597
Test: manual sanity
Change-Id: I673623c1342462887aef6e21b6de00e90513eeac
parent 95a73dba
Loading
Loading
Loading
Loading
+78 −4
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.telephony.data;

import android.annotation.CallbackExecutor;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.StringDef;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -56,6 +57,7 @@ import android.util.SparseArray;

import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RIL;
import com.android.internal.telephony.SlidingWindowEventCounter;
import com.android.internal.telephony.dataconnection.DataThrottler;
import com.android.telephony.Rlog;

@@ -111,6 +113,11 @@ public class AccessNetworksManager extends Handler {
     */
    public static final String IWLAN_OPERATION_MODE_AP_ASSISTED = "AP-assisted";

    /**
     * The counters to detect frequent QNS attempt to change preferred network transport by ApnType.
     */
    private final @NonNull SparseArray<SlidingWindowEventCounter> mApnTypeToQnsChangeNetworkCounter;

    private final String mLogTag;
    private final LocalLog mLocalLog = new LocalLog(64);
    private final UUID mAnomalyUUID = UUID.fromString("c2d1a639-00e2-4561-9619-6acf37d90590");
@@ -131,6 +138,8 @@ public class AccessNetworksManager extends Handler {

    private final CarrierConfigManager mCarrierConfigManager;

    private @Nullable DataConfigManager mDataConfigManager;

    private IQualifiedNetworksService mIQualifiedNetworksService;

    private AccessNetworksManagerDeathRecipient mDeathRecipient;
@@ -344,12 +353,24 @@ public class AccessNetworksManager extends Handler {
            if (Arrays.stream(qualifiedNetworkTypes).anyMatch(accessNetwork
                    -> !DataUtils.isValidAccessNetwork(accessNetwork))) {
                loge("Invalid access networks " + Arrays.toString(qualifiedNetworkTypes));
                if (mDataConfigManager != null
                        && mDataConfigManager.isInvalidQnsParamAnomalyReportEnabled()) {
                    reportAnomaly("QNS requested invalid Network Type",
                            "3e89a3df-3524-45fa-b5f2-0fb0e4c77ec4");
                }
                return;
            }

            List<QualifiedNetworks> qualifiedNetworksList = new ArrayList<>();
            int satisfiedApnTypes = 0;
            for (int apnType : SUPPORTED_APN_TYPES) {
                if ((apnTypes & apnType) == apnType) {
                    // skip the APN anomaly detection if not using the T data stack
                    if (mDataConfigManager != null) {
                        satisfiedApnTypes |= apnType;
                        trackFrequentApnTypeChange(apnType);
                    }

                    if (mAvailableNetworks.get(apnType) != null) {
                        if (Arrays.equals(mAvailableNetworks.get(apnType),
                                qualifiedNetworkTypes)) {
@@ -382,6 +403,16 @@ public class AccessNetworksManager extends Handler {
                }
            }

            // Report anomaly if any requested APN types are unsatisfied
            if (satisfiedApnTypes != apnTypes
                    && mDataConfigManager != null
                    && mDataConfigManager.isInvalidQnsParamAnomalyReportEnabled()) {
                int unsatisfied = satisfiedApnTypes ^ apnTypes;
                reportAnomaly("QNS requested unsupported APN Types:"
                        + Integer.toBinaryString(unsatisfied),
                        "3e89a3df-3524-45fa-b5f2-0fb0e4c77ec4");
            }

            if (!qualifiedNetworksList.isEmpty()) {
                setPreferredTransports(qualifiedNetworksList);
                mQualifiedNetworksChangedRegistrants.notifyResult(qualifiedNetworksList);
@@ -389,6 +420,27 @@ public class AccessNetworksManager extends Handler {
        }
    }

    /**
     * Called when receiving preferred transport change request for a specific apnType.
     *
     * @param apnType The requested apnType.
     */
    private void trackFrequentApnTypeChange(@ApnSetting.ApnType int apnType) {
        SlidingWindowEventCounter counter = mApnTypeToQnsChangeNetworkCounter.get(apnType);
        if (counter == null) {
            counter = new SlidingWindowEventCounter(
                    mDataConfigManager.getAnomalyQnsChangeThreshold().timeWindow,
                    mDataConfigManager.getAnomalyQnsChangeThreshold().eventNumOccurrence);
            mApnTypeToQnsChangeNetworkCounter.put(apnType, counter);
        }
        if (counter.addOccurrence()) {
            reportAnomaly("QNS requested network change for "
                            + ApnSetting.getApnTypeString(apnType) + " "
                            + counter.getFrequencyString(),
                    "3e89a3df-3524-45fa-b5f2-b8911abc7d57");
        }
    }

    /**
     * Access networks manager callback. This should be only used by {@link DataNetworkController}.
     */
@@ -422,6 +474,7 @@ public class AccessNetworksManager extends Handler {
        mCarrierConfigManager = (CarrierConfigManager) phone.getContext().getSystemService(
                Context.CARRIER_CONFIG_SERVICE);
        mLogTag = "ANM-" + mPhone.getPhoneId();
        mApnTypeToQnsChangeNetworkCounter = new SparseArray<>();

        if (isInLegacyMode()) {
            log("operates in legacy mode.");
@@ -446,9 +499,10 @@ public class AccessNetworksManager extends Handler {
        }

        if (phone.isUsingNewDataStack()) {
            // Using post to delay the registering because data retry manager instance is created
            // later than access networks manager.
            post(() -> mPhone.getDataNetworkController().getDataRetryManager().registerCallback(
            // Using post to delay the registering because data retry manager and data config
            // manager instances are created later than access networks manager.
            post(() -> {
                mPhone.getDataNetworkController().getDataRetryManager().registerCallback(
                    new DataRetryManager.DataRetryManagerCallback(this::post) {
                        @Override
                        public void onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses) {
@@ -462,8 +516,28 @@ public class AccessNetworksManager extends Handler {
                                loge("onThrottleStatusChanged: ", ex);
                            }
                        }
                    }));
                    });
                mDataConfigManager = mPhone.getDataNetworkController().getDataConfigManager();
                mDataConfigManager.registerCallback(
                        new DataConfigManager.DataConfigManagerCallback(this::post) {
                            @Override
                            public void onDeviceConfigChanged() {
                                mApnTypeToQnsChangeNetworkCounter.clear();
                            }
                        });
            });
        }
    }

    /**
     * Trigger the anomaly report with the specified UUID.
     *
     * @param anomalyMsg Description of the event
     * @param uuid UUID associated with that event
     */
    private void reportAnomaly(@NonNull String anomalyMsg, @NonNull String uuid) {
        logl(anomalyMsg);
        AnomalyReporter.reportAnomaly(UUID.fromString(uuid), anomalyMsg, mPhone.getCarrierId());
    }

    /**
+39 −9
Original line number Diff line number Diff line
@@ -205,6 +205,10 @@ public class DataConfigManager extends Handler {
            "anomaly_setup_data_call_failure";
    /** DeviceConfig key of anomaly report threshold for frequent network-unwanted call. */
    private static final String KEY_ANOMALY_NETWORK_UNWANTED = "anomaly_network_unwanted";
    /** DeviceConfig key of anomaly report threshold for frequent change of preferred network. */
    private static final String KEY_ANOMALY_QNS_CHANGE_NETWORK = "anomaly_qns_change_network";
    /** DeviceConfig key of anomaly report threshold for invalid QNS params. */
    private static final String KEY_ANOMALY_QNS_PARAM = "anomaly_qns_param";
    /** DeviceConfig key of anomaly report threshold for DataNetwork stuck in connecting state. */
    private static final String KEY_ANOMALY_NETWORK_CONNECTING_TIMEOUT =
            "anomaly_network_connecting_timeout";
@@ -227,6 +231,17 @@ public class DataConfigManager extends Handler {
     */
    private EventFrequency mNetworkUnwantedAnomalyReportThreshold;

    /**
     * Anomaly report thresholds for frequent APN type change at {@link AccessNetworksManager}
     */
    private EventFrequency mQnsFrequentApnTypeChangeAnomalyReportThreshold;

    /**
     * {@code true} if enabled anomaly detection for param when QNS wants to change preferred
     * network at {@link AccessNetworksManager}.
     */
    private boolean mIsInvalidQnsParamAnomalyReportEnabled;

    /**
     * Timeout in ms before creating an anomaly report for a DataNetwork stuck in
     * {@link DataNetwork.ConnectingState}.
@@ -392,17 +407,15 @@ public class DataConfigManager extends Handler {
                DeviceConfig.getProperties(DeviceConfig.NAMESPACE_TELEPHONY);

        mImsReleaseRequestAnomalyReportThreshold = parseSlidingWindowCounterThreshold(
                properties.getString(KEY_ANOMALY_IMS_RELEASE_REQUEST, null),
                0,
                2);
                properties.getString(KEY_ANOMALY_IMS_RELEASE_REQUEST, null), 0, 2);
        mNetworkUnwantedAnomalyReportThreshold = parseSlidingWindowCounterThreshold(
                properties.getString(KEY_ANOMALY_NETWORK_UNWANTED, null),
                0,
                12);
                properties.getString(KEY_ANOMALY_NETWORK_UNWANTED, null), 0, 12);
        mSetupDataCallAnomalyReportThreshold = parseSlidingWindowCounterThreshold(
                properties.getString(KEY_ANOMALY_SETUP_DATA_CALL_FAILURE, null),
                0,
                12);
                properties.getString(KEY_ANOMALY_SETUP_DATA_CALL_FAILURE, null), 0, 12);
        mQnsFrequentApnTypeChangeAnomalyReportThreshold = parseSlidingWindowCounterThreshold(
                properties.getString(KEY_ANOMALY_QNS_CHANGE_NETWORK, null), 0, 5);
        mIsInvalidQnsParamAnomalyReportEnabled = properties.getBoolean(
                KEY_ANOMALY_QNS_PARAM, false);
        mNetworkConnectingTimeout = properties.getInt(
                KEY_ANOMALY_NETWORK_CONNECTING_TIMEOUT, MAX_NETWORK_TRANSIT_STATE_TIMEOUT_MS);
        mNetworkDisconnectingTimeout = properties.getInt(
@@ -820,6 +833,23 @@ public class DataConfigManager extends Handler {
        return mImsReleaseRequestAnomalyReportThreshold;
    }

    /**
     * Anomaly report thresholds for frequent QNS change of preferred network
     * at {@link AccessNetworksManager}
     * @return EventFrequency to trigger the anomaly report
     */
    public @NonNull EventFrequency getAnomalyQnsChangeThreshold() {
        return mQnsFrequentApnTypeChangeAnomalyReportThreshold;
    }

    /**
     * @return {@code true} if enabled anomaly report for invalid param when QNS wants to change
     * preferred network at {@link AccessNetworksManager}.
     */
    public boolean isInvalidQnsParamAnomalyReportEnabled() {
        return mIsInvalidQnsParamAnomalyReportEnabled;
    }

    /**
     * @return Timeout in ms before creating an anomaly report for a DataNetwork stuck in
     * {@link DataNetwork.ConnectingState}.
+7 −0
Original line number Diff line number Diff line
@@ -61,6 +61,7 @@ public class AccessNetworksManagerTest extends TelephonyTest {
    private IQualifiedNetworksService mMockedQns;
    private IBinder mMockedIBinder;
    private AccessNetworksManagerCallback mMockedCallback;
    private DataConfigManager mMockedDataConfigManager;

    // The real callback passed created by AccessNetworksManager.
    private IQualifiedNetworksServiceCallback.Stub mQnsCallback;
@@ -106,8 +107,14 @@ public class AccessNetworksManagerTest extends TelephonyTest {
            return null;
        }).when(mMockedCallback).invokeFromExecutor(any(Runnable.class));

        mMockedDataConfigManager = Mockito.mock(DataConfigManager.class);
        doReturn(new DataConfigManager.EventFrequency(0, 2))
                .when(mMockedDataConfigManager).getAnomalyQnsChangeThreshold();
        mAccessNetworksManager = new AccessNetworksManager(mPhone, Looper.myLooper());

        processAllMessages();
        replaceInstance(AccessNetworksManager.class, "mDataConfigManager",
                mAccessNetworksManager, mMockedDataConfigManager);
        assumeFalse(mAccessNetworksManager.isInLegacyMode());
        logd("-setUp");
    }