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