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

Commit f047d8a2 authored by Ling Ma's avatar Ling Ma Committed by Android (Google) Code Review
Browse files

Merge "Add anomaly reports for QNS input" into tm-d1-dev

parents 00a1031e 3df338f1
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, DEFAULT_NETWORK_TRANSIT_STATE_TIMEOUT_MS);
        mNetworkDisconnectingTimeout = properties.getInt(
@@ -829,6 +842,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");
    }