1 /* 2 * Copyright 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.internal.telephony.data; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.ElapsedRealtimeLong; 21 import android.annotation.IntDef; 22 import android.annotation.NonNull; 23 import android.annotation.Nullable; 24 import android.app.AlarmManager; 25 import android.app.PendingIntent; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.net.NetworkCapabilities; 31 import android.os.AsyncResult; 32 import android.os.Handler; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.SystemClock; 36 import android.telephony.AccessNetworkConstants; 37 import android.telephony.AccessNetworkConstants.TransportType; 38 import android.telephony.Annotation.DataFailureCause; 39 import android.telephony.Annotation.NetCapability; 40 import android.telephony.AnomalyReporter; 41 import android.telephony.DataFailCause; 42 import android.telephony.data.DataCallResponse; 43 import android.telephony.data.DataProfile; 44 import android.telephony.data.ThrottleStatus; 45 import android.telephony.data.ThrottleStatus.RetryType; 46 import android.text.TextUtils; 47 import android.util.ArraySet; 48 import android.util.IndentingPrintWriter; 49 import android.util.LocalLog; 50 import android.util.SparseArray; 51 52 import com.android.internal.annotations.VisibleForTesting; 53 import com.android.internal.telephony.CommandsInterface; 54 import com.android.internal.telephony.Phone; 55 import com.android.internal.telephony.data.DataConfigManager.DataConfigManagerCallback; 56 import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback; 57 import com.android.internal.telephony.data.DataNetworkController.NetworkRequestList; 58 import com.android.internal.telephony.data.DataProfileManager.DataProfileManagerCallback; 59 import com.android.telephony.Rlog; 60 61 import java.io.FileDescriptor; 62 import java.io.PrintWriter; 63 import java.util.ArrayList; 64 import java.util.Arrays; 65 import java.util.List; 66 import java.util.Locale; 67 import java.util.Objects; 68 import java.util.Set; 69 import java.util.UUID; 70 import java.util.concurrent.Executor; 71 import java.util.concurrent.TimeUnit; 72 import java.util.stream.Collectors; 73 import java.util.stream.Stream; 74 75 /** 76 * DataRetryManager manages data network setup retry and its configurations. 77 */ 78 public class DataRetryManager extends Handler { 79 private static final boolean VDBG = false; 80 81 /** Intent of Alarm Manager for long retry timer. */ 82 private static final String ACTION_RETRY = "com.android.internal.telephony.data.ACTION_RETRY"; 83 /** The extra key for the hashcode of the retry entry for Alarm Manager. */ 84 private static final String ACTION_RETRY_EXTRA_HASHCODE = "extra_retry_hashcode"; 85 86 /** Event for data setup retry. */ 87 private static final int EVENT_DATA_SETUP_RETRY = 3; 88 89 /** Event for data handover retry. */ 90 private static final int EVENT_DATA_HANDOVER_RETRY = 4; 91 92 /** Event for data profile/apn unthrottled. */ 93 private static final int EVENT_DATA_PROFILE_UNTHROTTLED = 6; 94 95 /** Event for cancelling pending handover retry. */ 96 private static final int EVENT_CANCEL_PENDING_HANDOVER_RETRY = 7; 97 98 /** 99 * Event for radio on. This can happen when airplane mode is turned off, or RIL crashes and came 100 * back online. 101 */ 102 private static final int EVENT_RADIO_ON = 8; 103 104 /** Event for modem reset. */ 105 private static final int EVENT_MODEM_RESET = 9; 106 107 /** Event for tracking area code change. */ 108 private static final int EVENT_TAC_CHANGED = 10; 109 110 /** The maximum entries to preserve. */ 111 private static final int MAXIMUM_HISTORICAL_ENTRIES = 100; 112 /** 113 * The threshold of retry timer, longer than or equal to which we use alarm manager to schedule 114 * instead of handler. 115 */ 116 private static final long RETRY_LONG_DELAY_TIMER_THRESHOLD_MILLIS = TimeUnit 117 .MINUTES.toMillis(1); 118 119 @IntDef(prefix = {"RESET_REASON_"}, 120 value = { 121 RESET_REASON_DATA_PROFILES_CHANGED, 122 RESET_REASON_RADIO_ON, 123 RESET_REASON_MODEM_RESTART, 124 RESET_REASON_DATA_SERVICE_BOUND, 125 RESET_REASON_DATA_CONFIG_CHANGED, 126 RESET_REASON_TAC_CHANGED, 127 }) 128 public @interface RetryResetReason {} 129 130 /** Reset due to data profiles changed. */ 131 private static final int RESET_REASON_DATA_PROFILES_CHANGED = 1; 132 133 /** Reset due to radio on. This could happen after airplane mode off or RIL restarted. */ 134 private static final int RESET_REASON_RADIO_ON = 2; 135 136 /** Reset due to modem restarted. */ 137 private static final int RESET_REASON_MODEM_RESTART = 3; 138 139 /** 140 * Reset due to data service bound. This could happen when reboot or when data service crashed 141 * and rebound. 142 */ 143 private static final int RESET_REASON_DATA_SERVICE_BOUND = 4; 144 145 /** Reset due to data config changed. */ 146 private static final int RESET_REASON_DATA_CONFIG_CHANGED = 5; 147 148 /** Reset due to tracking area code changed. */ 149 private static final int RESET_REASON_TAC_CHANGED = 6; 150 151 /** The phone instance. */ 152 private final @NonNull Phone mPhone; 153 154 /** The RIL instance. */ 155 private final @NonNull CommandsInterface mRil; 156 157 /** Logging tag. */ 158 private final @NonNull String mLogTag; 159 160 /** Local log. */ 161 private final @NonNull LocalLog mLocalLog = new LocalLog(128); 162 163 /** Alarm Manager used to schedule long set up or handover retries. */ 164 private final @NonNull AlarmManager mAlarmManager; 165 166 /** 167 * The data retry callback. This is only used to notify {@link DataNetworkController} to retry 168 * setup data network. 169 */ 170 private @NonNull Set<DataRetryManagerCallback> mDataRetryManagerCallbacks = new ArraySet<>(); 171 172 /** Data service managers. */ 173 private @NonNull SparseArray<DataServiceManager> mDataServiceManagers; 174 175 /** Data config manager instance. */ 176 private final @NonNull DataConfigManager mDataConfigManager; 177 178 /** Data profile manager. */ 179 private final @NonNull DataProfileManager mDataProfileManager; 180 181 /** Data setup retry rule list. */ 182 private @NonNull List<DataSetupRetryRule> mDataSetupRetryRuleList = new ArrayList<>(); 183 184 /** Data handover retry rule list. */ 185 private @NonNull List<DataHandoverRetryRule> mDataHandoverRetryRuleList = new ArrayList<>(); 186 187 /** Data retry entries. */ 188 private final @NonNull List<DataRetryEntry> mDataRetryEntries = new ArrayList<>(); 189 190 /** 191 * Data throttling entries. Note this only stores throttling requested by networks. We intended 192 * not to store frameworks-initiated throttling because they are not explicit/strong throttling 193 * requests. 194 */ 195 private final @NonNull List<DataThrottlingEntry> mDataThrottlingEntries = new ArrayList<>(); 196 197 /** 198 * Represent a single data setup/handover throttling reported by networks. 199 */ 200 public static class DataThrottlingEntry { 201 /** 202 * The data profile that is being throttled for setup/handover retry. 203 */ 204 public final @NonNull DataProfile dataProfile; 205 206 /** 207 * The associated network request list when throttling happened. Should be {@code null} when 208 * retry type is {@link ThrottleStatus#RETRY_TYPE_HANDOVER}. 209 */ 210 public final @Nullable NetworkRequestList networkRequestList; 211 212 /** 213 * @param dataNetwork The data network that is being throttled for handover retry. Should be 214 * {@code null} when retryType is {@link ThrottleStatus#RETRY_TYPE_NEW_CONNECTION}. 215 */ 216 public final @Nullable DataNetwork dataNetwork; 217 218 /** The transport that the data profile has been throttled on. */ 219 public final @TransportType int transport; 220 221 /** The retry type when throttling expires. */ 222 public final @RetryType int retryType; 223 224 /** 225 * The expiration time of data throttling. This is the time retrieved from 226 * {@link SystemClock#elapsedRealtime()}. 227 */ 228 public final @ElapsedRealtimeLong long expirationTimeMillis; 229 230 /** 231 * Constructor. 232 * 233 * @param dataProfile The data profile that is being throttled for setup/handover retry. 234 * @param networkRequestList The associated network request list when throttling happened. 235 * Should be {@code null} when retry type is {@link ThrottleStatus#RETRY_TYPE_HANDOVER}. 236 * @param dataNetwork The data network that is being throttled for handover retry. 237 * Should be {@code null} when retryType is 238 * {@link ThrottleStatus#RETRY_TYPE_NEW_CONNECTION}. 239 * @param transport The transport that the data profile has been throttled on. 240 * @param retryType The retry type when throttling expires. 241 * @param expirationTimeMillis The expiration elapsed time of data throttling. 242 */ DataThrottlingEntry(@onNull DataProfile dataProfile, @Nullable NetworkRequestList networkRequestList, @Nullable DataNetwork dataNetwork, @TransportType int transport, @RetryType int retryType, @ElapsedRealtimeLong long expirationTimeMillis)243 public DataThrottlingEntry(@NonNull DataProfile dataProfile, 244 @Nullable NetworkRequestList networkRequestList, 245 @Nullable DataNetwork dataNetwork, @TransportType int transport, 246 @RetryType int retryType, @ElapsedRealtimeLong long expirationTimeMillis) { 247 this.dataProfile = dataProfile; 248 this.networkRequestList = networkRequestList; 249 this.dataNetwork = dataNetwork; 250 this.transport = transport; 251 this.retryType = retryType; 252 this.expirationTimeMillis = expirationTimeMillis; 253 } 254 255 @Override toString()256 public @NonNull String toString() { 257 return "[DataThrottlingEntry: dataProfile=" + dataProfile + ", request list=" 258 + networkRequestList + ", dataNetwork=" + dataNetwork + ", transport=" 259 + AccessNetworkConstants.transportTypeToString(transport) + ", expiration time=" 260 + DataUtils.elapsedTimeToString(expirationTimeMillis) + "]"; 261 } 262 } 263 264 /** 265 * Represent a data retry rule. A rule consists a retry type (e.g. either by capabilities, 266 * fail cause, or both), and a retry interval. 267 */ 268 public static class DataRetryRule { 269 private static final String RULE_TAG_FAIL_CAUSES = "fail_causes"; 270 private static final String RULE_TAG_RETRY_INTERVAL = "retry_interval"; 271 private static final String RULE_TAG_MAXIMUM_RETRIES = "maximum_retries"; 272 273 /** 274 * The data network setup retry interval. Note that if this is empty, then 275 * {@link #getMaxRetries()} must return 0. Default retry interval is 5 seconds. 276 */ 277 protected List<Long> mRetryIntervalsMillis = List.of(TimeUnit.SECONDS.toMillis(5)); 278 279 /** 280 * The maximum retry times. After reaching the retry times, data retry will not be scheduled 281 * with timer. Only environment changes (e.g. Airplane mode, SIM state, RAT, registration 282 * state changes, etc..) can trigger the retry. 283 */ 284 protected int mMaxRetries = 10; 285 286 /** 287 * The network capabilities. Each data setup must be 288 * associated with at least one network request. If that network request contains network 289 * capabilities specified here, then retry will happen. Empty set indicates the retry rule 290 * is not using network capabilities. 291 */ 292 protected @NonNull @NetCapability Set<Integer> mNetworkCapabilities = new ArraySet<>(); 293 294 /** 295 * The fail causes. If data setup failed with certain fail causes, then retry will happen. 296 * Empty set indicates the retry rule is not using the fail causes. 297 */ 298 protected @NonNull @DataFailureCause Set<Integer> mFailCauses = new ArraySet<>(); 299 DataRetryRule(@onNull String ruleString)300 public DataRetryRule(@NonNull String ruleString) { 301 if (TextUtils.isEmpty(ruleString)) { 302 throw new IllegalArgumentException("illegal rule " + ruleString); 303 } 304 ruleString = ruleString.trim().toLowerCase(Locale.ROOT); 305 String[] expressions = ruleString.split("\\s*,\\s*"); 306 for (String expression : expressions) { 307 String[] tokens = expression.trim().split("\\s*=\\s*"); 308 if (tokens.length != 2) { 309 throw new IllegalArgumentException("illegal rule " + ruleString); 310 } 311 String key = tokens[0].trim(); 312 String value = tokens[1].trim(); 313 try { 314 switch (key) { 315 case RULE_TAG_FAIL_CAUSES: 316 mFailCauses = Arrays.stream(value.split("\\s*\\|\\s*")) 317 .map(String::trim) 318 .map(Integer::valueOf) 319 .collect(Collectors.toSet()); 320 break; 321 case RULE_TAG_RETRY_INTERVAL: 322 mRetryIntervalsMillis = Arrays.stream(value.split("\\s*\\|\\s*")) 323 .map(String::trim) 324 .map(Long::valueOf) 325 .collect(Collectors.toList()); 326 break; 327 case RULE_TAG_MAXIMUM_RETRIES: 328 mMaxRetries = Integer.parseInt(value); 329 break; 330 } 331 } catch (Exception e) { 332 e.printStackTrace(); 333 throw new IllegalArgumentException("illegal rule " + ruleString + ", e=" + e); 334 } 335 } 336 337 if (mMaxRetries < 0) { 338 throw new IllegalArgumentException("Max retries should not be less than 0. " 339 + "mMaxRetries=" + mMaxRetries); 340 } 341 342 if (mRetryIntervalsMillis.stream().anyMatch(i -> i <= 0)) { 343 throw new IllegalArgumentException("Retry interval should not be less than 0. " 344 + "mRetryIntervalsMillis=" + mRetryIntervalsMillis); 345 } 346 } 347 348 /** 349 * @return The data network setup retry intervals in milliseconds. If this is empty, then 350 * {@link #getMaxRetries()} must return 0. 351 */ getRetryIntervalsMillis()352 public @NonNull List<Long> getRetryIntervalsMillis() { 353 return mRetryIntervalsMillis; 354 } 355 356 /** 357 * @return The maximum retry times. After reaching the retry times, data retry will not be 358 * scheduled with timer. Only environment changes (e.g. Airplane mode, SIM state, RAT, 359 * registration state changes, etc..) can trigger the retry. Note that if max retries 360 * is 0, then {@link #getRetryIntervalsMillis()} must be {@code null}. 361 */ getMaxRetries()362 public int getMaxRetries() { 363 return mMaxRetries; 364 } 365 366 /** 367 * @return The fail causes. If data setup failed with certain fail causes, then retry will 368 * happen. Empty set indicates the retry rule is not using the fail causes. 369 */ 370 @VisibleForTesting getFailCauses()371 public @NonNull @DataFailureCause Set<Integer> getFailCauses() { 372 return mFailCauses; 373 } 374 } 375 376 /** 377 * Represent a rule for data setup retry. 378 * 379 * The syntax of the retry rule: 380 * 1. Retry based on {@link NetworkCapabilities}. Note that only APN-type network capabilities 381 * are supported. If the capabilities are not specified, then the retry rule only applies 382 * to the current failed APN used in setup data call request. 383 * "capabilities=[netCaps1|netCaps2|...], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" 384 * 385 * 2. Retry based on {@link DataFailCause} 386 * "fail_causes=[cause1|cause2|cause3|..], [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" 387 * 388 * 3. Retry based on {@link NetworkCapabilities} and {@link DataFailCause}. Note that only 389 * APN-type network capabilities are supported. 390 * "capabilities=[netCaps1|netCaps2|...], fail_causes=[cause1|cause2|cause3|...], 391 * [retry_interval=n1|n2|n3|n4...], [maximum_retries=n]" 392 * 393 * 4. Permanent fail causes (no timer-based retry) on the current failed APN. Retry interval 394 * is specified for retrying the next available APN. 395 * "permanent_fail_causes=8|27|28|29|30|32|33|35|50|51|111|-5|-6|65537|65538|-3|65543|65547| 396 * 2252|2253|2254, retry_interval=2500" 397 * 398 * For example, 399 * "capabilities=eims, retry_interval=1000, maximum_retries=20" means if the attached 400 * network request is emergency, then retry data network setup every 1 second for up to 20 401 * times. 402 * 403 * "capabilities=internet|enterprise|dun|ims|fota, retry_interval=2500|3000|" 404 * "5000|10000|15000|20000|40000|60000|120000|240000|600000|1200000|1800000" 405 * "1800000, maximum_retries=20" means for those capabilities, retry happens in 2.5s, 3s, 5s, 406 * 10s, 15s, 20s, 40s, 1m, 2m, 4m, 10m, 20m, 30m, 30m, 30m, until reaching 20 retries. 407 * 408 */ 409 public static class DataSetupRetryRule extends DataRetryRule { 410 private static final String RULE_TAG_PERMANENT_FAIL_CAUSES = "permanent_fail_causes"; 411 private static final String RULE_TAG_CAPABILITIES = "capabilities"; 412 413 /** {@code true} if this rule is for permanent fail causes. */ 414 private boolean mIsPermanentFailCauseRule; 415 416 /** 417 * Constructor 418 * 419 * @param ruleString The retry rule in string format. 420 * @throws IllegalArgumentException if the string can't be parsed to a retry rule. 421 */ DataSetupRetryRule(@onNull String ruleString)422 public DataSetupRetryRule(@NonNull String ruleString) { 423 super(ruleString); 424 425 ruleString = ruleString.trim().toLowerCase(Locale.ROOT); 426 String[] expressions = ruleString.split("\\s*,\\s*"); 427 for (String expression : expressions) { 428 String[] tokens = expression.trim().split("\\s*=\\s*"); 429 if (tokens.length != 2) { 430 throw new IllegalArgumentException("illegal rule " + ruleString); 431 } 432 String key = tokens[0].trim(); 433 String value = tokens[1].trim(); 434 try { 435 switch (key) { 436 case RULE_TAG_PERMANENT_FAIL_CAUSES: 437 mFailCauses = Arrays.stream(value.split("\\s*\\|\\s*")) 438 .map(String::trim) 439 .map(Integer::valueOf) 440 .collect(Collectors.toSet()); 441 mIsPermanentFailCauseRule = true; 442 break; 443 case RULE_TAG_CAPABILITIES: 444 mNetworkCapabilities = DataUtils 445 .getNetworkCapabilitiesFromString(value); 446 break; 447 } 448 } catch (Exception e) { 449 e.printStackTrace(); 450 throw new IllegalArgumentException("illegal rule " + ruleString + ", e=" + e); 451 } 452 } 453 454 if (mFailCauses.isEmpty() && (mNetworkCapabilities.isEmpty() 455 || mNetworkCapabilities.contains(-1))) { 456 throw new IllegalArgumentException("illegal rule " + ruleString 457 + ". Should have either valid network capabilities or fail causes."); 458 } 459 } 460 461 /** 462 * @return The network capabilities. Each data setup must be associated with at least one 463 * network request. If that network request contains network capabilities specified here, 464 * then retry will happen. Empty set indicates the retry rule is not using network 465 * capabilities. 466 */ 467 @VisibleForTesting getNetworkCapabilities()468 public @NonNull @NetCapability Set<Integer> getNetworkCapabilities() { 469 return mNetworkCapabilities; 470 } 471 472 /** 473 * @return {@code true} if this rule is for permanent fail causes. 474 */ isPermanentFailCauseRule()475 public boolean isPermanentFailCauseRule() { 476 return mIsPermanentFailCauseRule; 477 } 478 479 /** 480 * Check if this rule can be matched. 481 * 482 * @param networkCapability The network capability for matching. 483 * @param cause Fail cause from previous setup data request. 484 * @return {@code true} if the retry rule can be matched. 485 */ canBeMatched(@onNull @etCapability int networkCapability, @DataFailureCause int cause)486 public boolean canBeMatched(@NonNull @NetCapability int networkCapability, 487 @DataFailureCause int cause) { 488 if (!mFailCauses.isEmpty() && !mFailCauses.contains(cause)) { 489 return false; 490 } 491 492 return mNetworkCapabilities.isEmpty() 493 || mNetworkCapabilities.contains(networkCapability); 494 } 495 496 @Override toString()497 public String toString() { 498 return "[DataSetupRetryRule: Network capabilities:" 499 + DataUtils.networkCapabilitiesToString(mNetworkCapabilities.stream() 500 .mapToInt(Number::intValue).toArray()) 501 + ", Fail causes=" + mFailCauses 502 + ", Retry intervals=" + mRetryIntervalsMillis + ", Maximum retries=" 503 + mMaxRetries + "]"; 504 } 505 } 506 507 /** 508 * Represent a handover data network retry rule. 509 * 510 * The syntax of the retry rule: 511 * 1. Retry when handover fails. 512 * "retry_interval=[n1|n2|n3|...], [maximum_retries=n]" 513 * 514 * For example, 515 * "retry_interval=1000|3000|5000, maximum_retries=10" means handover retry will happen in 1s, 516 * 3s, 5s, 5s, 5s....up to 10 times. 517 * 518 * 2. Retry when handover fails with certain fail causes. 519 * "retry_interval=[n1|n2|n3|...], fail_causes=[cause1|cause2|cause3|...], [maximum_retries=n] 520 * 521 * For example, 522 * "retry_interval=1000, maximum_retries=3, fail_causes=5" means handover retry every 1 second 523 * for up to 3 times when handover fails with the cause 5. 524 * 525 * "maximum_retries=0, fail_causes=6|10|67" means handover retry should not happen for those 526 * causes. 527 */ 528 public static class DataHandoverRetryRule extends DataRetryRule { 529 /** 530 * Constructor 531 * 532 * @param ruleString The retry rule in string format. 533 * @throws IllegalArgumentException if the string can't be parsed to a retry rule. 534 */ DataHandoverRetryRule(@onNull String ruleString)535 public DataHandoverRetryRule(@NonNull String ruleString) { 536 super(ruleString); 537 } 538 539 @Override toString()540 public String toString() { 541 return "[DataHandoverRetryRule: Retry intervals=" + mRetryIntervalsMillis 542 + ", Fail causes=" + mFailCauses + ", Maximum retries=" + mMaxRetries + "]"; 543 } 544 } 545 546 /** 547 * Represent a data retry entry. 548 */ 549 public static class DataRetryEntry { 550 /** Indicates the retry is not happened yet. */ 551 public static final int RETRY_STATE_NOT_RETRIED = 1; 552 553 /** Indicates the retry happened, but still failed to setup/handover the data network. */ 554 public static final int RETRY_STATE_FAILED = 2; 555 556 /** Indicates the retry happened and succeeded. */ 557 public static final int RETRY_STATE_SUCCEEDED = 3; 558 559 /** Indicates the retry was cancelled. */ 560 public static final int RETRY_STATE_CANCELLED = 4; 561 562 @IntDef(prefix = {"RETRY_STATE_"}, 563 value = { 564 RETRY_STATE_NOT_RETRIED, 565 RETRY_STATE_FAILED, 566 RETRY_STATE_SUCCEEDED, 567 RETRY_STATE_CANCELLED 568 }) 569 public @interface DataRetryState {} 570 571 /** The rule used for this data retry. {@code null} if the retry is requested by network. */ 572 public final @Nullable DataRetryRule appliedDataRetryRule; 573 574 /** The retry delay in milliseconds. */ 575 public final long retryDelayMillis; 576 577 /** 578 * Retry elapsed time. This is the system elapsed time retrieved from 579 * {@link SystemClock#elapsedRealtime()}. 580 */ 581 public final @ElapsedRealtimeLong long retryElapsedTime; 582 583 /** The retry state. */ 584 protected int mRetryState = RETRY_STATE_NOT_RETRIED; 585 586 /** Timestamp when a state is set. For debugging purposes only. */ 587 protected @ElapsedRealtimeLong long mRetryStateTimestamp = 0; 588 589 /** 590 * Constructor 591 * 592 * @param appliedDataRetryRule The applied data retry rule. 593 * @param retryDelayMillis The retry delay in milliseconds. 594 */ DataRetryEntry(@ullable DataRetryRule appliedDataRetryRule, long retryDelayMillis)595 public DataRetryEntry(@Nullable DataRetryRule appliedDataRetryRule, long retryDelayMillis) { 596 this.appliedDataRetryRule = appliedDataRetryRule; 597 this.retryDelayMillis = retryDelayMillis; 598 599 mRetryStateTimestamp = SystemClock.elapsedRealtime(); 600 retryElapsedTime = mRetryStateTimestamp + retryDelayMillis; 601 } 602 603 /** 604 * Set the state of a data retry. 605 * 606 * @param state The retry state. 607 */ setState(@ataRetryState int state)608 public void setState(@DataRetryState int state) { 609 mRetryState = state; 610 mRetryStateTimestamp = SystemClock.elapsedRealtime(); 611 } 612 613 /** 614 * @return Get the retry state. 615 */ getState()616 public @DataRetryState int getState() { 617 return mRetryState; 618 } 619 620 /** 621 * Convert retry state to string. 622 * 623 * @param retryState Retry state. 624 * @return Retry state in string format. 625 */ retryStateToString(@ataRetryState int retryState)626 public static String retryStateToString(@DataRetryState int retryState) { 627 switch (retryState) { 628 case RETRY_STATE_NOT_RETRIED: return "NOT_RETRIED"; 629 case RETRY_STATE_FAILED: return "FAILED"; 630 case RETRY_STATE_SUCCEEDED: return "SUCCEEDED"; 631 case RETRY_STATE_CANCELLED: return "CANCELLED"; 632 default: return "Unknown(" + retryState + ")"; 633 } 634 } 635 636 /** 637 * The generic builder for retry entry. 638 * 639 * @param <T> The type of extended retry entry builder. 640 */ 641 public static class Builder<T extends Builder<T>> { 642 /** 643 * The retry delay in milliseconds. Default is 5 seconds. 644 */ 645 protected long mRetryDelayMillis = TimeUnit.SECONDS.toMillis(5); 646 647 /** The applied data retry rule. */ 648 protected @Nullable DataRetryRule mAppliedDataRetryRule; 649 650 /** 651 * Set the data retry delay. 652 * 653 * @param retryDelayMillis The retry delay in milliseconds. 654 * @return This builder. 655 */ setRetryDelay(long retryDelayMillis)656 public @NonNull T setRetryDelay(long retryDelayMillis) { 657 mRetryDelayMillis = retryDelayMillis; 658 return (T) this; 659 } 660 661 /** 662 * Set the applied retry rule. 663 * 664 * @param dataRetryRule The rule that used for this data retry. 665 * @return This builder. 666 */ setAppliedRetryRule(@onNull DataRetryRule dataRetryRule)667 public @NonNull T setAppliedRetryRule(@NonNull DataRetryRule dataRetryRule) { 668 mAppliedDataRetryRule = dataRetryRule; 669 return (T) this; 670 } 671 } 672 } 673 674 /** 675 * Represent a setup data retry entry. 676 */ 677 public static class DataSetupRetryEntry extends DataRetryEntry { 678 /** 679 * Retry type is unknown. This should be only used for initialized value. 680 */ 681 public static final int RETRY_TYPE_UNKNOWN = 0; 682 /** 683 * To retry setup data with the same data profile. 684 */ 685 public static final int RETRY_TYPE_DATA_PROFILE = 1; 686 687 /** 688 * To retry satisfying the network request(s). Could be using a 689 * different data profile. 690 */ 691 public static final int RETRY_TYPE_NETWORK_REQUESTS = 2; 692 693 @IntDef(prefix = {"RETRY_TYPE_"}, 694 value = { 695 RETRY_TYPE_UNKNOWN, 696 RETRY_TYPE_DATA_PROFILE, 697 RETRY_TYPE_NETWORK_REQUESTS, 698 }) 699 public @interface SetupRetryType {} 700 701 /** Setup retry type. Could be retry by same data profile or same capability. */ 702 public final @SetupRetryType int setupRetryType; 703 704 /** The network requests to satisfy when retry happens. */ 705 public final @NonNull NetworkRequestList networkRequestList; 706 707 /** The data profile that will be used for retry. */ 708 public final @Nullable DataProfile dataProfile; 709 710 /** The transport to retry data setup. */ 711 public final @TransportType int transport; 712 713 /** 714 * Constructor 715 * 716 * @param setupRetryType Data retry type. Could be retry by same data profile or same 717 * capabilities. 718 * @param networkRequestList The network requests to satisfy when retry happens. 719 * @param dataProfile The data profile that will be used for retry. 720 * @param transport The transport to retry data setup. 721 * @param appliedDataSetupRetryRule The applied data setup retry rule. 722 * @param retryDelayMillis The retry delay in milliseconds. 723 */ DataSetupRetryEntry(@etupRetryType int setupRetryType, @Nullable NetworkRequestList networkRequestList, @NonNull DataProfile dataProfile, @TransportType int transport, @Nullable DataSetupRetryRule appliedDataSetupRetryRule, long retryDelayMillis)724 private DataSetupRetryEntry(@SetupRetryType int setupRetryType, 725 @Nullable NetworkRequestList networkRequestList, @NonNull DataProfile dataProfile, 726 @TransportType int transport, 727 @Nullable DataSetupRetryRule appliedDataSetupRetryRule, long retryDelayMillis) { 728 super(appliedDataSetupRetryRule, retryDelayMillis); 729 this.setupRetryType = setupRetryType; 730 this.networkRequestList = networkRequestList; 731 this.dataProfile = dataProfile; 732 this.transport = transport; 733 } 734 735 /** 736 * Convert retry type to string. 737 * 738 * @param setupRetryType Data setup retry type. 739 * @return Retry type in string format. 740 */ retryTypeToString(@etupRetryType int setupRetryType)741 private static String retryTypeToString(@SetupRetryType int setupRetryType) { 742 switch (setupRetryType) { 743 case RETRY_TYPE_DATA_PROFILE: return "BY_PROFILE"; 744 case RETRY_TYPE_NETWORK_REQUESTS: return "BY_NETWORK_REQUESTS"; 745 default: return "Unknown(" + setupRetryType + ")"; 746 } 747 } 748 749 @Override toString()750 public String toString() { 751 return "[DataSetupRetryEntry: delay=" + retryDelayMillis + "ms, retry time:" 752 + DataUtils.elapsedTimeToString(retryElapsedTime) + ", " + dataProfile 753 + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) 754 + ", retry type=" + retryTypeToString(setupRetryType) + ", retry requests=" 755 + networkRequestList + ", applied rule=" + appliedDataRetryRule + ", state=" 756 + retryStateToString(mRetryState) + ", timestamp=" 757 + DataUtils.elapsedTimeToString(mRetryStateTimestamp) + "]"; 758 } 759 760 /** 761 * The builder of {@link DataSetupRetryEntry}. 762 * 763 * @param <T> Type of the builder. 764 */ 765 public static class Builder<T extends Builder<T>> extends DataRetryEntry.Builder<T> { 766 /** Data setup retry type. Could be retry by same data profile or same capabilities. */ 767 private @SetupRetryType int mSetupRetryType = RETRY_TYPE_UNKNOWN; 768 769 /** The network requests to satisfy when retry happens. */ 770 private @NonNull NetworkRequestList mNetworkRequestList; 771 772 /** The data profile that will be used for retry. */ 773 private @Nullable DataProfile mDataProfile; 774 775 /** The transport to retry data setup. */ 776 private @TransportType int mTransport = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; 777 778 /** 779 * Set the data retry type. 780 * 781 * @param setupRetryType Data retry type. Could be retry by same data profile or same 782 * capabilities. 783 * @return This builder. 784 */ setSetupRetryType(@etupRetryType int setupRetryType)785 public @NonNull Builder<T> setSetupRetryType(@SetupRetryType int setupRetryType) { 786 mSetupRetryType = setupRetryType; 787 return this; 788 } 789 790 /** 791 * Set the network capability to satisfy when retry happens. 792 * 793 * @param networkRequestList The network requests to satisfy when retry happens. 794 * @return This builder. 795 */ setNetworkRequestList( @onNull NetworkRequestList networkRequestList)796 public @NonNull Builder<T> setNetworkRequestList( 797 @NonNull NetworkRequestList networkRequestList) { 798 mNetworkRequestList = networkRequestList; 799 return this; 800 } 801 802 /** 803 * Set the data profile that will be used for retry. 804 * 805 * @param dataProfile The data profile that will be used for retry. 806 * @return This builder. 807 */ setDataProfile(@onNull DataProfile dataProfile)808 public @NonNull Builder<T> setDataProfile(@NonNull DataProfile dataProfile) { 809 mDataProfile = dataProfile; 810 return this; 811 } 812 813 /** 814 * Set the transport of the data setup retry. 815 * 816 * @param transport The transport to retry data setup. 817 * @return This builder. 818 */ setTransport(@ransportType int transport)819 public @NonNull Builder<T> setTransport(@TransportType int transport) { 820 mTransport = transport; 821 return this; 822 } 823 824 /** 825 * Build the instance of {@link DataSetupRetryEntry}. 826 * 827 * @return The instance of {@link DataSetupRetryEntry}. 828 */ build()829 public @NonNull DataSetupRetryEntry build() { 830 if (mNetworkRequestList == null) { 831 throw new IllegalArgumentException("network request list is not specified."); 832 } 833 if (mTransport != AccessNetworkConstants.TRANSPORT_TYPE_WWAN 834 && mTransport != AccessNetworkConstants.TRANSPORT_TYPE_WLAN) { 835 throw new IllegalArgumentException("Invalid transport type " + mTransport); 836 } 837 if (mSetupRetryType != RETRY_TYPE_DATA_PROFILE 838 && mSetupRetryType != RETRY_TYPE_NETWORK_REQUESTS) { 839 throw new IllegalArgumentException("Invalid setup retry type " 840 + mSetupRetryType); 841 } 842 return new DataSetupRetryEntry(mSetupRetryType, mNetworkRequestList, mDataProfile, 843 mTransport, (DataSetupRetryRule) mAppliedDataRetryRule, mRetryDelayMillis); 844 } 845 } 846 } 847 848 /** 849 * Represent a data handover retry entry. 850 */ 851 public static class DataHandoverRetryEntry extends DataRetryEntry { 852 /** The data network to be retried for handover. */ 853 public final @NonNull DataNetwork dataNetwork; 854 855 /** 856 * Constructor. 857 * 858 * @param dataNetwork The data network to be retried for handover. 859 * @param appliedDataHandoverRetryRule The applied data retry rule. 860 * @param retryDelayMillis The retry delay in milliseconds. 861 */ DataHandoverRetryEntry(@onNull DataNetwork dataNetwork, @Nullable DataHandoverRetryRule appliedDataHandoverRetryRule, long retryDelayMillis)862 public DataHandoverRetryEntry(@NonNull DataNetwork dataNetwork, 863 @Nullable DataHandoverRetryRule appliedDataHandoverRetryRule, 864 long retryDelayMillis) { 865 super(appliedDataHandoverRetryRule, retryDelayMillis); 866 this.dataNetwork = dataNetwork; 867 } 868 869 @Override toString()870 public String toString() { 871 return "[DataHandoverRetryEntry: delay=" + retryDelayMillis + "ms, retry time:" 872 + DataUtils.elapsedTimeToString(retryElapsedTime) + ", " + dataNetwork 873 + ", applied rule=" + appliedDataRetryRule + ", state=" 874 + retryStateToString(mRetryState) + ", timestamp=" 875 + DataUtils.elapsedTimeToString(mRetryStateTimestamp) + "]"; 876 } 877 878 /** 879 * The builder of {@link DataHandoverRetryEntry}. 880 * 881 * @param <T> Type of the builder. 882 */ 883 public static class Builder<T extends Builder<T>> extends DataRetryEntry.Builder<T> { 884 /** The data network to be retried for handover. */ 885 public @NonNull DataNetwork mDataNetwork; 886 887 /** 888 * Set the data retry type. 889 * 890 * @param dataNetwork The data network to be retried for handover. 891 * 892 * @return This builder. 893 */ setDataNetwork(@onNull DataNetwork dataNetwork)894 public @NonNull Builder<T> setDataNetwork(@NonNull DataNetwork dataNetwork) { 895 mDataNetwork = dataNetwork; 896 return this; 897 } 898 899 /** 900 * Build the instance of {@link DataHandoverRetryEntry}. 901 * 902 * @return The instance of {@link DataHandoverRetryEntry}. 903 */ build()904 public @NonNull DataHandoverRetryEntry build() { 905 return new DataHandoverRetryEntry(mDataNetwork, 906 (DataHandoverRetryRule) mAppliedDataRetryRule, mRetryDelayMillis); 907 } 908 } 909 } 910 911 /** Data retry callback. */ 912 public static class DataRetryManagerCallback extends DataCallback { 913 /** 914 * Constructor 915 * 916 * @param executor The executor of the callback. 917 */ DataRetryManagerCallback(@onNull @allbackExecutor Executor executor)918 public DataRetryManagerCallback(@NonNull @CallbackExecutor Executor executor) { 919 super(executor); 920 } 921 922 /** 923 * Called when data setup retry occurs. 924 * 925 * @param dataSetupRetryEntry The data setup retry entry. 926 */ onDataNetworkSetupRetry(@onNull DataSetupRetryEntry dataSetupRetryEntry)927 public void onDataNetworkSetupRetry(@NonNull DataSetupRetryEntry dataSetupRetryEntry) {} 928 929 /** 930 * Called when data handover retry occurs. 931 * 932 * @param dataHandoverRetryEntry The data handover retry entry. 933 */ onDataNetworkHandoverRetry( @onNull DataHandoverRetryEntry dataHandoverRetryEntry)934 public void onDataNetworkHandoverRetry( 935 @NonNull DataHandoverRetryEntry dataHandoverRetryEntry) {} 936 937 /** 938 * Called when retry manager determines that the retry will no longer be performed on 939 * this data network. 940 * 941 * @param dataNetwork The data network that will never be retried handover. 942 */ onDataNetworkHandoverRetryStopped(@onNull DataNetwork dataNetwork)943 public void onDataNetworkHandoverRetryStopped(@NonNull DataNetwork dataNetwork) {} 944 945 /** 946 * Called when throttle status changed reported from network. 947 * 948 * @param throttleStatusList List of throttle status. 949 */ onThrottleStatusChanged(@onNull List<ThrottleStatus> throttleStatusList)950 public void onThrottleStatusChanged(@NonNull List<ThrottleStatus> throttleStatusList) {} 951 } 952 953 /** 954 * Constructor 955 * 956 * @param phone The phone instance. 957 * @param dataNetworkController Data network controller. 958 * @param looper The looper to be used by the handler. Currently the handler thread is the 959 * phone process's main thread. 960 * @param dataRetryManagerCallback Data retry callback. 961 */ DataRetryManager(@onNull Phone phone, @NonNull DataNetworkController dataNetworkController, @NonNull SparseArray<DataServiceManager> dataServiceManagers, @NonNull Looper looper, @NonNull DataRetryManagerCallback dataRetryManagerCallback)962 public DataRetryManager(@NonNull Phone phone, 963 @NonNull DataNetworkController dataNetworkController, 964 @NonNull SparseArray<DataServiceManager> dataServiceManagers, 965 @NonNull Looper looper, @NonNull DataRetryManagerCallback dataRetryManagerCallback) { 966 super(looper); 967 mPhone = phone; 968 mRil = phone.mCi; 969 mLogTag = "DRM-" + mPhone.getPhoneId(); 970 mDataRetryManagerCallbacks.add(dataRetryManagerCallback); 971 972 mDataServiceManagers = dataServiceManagers; 973 mDataConfigManager = dataNetworkController.getDataConfigManager(); 974 mDataProfileManager = dataNetworkController.getDataProfileManager(); 975 mAlarmManager = mPhone.getContext().getSystemService(AlarmManager.class); 976 977 mDataConfigManager.registerCallback(new DataConfigManagerCallback(this::post) { 978 @Override 979 public void onCarrierConfigChanged() { 980 DataRetryManager.this.onCarrierConfigUpdated(); 981 } 982 }); 983 984 for (int transport : mPhone.getAccessNetworksManager().getAvailableTransports()) { 985 mDataServiceManagers.get(transport) 986 .registerForApnUnthrottled(this, EVENT_DATA_PROFILE_UNTHROTTLED); 987 } 988 mDataProfileManager.registerCallback(new DataProfileManagerCallback(this::post) { 989 @Override 990 public void onDataProfilesChanged() { 991 onReset(RESET_REASON_DATA_PROFILES_CHANGED); 992 } 993 }); 994 dataNetworkController.registerDataNetworkControllerCallback( 995 new DataNetworkControllerCallback(this::post) { 996 /** 997 * Called when data service is bound. 998 * 999 * @param transport The transport of the data service. 1000 */ 1001 @Override 1002 public void onDataServiceBound(@TransportType int transport) { 1003 onReset(RESET_REASON_DATA_SERVICE_BOUND); 1004 } 1005 1006 /** 1007 * Called when data network is connected. 1008 * 1009 * @param transport Transport for the connected network. 1010 * @param dataProfile The data profile of the connected data network. 1011 */ 1012 @Override 1013 public void onDataNetworkConnected(@TransportType int transport, 1014 @NonNull DataProfile dataProfile) { 1015 DataRetryManager.this.onDataNetworkConnected(transport, dataProfile); 1016 } 1017 }); 1018 mRil.registerForOn(this, EVENT_RADIO_ON, null); 1019 mRil.registerForModemReset(this, EVENT_MODEM_RESET, null); 1020 1021 // Register intent of alarm manager for long retry timer 1022 IntentFilter intentFilter = new IntentFilter(); 1023 intentFilter.addAction(ACTION_RETRY); 1024 mPhone.getContext().registerReceiver(new BroadcastReceiver() { 1025 @Override 1026 public void onReceive(Context context, Intent intent) { 1027 if (ACTION_RETRY.equals(intent.getAction())) { 1028 DataRetryManager.this.onAlarmIntentRetry( 1029 intent.getIntExtra(ACTION_RETRY_EXTRA_HASHCODE, -1 /*Bad hashcode*/)); 1030 } 1031 } 1032 }, intentFilter); 1033 1034 if (mDataConfigManager.shouldResetDataThrottlingWhenTacChanges()) { 1035 mPhone.getServiceStateTracker().registerForAreaCodeChanged(this, EVENT_TAC_CHANGED, 1036 null); 1037 } 1038 } 1039 1040 @Override handleMessage(Message msg)1041 public void handleMessage(Message msg) { 1042 AsyncResult ar; 1043 switch (msg.what) { 1044 case EVENT_DATA_SETUP_RETRY: 1045 DataSetupRetryEntry dataSetupRetryEntry = (DataSetupRetryEntry) msg.obj; 1046 if (!isRetryCancelled(dataSetupRetryEntry)) { 1047 mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( 1048 () -> callback.onDataNetworkSetupRetry(dataSetupRetryEntry))); 1049 } 1050 break; 1051 case EVENT_DATA_HANDOVER_RETRY: 1052 DataHandoverRetryEntry dataHandoverRetryEntry = (DataHandoverRetryEntry) msg.obj; 1053 if (!isRetryCancelled(dataHandoverRetryEntry)) { 1054 mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( 1055 () -> callback.onDataNetworkHandoverRetry(dataHandoverRetryEntry))); 1056 } 1057 break; 1058 case EVENT_RADIO_ON: 1059 onReset(RESET_REASON_RADIO_ON); 1060 break; 1061 case EVENT_MODEM_RESET: 1062 onReset(RESET_REASON_MODEM_RESTART); 1063 break; 1064 case EVENT_TAC_CHANGED: 1065 onReset(RESET_REASON_TAC_CHANGED); 1066 break; 1067 case EVENT_DATA_PROFILE_UNTHROTTLED: 1068 ar = (AsyncResult) msg.obj; 1069 int transport = (int) ar.userObj; 1070 String apn = null; 1071 DataProfile dataProfile = null; 1072 // 1.6 or older HAL 1073 if (ar.result instanceof String) { 1074 apn = (String) ar.result; 1075 } else if (ar.result instanceof DataProfile) { 1076 dataProfile = (DataProfile) ar.result; 1077 } 1078 onDataProfileUnthrottled(dataProfile, apn, transport, true, true); 1079 break; 1080 case EVENT_CANCEL_PENDING_HANDOVER_RETRY: 1081 onCancelPendingHandoverRetry((DataNetwork) msg.obj); 1082 break; 1083 default: 1084 loge("Unexpected message " + msg.what); 1085 } 1086 } 1087 1088 /** 1089 * @param retryEntry The retry entry to check. 1090 * @return {@code true} if the retry is null or not in RETRY_STATE_NOT_RETRIED state. 1091 */ isRetryCancelled(@ullable DataRetryEntry retryEntry)1092 private boolean isRetryCancelled(@Nullable DataRetryEntry retryEntry) { 1093 if (retryEntry != null && retryEntry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) { 1094 return false; 1095 } 1096 log("Retry was removed earlier. " + retryEntry); 1097 return true; 1098 } 1099 1100 /** 1101 * Called when carrier config is updated. 1102 */ onCarrierConfigUpdated()1103 private void onCarrierConfigUpdated() { 1104 onReset(RESET_REASON_DATA_CONFIG_CHANGED); 1105 mDataSetupRetryRuleList = mDataConfigManager.getDataSetupRetryRules(); 1106 mDataHandoverRetryRuleList = mDataConfigManager.getDataHandoverRetryRules(); 1107 log("onDataConfigUpdated: mDataSetupRetryRuleList=" + mDataSetupRetryRuleList 1108 + ", mDataHandoverRetryRuleList=" + mDataHandoverRetryRuleList); 1109 } 1110 1111 /** 1112 * Called when data network is connected. 1113 * 1114 * @param transport Transport for the connected network. 1115 * @param dataProfile The data profile of the connected data network. 1116 */ onDataNetworkConnected(@ransportType int transport, @NonNull DataProfile dataProfile)1117 public void onDataNetworkConnected(@TransportType int transport, 1118 @NonNull DataProfile dataProfile) { 1119 if (dataProfile.getApnSetting() != null) { 1120 dataProfile.getApnSetting().setPermanentFailed(false); 1121 } 1122 1123 onDataProfileUnthrottled(dataProfile, null, transport, true, false); 1124 } 1125 1126 /** 1127 * Evaluate if data setup retry is needed or not. If needed, retry will be scheduled 1128 * automatically after evaluation. 1129 * 1130 * @param dataProfile The data profile that has been used in the previous data network setup. 1131 * @param transport The transport to retry data setup. 1132 * @param requestList The network requests attached to the previous data network setup. 1133 * @param cause The fail cause of previous data network setup. 1134 * @param retryDelayMillis The retry delay in milliseconds suggested by the network/data 1135 * service. {@link android.telephony.data.DataCallResponse#RETRY_DURATION_UNDEFINED} 1136 * indicates network/data service did not suggest retry or not. Telephony frameworks would use 1137 * its logic to perform data retry. 1138 */ evaluateDataSetupRetry(@onNull DataProfile dataProfile, @TransportType int transport, @NonNull NetworkRequestList requestList, @DataFailureCause int cause, long retryDelayMillis)1139 public void evaluateDataSetupRetry(@NonNull DataProfile dataProfile, 1140 @TransportType int transport, @NonNull NetworkRequestList requestList, 1141 @DataFailureCause int cause, long retryDelayMillis) { 1142 post(() -> onEvaluateDataSetupRetry(dataProfile, transport, requestList, cause, 1143 retryDelayMillis)); 1144 } 1145 onEvaluateDataSetupRetry(@onNull DataProfile dataProfile, @TransportType int transport, @NonNull NetworkRequestList requestList, @DataFailureCause int cause, long retryDelayMillis)1146 private void onEvaluateDataSetupRetry(@NonNull DataProfile dataProfile, 1147 @TransportType int transport, @NonNull NetworkRequestList requestList, 1148 @DataFailureCause int cause, long retryDelayMillis) { 1149 logl("onEvaluateDataSetupRetry: " + dataProfile + ", transport=" 1150 + AccessNetworkConstants.transportTypeToString(transport) + ", cause=" 1151 + DataFailCause.toString(cause) + ", retryDelayMillis=" + retryDelayMillis + "ms" 1152 + ", " + requestList); 1153 // Check if network suggested never retry for this data profile. Note that for HAL 1.5 1154 // and older, Integer.MAX_VALUE indicates never retry. For 1.6 or above, Long.MAX_VALUE 1155 // indicates never retry. 1156 if (retryDelayMillis == Long.MAX_VALUE || retryDelayMillis == Integer.MAX_VALUE) { 1157 logl("Network suggested never retry for " + dataProfile); 1158 // Note that RETRY_TYPE_NEW_CONNECTION is intended here because 1159 // when unthrottling happens, we still want to retry and we'll need 1160 // a type there so we know what to retry. Using RETRY_TYPE_NONE 1161 // ThrottleStatus is just for API backwards compatibility reason. 1162 updateThrottleStatus(dataProfile, requestList, null, 1163 ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, Long.MAX_VALUE); 1164 return; 1165 } else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) { 1166 // Network specifically asks retry the previous data profile again. 1167 DataSetupRetryEntry dataSetupRetryEntry = new DataSetupRetryEntry.Builder<>() 1168 .setRetryDelay(retryDelayMillis) 1169 .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_DATA_PROFILE) 1170 .setNetworkRequestList(requestList) 1171 .setDataProfile(dataProfile) 1172 .setTransport(transport) 1173 .build(); 1174 updateThrottleStatus(dataProfile, requestList, null, 1175 ThrottleStatus.RETRY_TYPE_NEW_CONNECTION, transport, 1176 dataSetupRetryEntry.retryElapsedTime); 1177 schedule(dataSetupRetryEntry); 1178 return; 1179 } 1180 1181 // Network did not suggest any retry. Use the configured rules to perform retry. 1182 logv("mDataSetupRetryRuleList=" + mDataSetupRetryRuleList); 1183 1184 boolean retryScheduled = false; 1185 List<NetworkRequestList> groupedNetworkRequestLists = 1186 DataUtils.getGroupedNetworkRequestList(requestList); 1187 for (DataSetupRetryRule retryRule : mDataSetupRetryRuleList) { 1188 if (retryRule.isPermanentFailCauseRule() && retryRule.getFailCauses().contains(cause)) { 1189 if (dataProfile.getApnSetting() != null) { 1190 dataProfile.getApnSetting().setPermanentFailed(true); 1191 1192 // It seems strange to have retry timer in permanent failure rule, but since 1193 // in this case permanent failure is only applicable to the failed profile, so 1194 // we need to see if other profile can be selected for next data setup. 1195 log("Marked " + dataProfile.getApnSetting().getApnName() + " permanently " 1196 + "failed, but still schedule retry to see if another data profile " 1197 + "can be used for setup data."); 1198 // Schedule a data retry to see if another data profile could be selected. 1199 // If the same data profile is selected again, since it's marked as 1200 // permanent failure, it won't be used for setup data call. 1201 schedule(new DataSetupRetryEntry.Builder<>() 1202 .setRetryDelay(retryRule.getRetryIntervalsMillis().get(0)) 1203 .setAppliedRetryRule(retryRule) 1204 .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) 1205 .setTransport(transport) 1206 .setNetworkRequestList(requestList) 1207 .build()); 1208 } else { 1209 // For TD-based data profile, do not do anything for now. Should expand this in 1210 // the future if needed. 1211 log("Stopped timer-based retry for TD-based data profile. Will retry only when " 1212 + "environment changes."); 1213 } 1214 return; 1215 } 1216 for (NetworkRequestList networkRequestList : groupedNetworkRequestLists) { 1217 int capability = networkRequestList.get(0).getApnTypeNetworkCapability(); 1218 if (retryRule.canBeMatched(capability, cause)) { 1219 // Check if there is already a similar network request retry scheduled. 1220 if (isSimilarNetworkRequestRetryScheduled( 1221 networkRequestList.get(0), transport)) { 1222 log(networkRequestList.get(0) + " already had similar retry " 1223 + "scheduled."); 1224 return; 1225 } 1226 1227 int failedCount = getRetryFailedCount(capability, retryRule, transport); 1228 log("For capability " + DataUtils.networkCapabilityToString(capability) 1229 + ", found matching rule " + retryRule + ", failed count=" 1230 + failedCount); 1231 if (failedCount == retryRule.getMaxRetries()) { 1232 log("Data retry failed for " + failedCount + " times on " 1233 + AccessNetworkConstants.transportTypeToString(transport) 1234 + ". Stopped timer-based data retry for " 1235 + DataUtils.networkCapabilityToString(capability) 1236 + ". Condition-based retry will still happen when condition " 1237 + "changes."); 1238 return; 1239 } 1240 1241 retryDelayMillis = retryRule.getRetryIntervalsMillis().get( 1242 Math.min(failedCount, retryRule 1243 .getRetryIntervalsMillis().size() - 1)); 1244 1245 // Schedule a data retry. 1246 schedule(new DataSetupRetryEntry.Builder<>() 1247 .setRetryDelay(retryDelayMillis) 1248 .setAppliedRetryRule(retryRule) 1249 .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS) 1250 .setTransport(transport) 1251 .setNetworkRequestList(networkRequestList) 1252 .build()); 1253 retryScheduled = true; 1254 break; 1255 } 1256 } 1257 } 1258 1259 if (!retryScheduled) { 1260 log("onEvaluateDataSetupRetry: Did not match any retry rule. Stop timer-based " 1261 + "retry."); 1262 } 1263 } 1264 1265 /** 1266 * Evaluate if data handover retry is needed or not. If needed, retry will be scheduled 1267 * automatically after evaluation. 1268 * 1269 * @param dataNetwork The data network to be retried for handover. 1270 * @param cause The fail cause of previous data network handover. 1271 * @param retryDelayMillis The retry delay in milliseconds suggested by the network/data 1272 * service. {@link android.telephony.data.DataCallResponse#RETRY_DURATION_UNDEFINED} 1273 * indicates network/data service did not suggest retry or not. Telephony frameworks would use 1274 * its logic to perform handover retry. 1275 */ evaluateDataHandoverRetry(@onNull DataNetwork dataNetwork, @DataFailureCause int cause, long retryDelayMillis)1276 public void evaluateDataHandoverRetry(@NonNull DataNetwork dataNetwork, 1277 @DataFailureCause int cause, long retryDelayMillis) { 1278 post(() -> onEvaluateDataHandoverRetry(dataNetwork, cause, retryDelayMillis)); 1279 } 1280 onEvaluateDataHandoverRetry(@onNull DataNetwork dataNetwork, @DataFailureCause int cause, long retryDelayMillis)1281 private void onEvaluateDataHandoverRetry(@NonNull DataNetwork dataNetwork, 1282 @DataFailureCause int cause, long retryDelayMillis) { 1283 logl("onEvaluateDataHandoverRetry: " + dataNetwork + ", cause=" 1284 + DataFailCause.toString(cause) + ", retryDelayMillis=" + retryDelayMillis + "ms"); 1285 int targetTransport = DataUtils.getTargetTransport(dataNetwork.getTransport()); 1286 if (retryDelayMillis == Long.MAX_VALUE || retryDelayMillis == Integer.MAX_VALUE) { 1287 logl("Network suggested never retry handover for " + dataNetwork); 1288 // Note that RETRY_TYPE_HANDOVER is intended here because 1289 // when unthrottling happens, we still want to retry and we'll need 1290 // a type there so we know what to retry. Using RETRY_TYPE_NONE 1291 // ThrottleStatus is just for API backwards compatibility reason. 1292 updateThrottleStatus(dataNetwork.getDataProfile(), 1293 dataNetwork.getAttachedNetworkRequestList(), dataNetwork, 1294 ThrottleStatus.RETRY_TYPE_HANDOVER, targetTransport, Long.MAX_VALUE); 1295 } else if (retryDelayMillis != DataCallResponse.RETRY_DURATION_UNDEFINED) { 1296 // Network specifically asks retry the previous data profile again. 1297 DataHandoverRetryEntry dataHandoverRetryEntry = new DataHandoverRetryEntry.Builder<>() 1298 .setRetryDelay(retryDelayMillis) 1299 .setDataNetwork(dataNetwork) 1300 .build(); 1301 1302 updateThrottleStatus(dataNetwork.getDataProfile(), 1303 dataNetwork.getAttachedNetworkRequestList(), dataNetwork, 1304 ThrottleStatus.RETRY_TYPE_HANDOVER, targetTransport, 1305 dataHandoverRetryEntry.retryElapsedTime); 1306 schedule(dataHandoverRetryEntry); 1307 } else { 1308 // Network did not suggest any retry. Use the configured rules to perform retry. 1309 1310 // Matching the rule in configured order. 1311 for (DataHandoverRetryRule retryRule : mDataHandoverRetryRuleList) { 1312 if (retryRule.getFailCauses().isEmpty() 1313 || retryRule.getFailCauses().contains(cause)) { 1314 int failedCount = getRetryFailedCount(dataNetwork, retryRule); 1315 log("Found matching rule " + retryRule + ", failed count=" + failedCount); 1316 if (failedCount == retryRule.getMaxRetries()) { 1317 log("Data handover retry failed for " + failedCount + " times. Stopped " 1318 + "handover retry."); 1319 mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( 1320 () -> callback.onDataNetworkHandoverRetryStopped(dataNetwork))); 1321 return; 1322 } 1323 1324 retryDelayMillis = retryRule.getRetryIntervalsMillis().get( 1325 Math.min(failedCount, retryRule 1326 .getRetryIntervalsMillis().size() - 1)); 1327 schedule(new DataHandoverRetryEntry.Builder<>() 1328 .setRetryDelay(retryDelayMillis) 1329 .setDataNetwork(dataNetwork) 1330 .setAppliedRetryRule(retryRule) 1331 .build()); 1332 } 1333 } 1334 } 1335 } 1336 1337 /** 1338 * @param dataNetwork The data network to check. 1339 * @return {@code true} if the data network had failed the maximum number of attempts for 1340 * handover according to any retry rules. 1341 */ isDataNetworkHandoverRetryStopped(@onNull DataNetwork dataNetwork)1342 public boolean isDataNetworkHandoverRetryStopped(@NonNull DataNetwork dataNetwork) { 1343 // Matching the rule in configured order. 1344 for (DataHandoverRetryRule retryRule : mDataHandoverRetryRuleList) { 1345 int failedCount = getRetryFailedCount(dataNetwork, retryRule); 1346 if (failedCount == retryRule.getMaxRetries()) { 1347 log("Data handover retry failed for " + failedCount + " times. Stopped " 1348 + "handover retry."); 1349 return true; 1350 } 1351 } 1352 return false; 1353 } 1354 1355 /** Cancel all retries and throttling entries. */ onReset(@etryResetReason int reason)1356 private void onReset(@RetryResetReason int reason) { 1357 logl("Remove all retry and throttling entries, reason=" + resetReasonToString(reason)); 1358 removeMessages(EVENT_DATA_SETUP_RETRY); 1359 removeMessages(EVENT_DATA_HANDOVER_RETRY); 1360 mDataRetryEntries.stream() 1361 .filter(entry -> entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) 1362 .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED)); 1363 1364 for (DataThrottlingEntry dataThrottlingEntry : mDataThrottlingEntries) { 1365 DataProfile dataProfile = dataThrottlingEntry.dataProfile; 1366 String apn = dataProfile.getApnSetting() != null 1367 ? dataProfile.getApnSetting().getApnName() : null; 1368 onDataProfileUnthrottled(dataProfile, apn, dataThrottlingEntry.transport, false, true); 1369 } 1370 1371 mDataThrottlingEntries.clear(); 1372 } 1373 1374 /** 1375 * Count how many times the same setup retry rule has been used for this data network but 1376 * failed. 1377 * 1378 * @param dataNetwork The data network to check. 1379 * @param dataRetryRule The data retry rule. 1380 * @return The failed count since last successful data setup. 1381 */ getRetryFailedCount(@onNull DataNetwork dataNetwork, @NonNull DataHandoverRetryRule dataRetryRule)1382 private int getRetryFailedCount(@NonNull DataNetwork dataNetwork, 1383 @NonNull DataHandoverRetryRule dataRetryRule) { 1384 int count = 0; 1385 for (int i = mDataRetryEntries.size() - 1; i >= 0; i--) { 1386 if (mDataRetryEntries.get(i) instanceof DataHandoverRetryEntry) { 1387 DataHandoverRetryEntry entry = (DataHandoverRetryEntry) mDataRetryEntries.get(i); 1388 if (entry.dataNetwork == dataNetwork 1389 && dataRetryRule.equals(entry.appliedDataRetryRule)) { 1390 if (entry.getState() == DataRetryEntry.RETRY_STATE_SUCCEEDED 1391 || entry.getState() == DataRetryEntry.RETRY_STATE_CANCELLED) { 1392 break; 1393 } 1394 count++; 1395 } 1396 } 1397 } 1398 return count; 1399 } 1400 1401 /** 1402 * Count how many times the same setup retry rule has been used for the capability since 1403 * last success data setup. 1404 * 1405 * @param networkCapability The network capability to check. 1406 * @param dataRetryRule The data retry rule. 1407 * @param transport The transport on which setup failure has occurred. 1408 * @return The failed count since last successful data setup. 1409 */ getRetryFailedCount(@etCapability int networkCapability, @NonNull DataSetupRetryRule dataRetryRule, @TransportType int transport)1410 private int getRetryFailedCount(@NetCapability int networkCapability, 1411 @NonNull DataSetupRetryRule dataRetryRule, @TransportType int transport) { 1412 int count = 0; 1413 for (int i = mDataRetryEntries.size() - 1; i >= 0; i--) { 1414 if (mDataRetryEntries.get(i) instanceof DataSetupRetryEntry) { 1415 DataSetupRetryEntry entry = (DataSetupRetryEntry) mDataRetryEntries.get(i); 1416 // count towards the last succeeded data setup. 1417 if (entry.setupRetryType == DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS 1418 && entry.transport == transport) { 1419 if (entry.networkRequestList.isEmpty()) { 1420 String msg = "Invalid data retry entry detected"; 1421 logl(msg); 1422 loge("mDataRetryEntries=" + mDataRetryEntries); 1423 AnomalyReporter.reportAnomaly( 1424 UUID.fromString("afeab78c-c0b0-49fc-a51f-f766814d7aa6"), 1425 msg, 1426 mPhone.getCarrierId()); 1427 continue; 1428 } 1429 if (entry.networkRequestList.get(0).getApnTypeNetworkCapability() 1430 == networkCapability 1431 && entry.appliedDataRetryRule.equals(dataRetryRule)) { 1432 if (entry.getState() == DataRetryEntry.RETRY_STATE_SUCCEEDED 1433 || entry.getState() == DataRetryEntry.RETRY_STATE_CANCELLED) { 1434 break; 1435 } 1436 count++; 1437 } 1438 } 1439 } 1440 } 1441 return count; 1442 } 1443 1444 /** 1445 * Schedule the data retry. 1446 * 1447 * @param dataRetryEntry The data retry entry. 1448 */ schedule(@onNull DataRetryEntry dataRetryEntry)1449 private void schedule(@NonNull DataRetryEntry dataRetryEntry) { 1450 logl("Scheduled data retry " + dataRetryEntry 1451 + " hashcode=" + dataRetryEntry.hashCode()); 1452 mDataRetryEntries.add(dataRetryEntry); 1453 if (mDataRetryEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { 1454 // Discard the oldest retry entry. 1455 mDataRetryEntries.remove(0); 1456 } 1457 1458 // When the device is in doze mode, the handler message might be extremely delayed because 1459 // handler uses relative system time(not counting sleep) which is inaccurate even when we 1460 // enter the maintenance window. 1461 // Therefore, we use alarm manager when we need to schedule long timers. 1462 if (dataRetryEntry.retryDelayMillis <= RETRY_LONG_DELAY_TIMER_THRESHOLD_MILLIS) { 1463 sendMessageDelayed(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry 1464 ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry), 1465 dataRetryEntry.retryDelayMillis); 1466 } else { 1467 Intent intent = new Intent(ACTION_RETRY); 1468 intent.putExtra(ACTION_RETRY_EXTRA_HASHCODE, dataRetryEntry.hashCode()); 1469 // No need to wake up the device, the retry can wait util next time the device wake up 1470 // to save power. 1471 mAlarmManager.setExactAndAllowWhileIdle(AlarmManager.ELAPSED_REALTIME, 1472 dataRetryEntry.retryElapsedTime, 1473 PendingIntent.getBroadcast(mPhone.getContext(), 1474 dataRetryEntry.hashCode() /*Unique identifier of this retry attempt*/, 1475 intent, 1476 PendingIntent.FLAG_IMMUTABLE)); 1477 } 1478 } 1479 1480 /** 1481 * Called when it's time to retry scheduled by Alarm Manager. 1482 * @param retryHashcode The hashcode is the unique identifier of which retry entry to retry. 1483 */ onAlarmIntentRetry(int retryHashcode)1484 private void onAlarmIntentRetry(int retryHashcode) { 1485 DataRetryEntry dataRetryEntry = mDataRetryEntries.stream() 1486 .filter(entry -> entry.hashCode() == retryHashcode) 1487 .findAny() 1488 .orElse(null); 1489 logl("onAlarmIntentRetry: found " + dataRetryEntry + " with hashcode " + retryHashcode); 1490 if (dataRetryEntry != null) { 1491 sendMessage(obtainMessage(dataRetryEntry instanceof DataSetupRetryEntry 1492 ? EVENT_DATA_SETUP_RETRY : EVENT_DATA_HANDOVER_RETRY, dataRetryEntry)); 1493 } 1494 } 1495 1496 /** 1497 * Add the latest throttling request and report it to the clients. 1498 * 1499 * @param dataProfile The data profile that is being throttled for setup/handover retry. 1500 * @param networkRequestList The associated network request list when throttling happened. 1501 * Can be {@code null} when retry type is {@link ThrottleStatus#RETRY_TYPE_HANDOVER}. 1502 * @param dataNetwork The data network that is being throttled for handover retry. 1503 * Must be {@code null} when retryType is 1504 * {@link ThrottleStatus#RETRY_TYPE_NEW_CONNECTION}. 1505 * @param retryType The retry type when throttling expires. 1506 * @param transport The transport that the data profile has been throttled on. 1507 * @param expirationTime The expiration time of data throttling. This is the time retrieved from 1508 * {@link SystemClock#elapsedRealtime()}. 1509 */ updateThrottleStatus(@onNull DataProfile dataProfile, @Nullable NetworkRequestList networkRequestList, @Nullable DataNetwork dataNetwork, @RetryType int retryType, @TransportType int transport, @ElapsedRealtimeLong long expirationTime)1510 private void updateThrottleStatus(@NonNull DataProfile dataProfile, 1511 @Nullable NetworkRequestList networkRequestList, 1512 @Nullable DataNetwork dataNetwork, @RetryType int retryType, 1513 @TransportType int transport, @ElapsedRealtimeLong long expirationTime) { 1514 DataThrottlingEntry entry = new DataThrottlingEntry(dataProfile, networkRequestList, 1515 dataNetwork, transport, retryType, expirationTime); 1516 // Remove previous entry that contains the same data profile. Therefore it should always 1517 // contain at maximum all the distinct data profiles of the current subscription. 1518 mDataThrottlingEntries.removeIf( 1519 throttlingEntry -> dataProfile.equals(throttlingEntry.dataProfile)); 1520 1521 if (mDataThrottlingEntries.size() >= MAXIMUM_HISTORICAL_ENTRIES) { 1522 // If we don't see the anomaly report after U release, we should remove this check for 1523 // the commented reason above. 1524 AnomalyReporter.reportAnomaly( 1525 UUID.fromString("24fd4d46-1d0f-4b13-b7d6-7bad70b8289b"), 1526 "DataRetryManager throttling more than 100 data profiles", 1527 mPhone.getCarrierId()); 1528 mDataThrottlingEntries.remove(0); 1529 } 1530 logl("Add throttling entry " + entry); 1531 mDataThrottlingEntries.add(entry); 1532 1533 // For backwards compatibility, we use RETRY_TYPE_NONE if network suggests never retry. 1534 final int dataRetryType = expirationTime == Long.MAX_VALUE 1535 ? ThrottleStatus.RETRY_TYPE_NONE : retryType; 1536 1537 // Report to the clients. 1538 final List<ThrottleStatus> throttleStatusList = new ArrayList<>(); 1539 if (dataProfile.getApnSetting() != null) { 1540 throttleStatusList.addAll(dataProfile.getApnSetting().getApnTypes().stream() 1541 .map(apnType -> new ThrottleStatus.Builder() 1542 .setApnType(apnType) 1543 .setRetryType(dataRetryType) 1544 .setSlotIndex(mPhone.getPhoneId()) 1545 .setThrottleExpiryTimeMillis(expirationTime) 1546 .setTransportType(transport) 1547 .build()) 1548 .collect(Collectors.toList())); 1549 } 1550 1551 mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( 1552 () -> callback.onThrottleStatusChanged(throttleStatusList))); 1553 } 1554 1555 /** 1556 * Called when network/modem informed to cancelling the previous throttling request. 1557 * 1558 * @param dataProfile The data profile to be unthrottled. Note this is only supported on HAL 1559 * with AIDL interface. When this is set, {@code apn} must be {@code null}. 1560 * @param apn The apn to be unthrottled. Note this should be only used for HIDL 1.6 or below. 1561 * When this is set, {@code dataProfile} must be {@code null}. 1562 * @param transport The transport that this unthrottling request is on. 1563 * @param remove Whether to remove unthrottled entries from the list of entries. 1564 * @param retry Whether schedule retry after unthrottling. 1565 */ onDataProfileUnthrottled(@ullable DataProfile dataProfile, @Nullable String apn, @TransportType int transport, boolean remove, boolean retry)1566 private void onDataProfileUnthrottled(@Nullable DataProfile dataProfile, @Nullable String apn, 1567 @TransportType int transport, boolean remove, boolean retry) { 1568 log("onDataProfileUnthrottled: dataProfile=" + dataProfile + ", apn=" + apn 1569 + ", transport=" + AccessNetworkConstants.transportTypeToString(transport) 1570 + ", remove=" + remove); 1571 1572 long now = SystemClock.elapsedRealtime(); 1573 List<DataThrottlingEntry> dataUnthrottlingEntries = new ArrayList<>(); 1574 if (dataProfile != null) { 1575 // For AIDL-based HAL. There should be only one entry containing this data profile. 1576 // Note that the data profile reconstructed from DataProfileInfo.aidl will not be 1577 // equal to the data profiles kept in data profile manager (due to some fields missing 1578 // in DataProfileInfo.aidl), so we need to get the equivalent data profile from data 1579 // profile manager. 1580 Stream<DataThrottlingEntry> stream = mDataThrottlingEntries.stream(); 1581 stream = stream.filter(entry -> entry.expirationTimeMillis > now); 1582 if (dataProfile.getApnSetting() != null) { 1583 stream = stream 1584 .filter(entry -> entry.dataProfile.getApnSetting() != null) 1585 .filter(entry -> entry.dataProfile.getApnSetting().getApnName() 1586 .equals(dataProfile.getApnSetting().getApnName())); 1587 } 1588 stream = stream.filter(entry -> Objects.equals(entry.dataProfile.getTrafficDescriptor(), 1589 dataProfile.getTrafficDescriptor())); 1590 1591 dataUnthrottlingEntries = stream.collect(Collectors.toList()); 1592 } else if (apn != null) { 1593 // For HIDL 1.6 or below 1594 dataUnthrottlingEntries = mDataThrottlingEntries.stream() 1595 .filter(entry -> entry.expirationTimeMillis > now 1596 && entry.dataProfile.getApnSetting() != null 1597 && apn.equals(entry.dataProfile.getApnSetting().getApnName()) 1598 && entry.transport == transport) 1599 .collect(Collectors.toList()); 1600 } 1601 1602 if (dataUnthrottlingEntries.isEmpty()) { 1603 log("onDataProfileUnthrottled: Nothing to unthrottle."); 1604 return; 1605 } 1606 1607 // Report to the clients. 1608 final List<ThrottleStatus> throttleStatusList = new ArrayList<>(); 1609 DataProfile unthrottledProfile = null; 1610 int retryType = ThrottleStatus.RETRY_TYPE_NONE; 1611 if (dataUnthrottlingEntries.get(0).retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { 1612 unthrottledProfile = dataUnthrottlingEntries.get(0).dataProfile; 1613 retryType = ThrottleStatus.RETRY_TYPE_NEW_CONNECTION; 1614 } else if (dataUnthrottlingEntries.get(0).retryType == ThrottleStatus.RETRY_TYPE_HANDOVER) { 1615 unthrottledProfile = dataUnthrottlingEntries.get(0).dataNetwork.getDataProfile(); 1616 retryType = ThrottleStatus.RETRY_TYPE_HANDOVER; 1617 } 1618 1619 // Make it final so it can be used in the lambda function below. 1620 final int dataRetryType = retryType; 1621 1622 if (unthrottledProfile != null && unthrottledProfile.getApnSetting() != null) { 1623 unthrottledProfile.getApnSetting().setPermanentFailed(false); 1624 throttleStatusList.addAll(unthrottledProfile.getApnSetting().getApnTypes().stream() 1625 .map(apnType -> new ThrottleStatus.Builder() 1626 .setApnType(apnType) 1627 .setSlotIndex(mPhone.getPhoneId()) 1628 .setNoThrottle() 1629 .setRetryType(dataRetryType) 1630 .setTransportType(transport) 1631 .build()) 1632 .collect(Collectors.toList())); 1633 } 1634 1635 mDataRetryManagerCallbacks.forEach(callback -> callback.invokeFromExecutor( 1636 () -> callback.onThrottleStatusChanged(throttleStatusList))); 1637 1638 if (unthrottledProfile != null) { 1639 // cancel pending retries since we will soon schedule an immediate retry 1640 cancelRetriesForDataProfile(unthrottledProfile, transport); 1641 } 1642 1643 logl("onDataProfileUnthrottled: Removing the following throttling entries. " 1644 + dataUnthrottlingEntries); 1645 if (retry) { 1646 for (DataThrottlingEntry entry : dataUnthrottlingEntries) { 1647 // Immediately retry after unthrottling. 1648 if (entry.retryType == ThrottleStatus.RETRY_TYPE_NEW_CONNECTION) { 1649 schedule(new DataSetupRetryEntry.Builder<>() 1650 .setDataProfile(entry.dataProfile) 1651 .setTransport(entry.transport) 1652 .setSetupRetryType(DataSetupRetryEntry.RETRY_TYPE_DATA_PROFILE) 1653 .setNetworkRequestList(entry.networkRequestList) 1654 .setRetryDelay(0) 1655 .build()); 1656 } else if (entry.retryType == ThrottleStatus.RETRY_TYPE_HANDOVER) { 1657 schedule(new DataHandoverRetryEntry.Builder<>() 1658 .setDataNetwork(entry.dataNetwork) 1659 .setRetryDelay(0) 1660 .build()); 1661 } 1662 } 1663 } 1664 if (remove) { 1665 mDataThrottlingEntries.removeAll(dataUnthrottlingEntries); 1666 } 1667 } 1668 1669 /** 1670 * Cancel pending retries that uses the specified data profile, with specified target transport. 1671 * 1672 * @param dataProfile The data profile to cancel. 1673 * @param transport The target {@link TransportType} on which the retry to cancel. 1674 */ cancelRetriesForDataProfile(@onNull DataProfile dataProfile, @TransportType int transport)1675 private void cancelRetriesForDataProfile(@NonNull DataProfile dataProfile, 1676 @TransportType int transport) { 1677 logl("cancelRetriesForDataProfile: Canceling pending retries for " + dataProfile); 1678 mDataRetryEntries.stream() 1679 .filter(entry -> { 1680 if (entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) { 1681 if (entry instanceof DataSetupRetryEntry) { 1682 DataSetupRetryEntry retryEntry = (DataSetupRetryEntry) entry; 1683 return dataProfile.equals(retryEntry.dataProfile) 1684 && transport == retryEntry.transport; 1685 } else if (entry instanceof DataHandoverRetryEntry) { 1686 DataHandoverRetryEntry retryEntry = (DataHandoverRetryEntry) entry; 1687 return dataProfile.equals(retryEntry.dataNetwork.getDataProfile()); 1688 } 1689 } 1690 return false; 1691 }) 1692 .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED)); 1693 } 1694 1695 1696 1697 /** 1698 * Check if there is any similar network request scheduled to retry. The definition of similar 1699 * is that network requests have same APN capability and on the same transport. 1700 * 1701 * @param networkRequest The network request to check. 1702 * @param transport The transport that this request is on. 1703 * @return {@code true} if similar network request scheduled to retry. 1704 */ isSimilarNetworkRequestRetryScheduled( @onNull TelephonyNetworkRequest networkRequest, @TransportType int transport)1705 public boolean isSimilarNetworkRequestRetryScheduled( 1706 @NonNull TelephonyNetworkRequest networkRequest, @TransportType int transport) { 1707 long now = SystemClock.elapsedRealtime(); 1708 for (int i = mDataRetryEntries.size() - 1; i >= 0; i--) { 1709 if (mDataRetryEntries.get(i) instanceof DataSetupRetryEntry) { 1710 DataSetupRetryEntry entry = (DataSetupRetryEntry) mDataRetryEntries.get(i); 1711 if (entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED 1712 && entry.setupRetryType 1713 == DataSetupRetryEntry.RETRY_TYPE_NETWORK_REQUESTS 1714 && entry.retryElapsedTime > now) { 1715 if (entry.networkRequestList.isEmpty()) { 1716 String msg = "Invalid data retry entry detected"; 1717 logl(msg); 1718 loge("mDataRetryEntries=" + mDataRetryEntries); 1719 AnomalyReporter.reportAnomaly( 1720 UUID.fromString("781af571-f55d-476d-b510-7a5381f633dc"), 1721 msg, 1722 mPhone.getCarrierId()); 1723 continue; 1724 } 1725 if (entry.networkRequestList.get(0).getApnTypeNetworkCapability() 1726 == networkRequest.getApnTypeNetworkCapability() 1727 && entry.transport == transport) { 1728 return true; 1729 } 1730 } 1731 } 1732 } 1733 return false; 1734 } 1735 1736 /** 1737 * Check if a specific data profile is explicitly throttled by the network. 1738 * 1739 * @param dataProfile The data profile to check. 1740 * @param transport The transport that the request is on. 1741 * @return {@code true} if the data profile is currently throttled. 1742 */ isDataProfileThrottled(@onNull DataProfile dataProfile, @TransportType int transport)1743 public boolean isDataProfileThrottled(@NonNull DataProfile dataProfile, 1744 @TransportType int transport) { 1745 long now = SystemClock.elapsedRealtime(); 1746 return mDataThrottlingEntries.stream().anyMatch( 1747 entry -> entry.dataProfile.equals(dataProfile) && entry.expirationTimeMillis > now 1748 && entry.transport == transport); 1749 } 1750 1751 /** 1752 * Cancel pending scheduled handover retry entries. 1753 * 1754 * @param dataNetwork The data network that was originally scheduled for handover retry. 1755 */ cancelPendingHandoverRetry(@onNull DataNetwork dataNetwork)1756 public void cancelPendingHandoverRetry(@NonNull DataNetwork dataNetwork) { 1757 sendMessage(obtainMessage(EVENT_CANCEL_PENDING_HANDOVER_RETRY, dataNetwork)); 1758 } 1759 1760 /** 1761 * Called when cancelling pending scheduled handover retry entries. 1762 * 1763 * @param dataNetwork The data network that was originally scheduled for handover retry. 1764 */ onCancelPendingHandoverRetry(@onNull DataNetwork dataNetwork)1765 private void onCancelPendingHandoverRetry(@NonNull DataNetwork dataNetwork) { 1766 mDataRetryEntries.stream() 1767 .filter(entry -> entry instanceof DataHandoverRetryEntry 1768 && ((DataHandoverRetryEntry) entry).dataNetwork == dataNetwork 1769 && entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED) 1770 .forEach(entry -> entry.setState(DataRetryEntry.RETRY_STATE_CANCELLED)); 1771 } 1772 1773 /** 1774 * Check if there is any data handover retry scheduled. 1775 * 1776 * @param dataNetwork The network network to retry handover. 1777 * @return {@code true} if there is retry scheduled for this network capability. 1778 */ isAnyHandoverRetryScheduled(@onNull DataNetwork dataNetwork)1779 public boolean isAnyHandoverRetryScheduled(@NonNull DataNetwork dataNetwork) { 1780 return mDataRetryEntries.stream() 1781 .filter(DataHandoverRetryEntry.class::isInstance) 1782 .map(DataHandoverRetryEntry.class::cast) 1783 .anyMatch(entry -> entry.getState() == DataRetryEntry.RETRY_STATE_NOT_RETRIED 1784 && entry.dataNetwork == dataNetwork); 1785 } 1786 1787 /** 1788 * Register the callback for receiving information from {@link DataRetryManager}. 1789 * 1790 * @param callback The callback. 1791 */ registerCallback(@onNull DataRetryManagerCallback callback)1792 public void registerCallback(@NonNull DataRetryManagerCallback callback) { 1793 mDataRetryManagerCallbacks.add(callback); 1794 } 1795 1796 /** 1797 * Unregister the previously registered {@link DataRetryManagerCallback}. 1798 * 1799 * @param callback The callback to unregister. 1800 */ unregisterCallback(@onNull DataRetryManagerCallback callback)1801 public void unregisterCallback(@NonNull DataRetryManagerCallback callback) { 1802 mDataRetryManagerCallbacks.remove(callback); 1803 } 1804 1805 /** 1806 * Convert reset reason to string 1807 * 1808 * @param reason The reason 1809 * @return The reason in string format. 1810 */ resetReasonToString(int reason)1811 private static @NonNull String resetReasonToString(int reason) { 1812 switch (reason) { 1813 case RESET_REASON_DATA_PROFILES_CHANGED: 1814 return "DATA_PROFILES_CHANGED"; 1815 case RESET_REASON_RADIO_ON: 1816 return "RADIO_ON"; 1817 case RESET_REASON_MODEM_RESTART: 1818 return "MODEM_RESTART"; 1819 case RESET_REASON_DATA_SERVICE_BOUND: 1820 return "DATA_SERVICE_BOUND"; 1821 case RESET_REASON_DATA_CONFIG_CHANGED: 1822 return "DATA_CONFIG_CHANGED"; 1823 case RESET_REASON_TAC_CHANGED: 1824 return "TAC_CHANGED"; 1825 default: 1826 return "UNKNOWN(" + reason + ")"; 1827 } 1828 } 1829 1830 /** 1831 * Log debug messages. 1832 * @param s debug messages 1833 */ log(@onNull String s)1834 private void log(@NonNull String s) { 1835 Rlog.d(mLogTag, s); 1836 } 1837 1838 /** 1839 * Log error messages. 1840 * @param s error messages 1841 */ loge(@onNull String s)1842 private void loge(@NonNull String s) { 1843 Rlog.e(mLogTag, s); 1844 } 1845 1846 /** 1847 * Log verbose messages. 1848 * @param s debug messages. 1849 */ logv(@onNull String s)1850 private void logv(@NonNull String s) { 1851 if (VDBG) Rlog.v(mLogTag, s); 1852 } 1853 1854 /** 1855 * Log debug messages and also log into the local log. 1856 * @param s debug messages 1857 */ logl(@onNull String s)1858 private void logl(@NonNull String s) { 1859 log(s); 1860 mLocalLog.log(s); 1861 } 1862 1863 /** 1864 * Dump the state of DataRetryManager. 1865 * 1866 * @param fd File descriptor 1867 * @param printWriter Print writer 1868 * @param args Arguments 1869 */ dump(FileDescriptor fd, PrintWriter printWriter, String[] args)1870 public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) { 1871 IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); 1872 pw.println(DataRetryManager.class.getSimpleName() + "-" + mPhone.getPhoneId() + ":"); 1873 pw.increaseIndent(); 1874 pw.println("Data Setup Retry rules:"); 1875 pw.increaseIndent(); 1876 mDataSetupRetryRuleList.forEach(pw::println); 1877 pw.decreaseIndent(); 1878 pw.println("Data Handover Retry rules:"); 1879 pw.increaseIndent(); 1880 mDataHandoverRetryRuleList.forEach(pw::println); 1881 pw.decreaseIndent(); 1882 1883 pw.println("Retry entries:"); 1884 pw.increaseIndent(); 1885 for (DataRetryEntry entry : mDataRetryEntries) { 1886 pw.println(entry); 1887 } 1888 pw.decreaseIndent(); 1889 1890 pw.println("Throttling entries:"); 1891 pw.increaseIndent(); 1892 for (DataThrottlingEntry entry : mDataThrottlingEntries) { 1893 pw.println(entry); 1894 } 1895 pw.decreaseIndent(); 1896 1897 pw.println("Local logs:"); 1898 pw.increaseIndent(); 1899 mLocalLog.dump(fd, pw, args); 1900 pw.decreaseIndent(); 1901 pw.decreaseIndent(); 1902 } 1903 } 1904