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

Commit 0c88584f authored by Jayachandran Chinnakkannu's avatar Jayachandran Chinnakkannu Committed by android-build-merger
Browse files

Merge "Cellular data stall recovery based on networkStatus"

am: 0f4a5449

Change-Id: I1e5627be2f5ece8cb4a042017ad45139bd94d3a6
parents d953cd80 0f4a5449
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ java_library {
        "android.hardware.radio.config-V1.2-java",
        "android.hardware.radio.deprecated-V1.0-java",
        "android.hidl.base-V1.0-java",
	"android-support-annotations",
    ],

    product_variables: {
+4 −9
Original line number Diff line number Diff line
@@ -2200,16 +2200,11 @@ public class DataConnection extends StateMachine {

        @Override
        protected void networkStatus(int status, String redirectUrl) {
            if(!TextUtils.isEmpty(redirectUrl)) {
            log("validation status: " + status + " with redirection URL: " + redirectUrl);
                /* its possible that we have multiple DataConnection with INTERNET_CAPABILITY
                   all fail the validation with the same redirection url, send CMD back to DCTracker
                   and let DcTracker to make the decision */
                Message msg = mDct.obtainMessage(DctConstants.EVENT_REDIRECTION_DETECTED,
                        redirectUrl);
            Message msg = mDct.obtainMessage(DctConstants.EVENT_NETWORK_STATUS_CHANGED,
                    status, 0, redirectUrl);
            msg.sendToTarget();
        }
        }

        @Override
        public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) {
+203 −82
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.internal.telephony.dataconnection;

import static android.Manifest.permission.READ_PHONE_STATE;
import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;

import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT;
import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID;
@@ -38,6 +38,7 @@ import android.database.ContentObserver;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.LinkProperties;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
import android.net.NetworkRequest;
@@ -59,6 +60,7 @@ import android.preference.PreferenceManager;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Telephony;
import android.support.annotation.IntDef;
import android.telephony.AccessNetworkConstants.TransportType;
import android.telephony.CarrierConfigManager;
import android.telephony.CellLocation;
@@ -102,6 +104,8 @@ import com.android.internal.util.AsyncChannel;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
@@ -487,7 +491,7 @@ public class DcTracker extends Handler {
    // Reference counter for enabling fail fast
    private static int sEnableFailFastRefCounter = 0;
    // True if data stall detection is enabled
    private volatile boolean mDataStallDetectionEnabled = true;
    private volatile boolean mDataStallNoRxEnabled = true;

    private volatile boolean mFailFast = false;

@@ -573,6 +577,8 @@ public class DcTracker extends Handler {

    private final int mTransportType;

    private DataStallRecoveryHandler mDsRecoveryHandler;

    //***** Constructor
    public DcTracker(Phone phone, int transportType) {
        super();
@@ -597,6 +603,8 @@ public class DcTracker extends Handler {
        mAlarmManager =
                (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);

        mDsRecoveryHandler = new DataStallRecoveryHandler();

        IntentFilter filter = new IntentFilter();
        filter.addAction(Intent.ACTION_SCREEN_ON);
        filter.addAction(Intent.ACTION_SCREEN_OFF);
@@ -2024,7 +2032,11 @@ public class DcTracker extends Handler {
         */

        int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
        try {
            SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset + 1));
        } catch (RuntimeException ex) {
            log("Failed to set net.ppp.reset-by-timeout");
        }
    }

    /**
@@ -2792,14 +2804,30 @@ public class DcTracker extends Handler {
    }

    /**
     * Called when EVENT_REDIRECTION_DETECTED is received.
     * Called when EVENT_NETWORK_STATUS_CHANGED is received.
     *
     * @param status One of {@code NetworkAgent.VALID_NETWORK} or
     * {@code NetworkAgent.INVALID_NETWORK}.
     * @param redirectUrl If the Internet probe was redirected, this
     * is the destination it was redirected to, otherwise {@code null}
     */
    private void onDataConnectionRedirected(String redirectUrl) {
    private void onNetworkStatusChanged(int status, String redirectUrl) {
        if (!TextUtils.isEmpty(redirectUrl)) {
            Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
            intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, redirectUrl);
            mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
            log("Notify carrier signal receivers with redirectUrl: " + redirectUrl);
        } else {
            final boolean isValid = status == NetworkAgent.VALID_NETWORK;
            if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) {
                if (DBG) log("Skip data stall recovery on network status change with in threshold");
                return;
            }
            if (mTransportType != TransportType.WWAN) {
                if (DBG) log("Skip data stall recovery on non WWAN");
                return;
            }
            mDsRecoveryHandler.processNetworkStatusChanged(isValid);
        }
    }

@@ -3323,7 +3351,7 @@ public class DcTracker extends Handler {
                break;

            case DctConstants.EVENT_DO_RECOVERY:
                doRecovery();
                mDsRecoveryHandler.doRecovery();
                break;

            case DctConstants.EVENT_APN_CHANGED:
@@ -3432,6 +3460,7 @@ public class DcTracker extends Handler {
            case DctConstants.EVENT_ROAMING_SETTING_CHANGE:
                onDataRoamingOnOrSettingsChanged(msg.what);
                break;

            case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE:
                // Update sharedPreference to false when exits new device provisioning, indicating
                // no users modifications on the settings for new devices. Thus carrier specific
@@ -3442,10 +3471,11 @@ public class DcTracker extends Handler {
                    sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit();
                }
                break;
            case DctConstants.EVENT_REDIRECTION_DETECTED:

            case DctConstants.EVENT_NETWORK_STATUS_CHANGED:
                int status = msg.arg1;
                String url = (String) msg.obj;
                log("dataConnectionTracker.handleMessage: EVENT_REDIRECTION_DETECTED=" + url);
                onDataConnectionRedirected(url);
                onNetworkStatusChanged(status, url);
                break;

            case DctConstants.EVENT_RADIO_AVAILABLE:
@@ -3529,8 +3559,8 @@ public class DcTracker extends Handler {
                if (mFailFast != enabled) {
                    mFailFast = enabled;

                    mDataStallDetectionEnabled = !enabled;
                    if (mDataStallDetectionEnabled
                    mDataStallNoRxEnabled = !enabled;
                    if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled()
                            && (getOverallState() == DctConstants.State.CONNECTED)
                            && (!mInVoiceCall ||
                                    mPhone.getServiceStateTracker()
@@ -3807,7 +3837,7 @@ public class DcTracker extends Handler {
        pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
        pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
        pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
        pw.println(" mDataStallDetectionEnabled=" + mDataStallDetectionEnabled);
        pw.println(" mDataStallNoRxEnabled=" + mDataStallNoRxEnabled);
        pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
        pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
        pw.println(" mResolver=" + mResolver);
@@ -4198,80 +4228,172 @@ public class DcTracker extends Handler {
    /**
     * Data-Stall
     */

    // Recovery action taken in case of data stall
    private static class RecoveryAction {
        public static final int GET_DATA_CALL_LIST      = 0;
        public static final int CLEANUP                 = 1;
        public static final int REREGISTER              = 2;
        public static final int RADIO_RESTART           = 3;
    @IntDef(
        value = {
            RECOVERY_ACTION_GET_DATA_CALL_LIST,
            RECOVERY_ACTION_CLEANUP,
            RECOVERY_ACTION_REREGISTER,
            RECOVERY_ACTION_RADIO_RESTART
        })
    @Retention(RetentionPolicy.SOURCE)
    private @interface RecoveryAction {};
    private static final int RECOVERY_ACTION_GET_DATA_CALL_LIST      = 0;
    private static final int RECOVERY_ACTION_CLEANUP                 = 1;
    private static final int RECOVERY_ACTION_REREGISTER              = 2;
    private static final int RECOVERY_ACTION_RADIO_RESTART           = 3;

    // Recovery handler class for cellular data stall
    private class DataStallRecoveryHandler {
        // Default minimum duration between each recovery steps
        private static final int
                DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = (3 * 60 * 1000); // 3 mins

        // The elapsed real time of last recovery attempted
        private long mTimeLastRecoveryStartMs;
        // Whether current network good or not
        private boolean mIsValidNetwork;

        public DataStallRecoveryHandler() {
            reset();
        }

        public void reset() {
            mTimeLastRecoveryStartMs = 0;
            putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST);
        }

        private static boolean isAggressiveRecovery(int value) {
            return ((value == RecoveryAction.CLEANUP) ||
                    (value == RecoveryAction.REREGISTER) ||
                    (value == RecoveryAction.RADIO_RESTART));
        public boolean isAggressiveRecovery() {
            @RecoveryAction int action = getRecoveryAction();

            return ((action == RECOVERY_ACTION_CLEANUP)
                    || (action == RECOVERY_ACTION_REREGISTER)
                    || (action == RECOVERY_ACTION_RADIO_RESTART));
        }

        private long getMinDurationBetweenRecovery() {
            return Settings.Global.getLong(mResolver,
                Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS,
                DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS);
        }

        private long getElapsedTimeSinceRecoveryMs() {
            return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs);
        }

        @RecoveryAction
        private int getRecoveryAction() {
        int action = Settings.System.getInt(mResolver,
                "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
            @RecoveryAction int action = Settings.System.getInt(mResolver,
                    "radio.data.stall.recovery.action", RECOVERY_ACTION_GET_DATA_CALL_LIST);
            if (VDBG_STALL) log("getRecoveryAction: " + action);
            return action;
        }

    private void putRecoveryAction(int action) {
        private void putRecoveryAction(@RecoveryAction int action) {
            Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action);
            if (VDBG_STALL) log("putRecoveryAction: " + action);
        }

    private void broadcastDataStallDetected(int recoveryAction) {
        private void broadcastDataStallDetected(@RecoveryAction int recoveryAction) {
            Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED);
            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
            intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction);
        mPhone.getContext().sendBroadcast(intent, READ_PHONE_STATE);
            mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE);
        }

        private boolean isRecoveryAlreadyStarted() {
            return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST;
        }

    private void doRecovery() {
        private boolean checkRecovery() {
            // To avoid back to back recovery wait for a grace period
            if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) {
                if (VDBG_STALL) log("skip back to back data stall recovery");
                return false;
            }
            // Data is not allowed in current environment
            if (!isDataAllowed(null, null)) {
                log("skipped data stall recovery due to data is not allowd");
                return false;
            }
            return true;
        }

        private void triggerRecovery() {
            sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
        }

        public void doRecovery() {
            if (getOverallState() == DctConstants.State.CONNECTED) {
                // Go through a series of recovery steps, each action transitions to the next action
            final int recoveryAction = getRecoveryAction();
            TelephonyMetrics.getInstance().writeDataStallEvent(mPhone.getPhoneId(), recoveryAction);
                @RecoveryAction final int recoveryAction = getRecoveryAction();
                TelephonyMetrics.getInstance().writeDataStallEvent(
                        mPhone.getPhoneId(), recoveryAction);
                broadcastDataStallDetected(recoveryAction);

                switch (recoveryAction) {
                case RecoveryAction.GET_DATA_CALL_LIST:
                    case RECOVERY_ACTION_GET_DATA_CALL_LIST:
                        EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
                            mSentSinceLastRecv);
                        if (DBG) log("doRecovery() get data call list");
                        mDataServiceManager.getDataCallList(obtainMessage());
                    putRecoveryAction(RecoveryAction.CLEANUP);
                        putRecoveryAction(RECOVERY_ACTION_CLEANUP);
                        break;
                case RecoveryAction.CLEANUP:
                    case RECOVERY_ACTION_CLEANUP:
                        EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP,
                            mSentSinceLastRecv);
                        if (DBG) log("doRecovery() cleanup all connections");
                    cleanUpAllConnectionsInternal(true, Phone.REASON_PDP_RESET);
                    putRecoveryAction(RecoveryAction.REREGISTER);
                        cleanUpAllConnections(Phone.REASON_PDP_RESET);
                        putRecoveryAction(RECOVERY_ACTION_REREGISTER);
                        break;
                case RecoveryAction.REREGISTER:
                    case RECOVERY_ACTION_REREGISTER:
                        EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
                            mSentSinceLastRecv);
                        if (DBG) log("doRecovery() re-register");
                        mPhone.getServiceStateTracker().reRegisterNetwork(null);
                    putRecoveryAction(RecoveryAction.RADIO_RESTART);
                        putRecoveryAction(RECOVERY_ACTION_RADIO_RESTART);
                        break;
                case RecoveryAction.RADIO_RESTART:
                    case RECOVERY_ACTION_RADIO_RESTART:
                        EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
                            mSentSinceLastRecv);
                        if (DBG) log("restarting radio");
                        restartRadio();
                    putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
                        reset();
                        break;
                    default:
                        throw new RuntimeException("doRecovery: Invalid recoveryAction="
                            + recoveryAction);
                }
                mSentSinceLastRecv = 0;
                mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime();
            }
        }

        public void processNetworkStatusChanged(boolean isValid) {
            if (isValid) {
                mIsValidNetwork = true;
                reset();
            } else {
                if (mIsValidNetwork || isRecoveryAlreadyStarted()) {
                    mIsValidNetwork = false;
                    // Check and trigger a recovery if network switched from good
                    // to bad or recovery is already started before.
                    if (checkRecovery()) {
                        if (DBG) log("trigger data stall recovery");
                        triggerRecovery();
                    }
                }
            }
        }

        public boolean isRecoveryOnBadNetworkEnabled() {
            return Settings.Global.getInt(mResolver,
                    Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1;
        }

        public boolean isNoRxDataStallDetectionEnabled() {
            return mDataStallNoRxEnabled && !isRecoveryOnBadNetworkEnabled();
        }
    }

@@ -4298,7 +4420,7 @@ public class DcTracker extends Handler {
        if ( sent > 0 && received > 0 ) {
            if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
            mSentSinceLastRecv = 0;
            putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
            mDsRecoveryHandler.reset();
        } else if (sent > 0 && received == 0) {
            if (isPhoneStateIdle()) {
                mSentSinceLastRecv += sent;
@@ -4312,7 +4434,7 @@ public class DcTracker extends Handler {
        } else if (sent == 0 && received > 0) {
            if (VDBG_STALL) log("updateDataStallInfo: IN");
            mSentSinceLastRecv = 0;
            putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
            mDsRecoveryHandler.reset();
        } else {
            if (VDBG_STALL) log("updateDataStallInfo: NONE");
        }
@@ -4347,7 +4469,8 @@ public class DcTracker extends Handler {
        boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
        if (mSentSinceLastRecv >= hangWatchdogTrigger) {
            if (DBG) {
                log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
                log("onDataStallAlarm: tag=" + tag + " do recovery action="
                        + mDsRecoveryHandler.getRecoveryAction());
            }
            suspectedStall = DATA_STALL_SUSPECTED;
            sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
@@ -4361,13 +4484,13 @@ public class DcTracker extends Handler {
    }

    private void startDataStallAlarm(boolean suspectedStall) {
        int nextAction = getRecoveryAction();
        int delayInMs;

        if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
        if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled()
                && getOverallState() == DctConstants.State.CONNECTED) {
            // If screen is on or data stall is currently suspected, set the alarm
            // with an aggressive timeout.
            if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
            if (mIsScreenOn || suspectedStall || mDsRecoveryHandler.isAggressiveRecovery()) {
                delayInMs = Settings.Global.getInt(mResolver,
                        Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
                        DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
@@ -4413,9 +4536,7 @@ public class DcTracker extends Handler {
        if (isConnected() == false) return;
        // To be called on screen status change.
        // Do not cancel the alarm if it is set with aggressive timeout.
        int nextAction = getRecoveryAction();

        if (RecoveryAction.isAggressiveRecovery(nextAction)) {
        if (mDsRecoveryHandler.isAggressiveRecovery()) {
            if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
            return;
        }
+6 −2
Original line number Diff line number Diff line
@@ -45,7 +45,6 @@ import android.telephony.Rlog;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.data.DataCallResponse;
import android.telephony.data.DataProfile;
import android.telephony.emergency.EmergencyNumber;

@@ -540,7 +539,12 @@ public class SimulatedCommands extends BaseCommands
     */
    @Override
    public void getDataCallList(Message result) {
        resultSuccess(result, new ArrayList<DataCallResponse>(0));
        ArrayList<SetupDataCallResult> dcCallList = new ArrayList<SetupDataCallResult>(0);
        SimulatedCommandsVerifier.getInstance().getDataCallList(result);
        if (mSetupDataCallResult != null) {
            dcCallList.add(mSetupDataCallResult);
        }
        resultSuccess(result, dcCallList);
    }

    /**
+215 −0

File changed.

Preview size limit exceeded, changes collapsed.