aboutsummaryrefslogtreecommitdiff
path: root/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java')
-rw-r--r--src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java209
1 files changed, 192 insertions, 17 deletions
diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
index 6c6f06455d..375b2503a7 100644
--- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
+++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java
@@ -23,7 +23,10 @@ import android.annotation.ElapsedRealtimeLong;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.NetworkAgent;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -34,6 +37,7 @@ import android.telephony.Annotation.ValidationStatus;
import android.telephony.CellSignalStrength;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.TextUtils;
import android.util.IndentingPrintWriter;
import android.util.LocalLog;
@@ -127,12 +131,24 @@ public class DataStallRecoveryManager extends Handler {
/** The data stall recovered by user (Mobile Data Power off/on). */
private static final int RECOVERED_REASON_USER = 3;
+ /** The number of milliseconds to wait for the DSRM prediction to complete. */
+ private static final int DSRM_PREDICT_WAITING_MILLIS = 1000;
+
+ /** Event for send data stall broadcast. */
+ private static final int EVENT_SEND_DATA_STALL_BROADCAST = 1;
+
/** Event for triggering recovery action. */
private static final int EVENT_DO_RECOVERY = 2;
/** Event for radio state changed. */
private static final int EVENT_RADIO_STATE_CHANGED = 3;
+ /** Event for recovery actions changed. */
+ private static final int EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED = 4;
+
+ /** Event for duration milliseconds changed. */
+ private static final int EVENT_CONTENT_DSRM_DURATION_MILLIS_CHANGED = 5;
+
private final @NonNull Phone mPhone;
private final @NonNull String mLogTag;
private final @NonNull LocalLog mLocalLog = new LocalLog(128);
@@ -185,8 +201,30 @@ public class DataStallRecoveryManager extends Handler {
/** The boolean array for the flags. They are used to skip the recovery actions if needed. */
private @NonNull boolean[] mSkipRecoveryActionArray;
+ /**
+ * The content URI for the DSRM recovery actions.
+ *
+ * @see Settings.Global#DSRM_ENABLED_ACTIONS
+ */
+ private static final Uri CONTENT_URL_DSRM_ENABLED_ACTIONS = Settings.Global.getUriFor(
+ Settings.Global.DSRM_ENABLED_ACTIONS);
+
+ /**
+ * The content URI for the DSRM duration milliseconds.
+ *
+ * @see Settings.Global#DSRM_DURATION_MILLIS
+ */
+ private static final Uri CONTENT_URL_DSRM_DURATION_MILLIS = Settings.Global.getUriFor(
+ Settings.Global.DSRM_DURATION_MILLIS);
+
+
private DataStallRecoveryManagerCallback mDataStallRecoveryManagerCallback;
+ private final DataStallRecoveryStats mStats;
+
+ /** The number of milliseconds to wait for the DSRM prediction to complete. */
+ private @ElapsedRealtimeLong long mPredictWaitingMillis = 0L;
+
/**
* The data stall recovery manager callback. Note this is only used for passing information
* internally in the data stack, should not be used externally.
@@ -248,6 +286,8 @@ public class DataStallRecoveryManager extends Handler {
updateDataStallRecoveryConfigs();
registerAllEvents();
+
+ mStats = new DataStallRecoveryStats(mPhone, dataNetworkController);
}
/** Register for all events that data stall monitor is interested. */
@@ -280,12 +320,33 @@ public class DataStallRecoveryManager extends Handler {
}
});
mPhone.mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
+
+ // Register for DSRM global setting changes.
+ mPhone.getContext().getContentResolver().registerContentObserver(
+ CONTENT_URL_DSRM_ENABLED_ACTIONS, false, mContentObserver);
+ mPhone.getContext().getContentResolver().registerContentObserver(
+ CONTENT_URL_DSRM_DURATION_MILLIS, false, mContentObserver);
+
}
@Override
public void handleMessage(Message msg) {
logv("handleMessage = " + msg);
switch (msg.what) {
+ case EVENT_SEND_DATA_STALL_BROADCAST:
+ mRecoveryTriggered = true;
+ // Verify that DSRM needs to process the recovery action
+ if (!isRecoveryNeeded(false)) {
+ cancelNetworkCheckTimer();
+ startNetworkCheckTimer(getRecoveryAction());
+ return;
+ }
+ // Broadcast intent that data stall has been detected.
+ broadcastDataStallDetected(getRecoveryAction());
+ // Schedule the message to to wait for the predicted value.
+ sendMessageDelayed(
+ obtainMessage(EVENT_DO_RECOVERY), mPredictWaitingMillis);
+ break;
case EVENT_DO_RECOVERY:
doRecovery();
break;
@@ -302,16 +363,119 @@ public class DataStallRecoveryManager extends Handler {
}
}
break;
+ case EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED:
+ updateGlobalConfigActions();
+ break;
+ case EVENT_CONTENT_DSRM_DURATION_MILLIS_CHANGED:
+ updateGlobalConfigDurations();
+ break;
default:
loge("Unexpected message = " + msg);
break;
}
}
+ private final ContentObserver mContentObserver = new ContentObserver(this) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ super.onChange(selfChange, uri);
+ if (CONTENT_URL_DSRM_ENABLED_ACTIONS.equals(uri)) {
+ log("onChange URI: " + uri);
+ sendMessage(obtainMessage(EVENT_CONTENT_DSRM_ENABLED_ACTIONS_CHANGED));
+ } else if (CONTENT_URL_DSRM_DURATION_MILLIS.equals(uri)) {
+ log("onChange URI: " + uri);
+ sendMessage(obtainMessage(EVENT_CONTENT_DSRM_DURATION_MILLIS_CHANGED));
+ }
+ }
+ };
+
+
+ @VisibleForTesting
+ public ContentObserver getContentObserver() {
+ return mContentObserver;
+ }
+
+ /**
+ * Updates the skip recovery action array based on DSRM global configuration actions.
+ *
+ * @see Settings.Global#DSRM_ENABLED_ACTIONS
+ */
+ private void updateGlobalConfigActions() {
+ String enabledActions = Settings.Global.getString(
+ mPhone.getContext().getContentResolver(),
+ Settings.Global.DSRM_ENABLED_ACTIONS);
+
+ if (!TextUtils.isEmpty(enabledActions)) {
+ String[] splitEnabledActions = enabledActions.split(",");
+ boolean[] enabledActionsArray = new boolean[splitEnabledActions.length];
+ for (int i = 0; i < enabledActionsArray.length; i++) {
+ enabledActionsArray[i] = Boolean.parseBoolean(splitEnabledActions[i].trim());
+ }
+
+ int minLength = Math.min(enabledActionsArray.length,
+ mSkipRecoveryActionArray.length);
+
+ // Update the skip recovery action array.
+ for (int i = 0; i < minLength; i++) {
+ mSkipRecoveryActionArray[i] = !enabledActionsArray[i];
+ }
+ log("SkipRecoveryAction: "
+ + Arrays.toString(mSkipRecoveryActionArray));
+ mPredictWaitingMillis = DSRM_PREDICT_WAITING_MILLIS;
+ } else {
+ mPredictWaitingMillis = 0;
+ log("Enabled actions is null");
+ }
+ }
+
+ /**
+ * Updates the duration millis array based on DSRM global configuration durations.
+ *
+ * @see Settings.Global#DSRM_DURATION_MILLIS
+ */
+ private void updateGlobalConfigDurations() {
+ String durationMillis = Settings.Global.getString(
+ mPhone.getContext().getContentResolver(),
+ Settings.Global.DSRM_DURATION_MILLIS);
+
+ if (!TextUtils.isEmpty(durationMillis)) {
+ String[] splitDurationMillis = durationMillis.split(",");
+ long[] durationMillisArray = new long[splitDurationMillis.length];
+ for (int i = 0; i < durationMillisArray.length; i++) {
+ try {
+ durationMillisArray[i] = Long.parseLong(splitDurationMillis[i].trim());
+ } catch (NumberFormatException e) {
+ mPredictWaitingMillis = 0;
+ loge("Parsing duration millis error");
+ return;
+ }
+ }
+
+ int minLength = Math.min(durationMillisArray.length,
+ mDataStallRecoveryDelayMillisArray.length);
+
+ // Copy the values from the durationMillisArray array to the
+ // mDataStallRecoveryDelayMillisArray array.
+ for (int i = 0; i < minLength; i++) {
+ mDataStallRecoveryDelayMillisArray[i] = durationMillisArray[i];
+ }
+ log("DataStallRecoveryDelayMillis: "
+ + Arrays.toString(mDataStallRecoveryDelayMillisArray));
+ mPredictWaitingMillis = DSRM_PREDICT_WAITING_MILLIS;
+ } else {
+ mPredictWaitingMillis = 0;
+ log("Duration millis is null");
+ }
+ }
+
/** Update the data stall recovery configs from DataConfigManager. */
private void updateDataStallRecoveryConfigs() {
mDataStallRecoveryDelayMillisArray = mDataConfigManager.getDataStallRecoveryDelayMillis();
mSkipRecoveryActionArray = mDataConfigManager.getDataStallRecoveryShouldSkipArray();
+
+ //Update Global settings
+ updateGlobalConfigActions();
+ updateGlobalConfigDurations();
}
/**
@@ -320,7 +484,8 @@ public class DataStallRecoveryManager extends Handler {
* @param recoveryAction The recovery action to query.
* @return the delay in milliseconds for the specific recovery action.
*/
- private long getDataStallRecoveryDelayMillis(@RecoveryAction int recoveryAction) {
+ @VisibleForTesting
+ public long getDataStallRecoveryDelayMillis(@RecoveryAction int recoveryAction) {
return mDataStallRecoveryDelayMillisArray[recoveryAction];
}
@@ -330,7 +495,8 @@ public class DataStallRecoveryManager extends Handler {
* @param recoveryAction The recovery action.
* @return {@code true} if the action needs to be skipped.
*/
- private boolean shouldSkipRecoveryAction(@RecoveryAction int recoveryAction) {
+ @VisibleForTesting
+ public boolean shouldSkipRecoveryAction(@RecoveryAction int recoveryAction) {
return mSkipRecoveryActionArray[recoveryAction];
}
@@ -385,7 +551,7 @@ public class DataStallRecoveryManager extends Handler {
mIsValidNetwork = false;
log("trigger data stall recovery");
mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime();
- sendMessage(obtainMessage(EVENT_DO_RECOVERY));
+ sendMessage(obtainMessage(EVENT_SEND_DATA_STALL_BROADCAST));
}
}
@@ -490,6 +656,22 @@ public class DataStallRecoveryManager extends Handler {
Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED);
SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction);
+
+ // Get the information for DSRS state
+ final boolean isRecovered = !mDataStalled;
+ final int duration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs);
+ final @RecoveredReason int reason = getRecoveredReason(mIsValidNetwork);
+ final boolean isFirstValidationOfAction = false;
+ final int durationOfAction = (int) getDurationOfCurrentRecoveryMs();
+
+ // Get the bundled DSRS stats.
+ Bundle bundle = mStats.getDataStallRecoveryMetricsData(
+ recoveryAction, isRecovered, duration, reason, isFirstValidationOfAction,
+ durationOfAction);
+
+ // Put the bundled stats extras on the intent.
+ intent.putExtra("EXTRA_DSRS_STATS_BUNDLE", bundle);
+
mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE);
}
@@ -531,7 +713,8 @@ public class DataStallRecoveryManager extends Handler {
mNetworkCheckTimerStarted = true;
mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime();
sendMessageDelayed(
- obtainMessage(EVENT_DO_RECOVERY), getDataStallRecoveryDelayMillis(action));
+ obtainMessage(EVENT_SEND_DATA_STALL_BROADCAST),
+ getDataStallRecoveryDelayMillis(action));
}
}
@@ -540,7 +723,7 @@ public class DataStallRecoveryManager extends Handler {
log("cancelNetworkCheckTimer()");
if (mNetworkCheckTimerStarted) {
mNetworkCheckTimerStarted = false;
- removeMessages(EVENT_DO_RECOVERY);
+ removeMessages(EVENT_SEND_DATA_STALL_BROADCAST);
}
}
@@ -645,8 +828,9 @@ public class DataStallRecoveryManager extends Handler {
&& !mIsAttemptedAllSteps)
|| mLastAction == RECOVERY_ACTION_RESET_MODEM)
? (int) getDurationOfCurrentRecoveryMs() : 0;
- DataStallRecoveryStats.onDataStallEvent(
- mLastAction, mPhone, isValid, timeDuration, reason,
+
+ mStats.uploadMetrics(
+ mLastAction, isValid, timeDuration, reason,
isFirstValidationAfterDoRecovery, timeDurationOfCurrentAction);
logl(
"data stall: "
@@ -696,22 +880,12 @@ public class DataStallRecoveryManager extends Handler {
private void doRecovery() {
@RecoveryAction final int recoveryAction = getRecoveryAction();
final int signalStrength = mPhone.getSignalStrength().getLevel();
- mRecoveryTriggered = true;
-
- // DSRM used sendMessageDelayed to process the next event EVENT_DO_RECOVERY, so it need
- // to check the condition if DSRM need to process the recovery action.
- if (!isRecoveryNeeded(false)) {
- cancelNetworkCheckTimer();
- startNetworkCheckTimer(recoveryAction);
- return;
- }
TelephonyMetrics.getInstance()
.writeSignalStrengthEvent(mPhone.getPhoneId(), signalStrength);
TelephonyMetrics.getInstance().writeDataStallEvent(mPhone.getPhoneId(), recoveryAction);
mLastAction = recoveryAction;
mLastActionReported = false;
- broadcastDataStallDetected(recoveryAction);
mNetworkCheckTimerStarted = false;
mTimeElapsedOfCurrentAction = SystemClock.elapsedRealtime();
@@ -873,6 +1047,7 @@ public class DataStallRecoveryManager extends Handler {
pw.println(
"mMobileDataChangedToEnabledDuringDataStall="
+ mMobileDataChangedToEnabledDuringDataStall);
+ pw.println("mPredictWaitingMillis=" + mPredictWaitingMillis);
pw.println(
"DataStallRecoveryDelayMillisArray="
+ Arrays.toString(mDataStallRecoveryDelayMillisArray));