Loading Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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: { Loading src/java/com/android/internal/telephony/dataconnection/DataConnection.java +4 −9 Original line number Diff line number Diff line Loading @@ -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) { Loading src/java/com/android/internal/telephony/dataconnection/DcTracker.java +203 −82 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -573,6 +577,8 @@ public class DcTracker extends Handler { private final int mTransportType; private DataStallRecoveryHandler mDsRecoveryHandler; //***** Constructor public DcTracker(Phone phone, int transportType) { super(); Loading @@ -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); Loading Loading @@ -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"); } } /** Loading Loading @@ -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); } } Loading Loading @@ -3323,7 +3351,7 @@ public class DcTracker extends Handler { break; case DctConstants.EVENT_DO_RECOVERY: doRecovery(); mDsRecoveryHandler.doRecovery(); break; case DctConstants.EVENT_APN_CHANGED: Loading Loading @@ -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 Loading @@ -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: Loading Loading @@ -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() Loading Loading @@ -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); Loading Loading @@ -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(); } } Loading @@ -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; Loading @@ -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"); } Loading Loading @@ -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)); Loading @@ -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); Loading Loading @@ -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; } Loading src/java/com/android/internal/telephony/test/SimulatedCommands.java +6 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } /** Loading tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +215 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -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: { Loading
src/java/com/android/internal/telephony/dataconnection/DataConnection.java +4 −9 Original line number Diff line number Diff line Loading @@ -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) { Loading
src/java/com/android/internal/telephony/dataconnection/DcTracker.java +203 −82 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -573,6 +577,8 @@ public class DcTracker extends Handler { private final int mTransportType; private DataStallRecoveryHandler mDsRecoveryHandler; //***** Constructor public DcTracker(Phone phone, int transportType) { super(); Loading @@ -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); Loading Loading @@ -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"); } } /** Loading Loading @@ -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); } } Loading Loading @@ -3323,7 +3351,7 @@ public class DcTracker extends Handler { break; case DctConstants.EVENT_DO_RECOVERY: doRecovery(); mDsRecoveryHandler.doRecovery(); break; case DctConstants.EVENT_APN_CHANGED: Loading Loading @@ -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 Loading @@ -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: Loading Loading @@ -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() Loading Loading @@ -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); Loading Loading @@ -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(); } } Loading @@ -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; Loading @@ -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"); } Loading Loading @@ -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)); Loading @@ -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); Loading Loading @@ -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; } Loading
src/java/com/android/internal/telephony/test/SimulatedCommands.java +6 −2 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); } /** Loading
tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java +215 −0 File changed.Preview size limit exceeded, changes collapsed. Show changes