• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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