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