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