• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 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.dataconnection;
18 
19 import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
20 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_CONGESTED;
21 import static android.net.NetworkPolicyManager.SUBSCRIPTION_OVERRIDE_UNMETERED;
22 import static android.telephony.TelephonyManager.NETWORK_TYPE_LTE;
23 import static android.telephony.TelephonyManager.NETWORK_TYPE_NR;
24 import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_DO_FALLBACK;
25 import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY;
26 import static android.telephony.data.DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL;
27 
28 import static com.android.internal.telephony.RILConstants.DATA_PROFILE_DEFAULT;
29 import static com.android.internal.telephony.RILConstants.DATA_PROFILE_INVALID;
30 
31 import android.annotation.IntDef;
32 import android.annotation.NonNull;
33 import android.annotation.Nullable;
34 import android.app.AlarmManager;
35 import android.app.Notification;
36 import android.app.NotificationManager;
37 import android.app.PendingIntent;
38 import android.app.ProgressDialog;
39 import android.content.ActivityNotFoundException;
40 import android.content.BroadcastReceiver;
41 import android.content.ContentResolver;
42 import android.content.ContentValues;
43 import android.content.Context;
44 import android.content.Intent;
45 import android.content.IntentFilter;
46 import android.content.SharedPreferences;
47 import android.content.res.Resources;
48 import android.database.ContentObserver;
49 import android.database.Cursor;
50 import android.net.ConnectivityManager;
51 import android.net.LinkProperties;
52 import android.net.NetworkAgent;
53 import android.net.NetworkCapabilities;
54 import android.net.NetworkPolicyManager;
55 import android.net.NetworkRequest;
56 import android.net.TrafficStats;
57 import android.net.Uri;
58 import android.os.AsyncResult;
59 import android.os.Bundle;
60 import android.os.Handler;
61 import android.os.HandlerThread;
62 import android.os.Message;
63 import android.os.PersistableBundle;
64 import android.os.RegistrantList;
65 import android.os.SystemClock;
66 import android.os.SystemProperties;
67 import android.os.UserHandle;
68 import android.preference.PreferenceManager;
69 import android.provider.Settings;
70 import android.provider.Settings.SettingNotFoundException;
71 import android.provider.Telephony;
72 import android.telephony.AccessNetworkConstants;
73 import android.telephony.AccessNetworkConstants.TransportType;
74 import android.telephony.Annotation.ApnType;
75 import android.telephony.Annotation.DataFailureCause;
76 import android.telephony.Annotation.NetworkType;
77 import android.telephony.CarrierConfigManager;
78 import android.telephony.CellLocation;
79 import android.telephony.DataFailCause;
80 import android.telephony.NetworkRegistrationInfo;
81 import android.telephony.PcoData;
82 import android.telephony.PreciseDataConnectionState;
83 import android.telephony.ServiceState;
84 import android.telephony.ServiceState.RilRadioTechnology;
85 import android.telephony.SubscriptionManager;
86 import android.telephony.SubscriptionPlan;
87 import android.telephony.TelephonyDisplayInfo;
88 import android.telephony.TelephonyFrameworkInitializer;
89 import android.telephony.TelephonyManager;
90 import android.telephony.TelephonyManager.SimState;
91 import android.telephony.cdma.CdmaCellLocation;
92 import android.telephony.data.ApnSetting;
93 import android.telephony.data.DataCallResponse;
94 import android.telephony.data.DataCallResponse.HandoverFailureMode;
95 import android.telephony.data.DataProfile;
96 import android.telephony.data.ThrottleStatus;
97 import android.telephony.gsm.GsmCellLocation;
98 import android.text.TextUtils;
99 import android.util.EventLog;
100 import android.util.LocalLog;
101 import android.util.Log;
102 import android.util.Pair;
103 import android.util.SparseArray;
104 import android.view.WindowManager;
105 
106 import com.android.internal.R;
107 import com.android.internal.annotations.VisibleForTesting;
108 import com.android.internal.telephony.DctConstants;
109 import com.android.internal.telephony.EventLogTags;
110 import com.android.internal.telephony.GsmCdmaPhone;
111 import com.android.internal.telephony.ITelephony;
112 import com.android.internal.telephony.Phone;
113 import com.android.internal.telephony.PhoneConstants;
114 import com.android.internal.telephony.PhoneFactory;
115 import com.android.internal.telephony.RILConstants;
116 import com.android.internal.telephony.RetryManager;
117 import com.android.internal.telephony.SettingsObserver;
118 import com.android.internal.telephony.SubscriptionInfoUpdater;
119 import com.android.internal.telephony.data.DataConfigManager;
120 import com.android.internal.telephony.data.PhoneSwitcher;
121 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataAllowedReasonType;
122 import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataDisallowedReasonType;
123 import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason;
124 import com.android.internal.telephony.metrics.DataStallRecoveryStats;
125 import com.android.internal.telephony.metrics.TelephonyMetrics;
126 import com.android.internal.telephony.util.ArrayUtils;
127 import com.android.internal.telephony.util.NotificationChannelController;
128 import com.android.internal.telephony.util.TelephonyUtils;
129 import com.android.internal.util.AsyncChannel;
130 import com.android.telephony.Rlog;
131 
132 import java.io.FileDescriptor;
133 import java.io.PrintWriter;
134 import java.lang.annotation.Retention;
135 import java.lang.annotation.RetentionPolicy;
136 import java.util.ArrayList;
137 import java.util.Arrays;
138 import java.util.Collection;
139 import java.util.Collections;
140 import java.util.HashMap;
141 import java.util.List;
142 import java.util.Map;
143 import java.util.Map.Entry;
144 import java.util.Set;
145 import java.util.concurrent.ConcurrentHashMap;
146 import java.util.concurrent.atomic.AtomicBoolean;
147 import java.util.concurrent.atomic.AtomicInteger;
148 import java.util.stream.Collectors;
149 
150 /**
151  * {@hide}
152  */
153 public class DcTracker extends Handler {
154     protected static final boolean DBG = true;
155     private static final boolean VDBG = false; // STOPSHIP if true
156     private static final boolean VDBG_STALL = false; // STOPSHIP if true
157     private static final boolean RADIO_TESTS = false;
158     private static final String NOTIFICATION_TAG = DcTracker.class.getSimpleName();
159 
160     @IntDef(value = {
161             REQUEST_TYPE_NORMAL,
162             REQUEST_TYPE_HANDOVER,
163     })
164     @Retention(RetentionPolicy.SOURCE)
165     public @interface RequestNetworkType {}
166 
167     /**
168      * Normal request for {@link #requestNetwork(NetworkRequest, int, Message)}. For request
169      * network, this adds the request to the {@link ApnContext}. If there were no network request
170      * attached to the {@link ApnContext} earlier, this request setups a data connection.
171      */
172     public static final int REQUEST_TYPE_NORMAL = 1;
173 
174     /**
175      * Handover request for {@link #requestNetwork(NetworkRequest, int, Message)} or
176      * {@link #releaseNetwork(NetworkRequest, int)}. For request network, this
177      * initiates the handover data setup process. The existing data connection will be seamlessly
178      * handover to the new network. For release network, this performs a data connection softly
179      * clean up at the underlying layer (versus normal data release).
180      */
181     public static final int REQUEST_TYPE_HANDOVER = 2;
182 
183     @IntDef(value = {
184             RELEASE_TYPE_NORMAL,
185             RELEASE_TYPE_DETACH,
186             RELEASE_TYPE_HANDOVER,
187     })
188     @Retention(RetentionPolicy.SOURCE)
189     public @interface ReleaseNetworkType {}
190 
191     /**
192      * For release network, this is just removing the network request from the {@link ApnContext}.
193      * Note this does not tear down the physical data connection. Normally the data connection is
194      * torn down by connectivity service directly calling {@link NetworkAgent#unwanted()}.
195      */
196     public static final int RELEASE_TYPE_NORMAL = 1;
197 
198     /**
199      * Detach request for {@link #releaseNetwork(NetworkRequest, int)} only. This
200      * forces the APN context detach from the data connection. If this {@link ApnContext} is the
201      * last one attached to the data connection, the data connection will be torn down, otherwise
202      * the data connection remains active.
203      */
204     public static final int RELEASE_TYPE_DETACH = 2;
205 
206     /**
207      * Handover request for {@link #releaseNetwork(NetworkRequest, int)}. For release
208      * network, this performs a data connection softly clean up at the underlying layer (versus
209      * normal data release).
210      */
211     public static final int RELEASE_TYPE_HANDOVER = 3;
212 
213     /** The extras for handover completion message */
214     public static final String DATA_COMPLETE_MSG_EXTRA_NETWORK_REQUEST = "extra_network_request";
215     public static final String DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE = "extra_transport_type";
216     public static final String DATA_COMPLETE_MSG_EXTRA_SUCCESS = "extra_success";
217     /**
218      * The flag indicates whether after handover failure, the data connection should remain on the
219      * original transport.
220      */
221     public static final String DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK =
222             "extra_handover_failure_fallback";
223 
224     private final String mLogTag;
225 
226     public AtomicBoolean isCleanupRequired = new AtomicBoolean(false);
227 
228     private final TelephonyManager mTelephonyManager;
229 
230     private final AlarmManager mAlarmManager;
231 
232     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
233     private int mRequestedApnType = ApnSetting.TYPE_DEFAULT;
234 
235     // All data enabling/disabling related settings
236     private final DataEnabledSettings mDataEnabledSettings;
237 
238     /**
239      * After detecting a potential connection problem, this is the max number
240      * of subsequent polls before attempting recovery.
241      */
242     // 1 sec. default polling interval when screen is on.
243     private static final int POLL_NETSTAT_MILLIS = 1000;
244     // 10 min. default polling interval when screen is off.
245     private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
246     // Default sent packets without ack which triggers initial recovery steps
247     private static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
248 
249     // Default for the data stall alarm while non-aggressive stall detection
250     private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
251     // Default for the data stall alarm for aggressive stall detection
252     private static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
253 
254     private static final boolean DATA_STALL_SUSPECTED = true;
255     protected static final boolean DATA_STALL_NOT_SUSPECTED = false;
256 
257     private static final String INTENT_DATA_STALL_ALARM =
258             "com.android.internal.telephony.data-stall";
259     // Tag for tracking stale alarms
260     private static final String INTENT_DATA_STALL_ALARM_EXTRA_TAG = "data_stall_alarm_extra_tag";
261     private static final String INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE =
262             "data_stall_alarm_extra_transport_type";
263 
264     // Unique id for no data notification on setup data permanently failed.
265     private static final int NO_DATA_NOTIFICATION = 1001;
266 
267     /** The higher index has higher priority. */
268     private static final DctConstants.State[] DATA_CONNECTION_STATE_PRIORITIES = {
269             DctConstants.State.IDLE,
270             DctConstants.State.DISCONNECTING,
271             DctConstants.State.CONNECTING,
272             DctConstants.State.CONNECTED,
273     };
274 
275     private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
276     private DcController mDcc;
277 
278     /** kept in sync with mApnContexts
279      * Higher numbers are higher priority and sorted so highest priority is first */
280     private ArrayList<ApnContext> mPrioritySortedApnContexts = new ArrayList<>();
281 
282     /** all APN settings applicable to the current carrier */
283     private ArrayList<ApnSetting> mAllApnSettings = new ArrayList<>();
284 
285     /** preferred apn */
286     private ApnSetting mPreferredApn = null;
287 
288     /** Is packet service restricted by network */
289     private boolean mIsPsRestricted = false;
290 
291     /** emergency apn Setting*/
292     private ApnSetting mEmergencyApn = null;
293 
294     /* Once disposed dont handle any messages */
295     private boolean mIsDisposed = false;
296 
297     private ContentResolver mResolver;
298 
299     /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */
300     private boolean mIsProvisioning = false;
301 
302     /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */
303     private String mProvisioningUrl = null;
304 
305     /* Indicating data service is bound or not */
306     private boolean mDataServiceBound = false;
307 
308     /* Intent to hide/show the sign-in error notification for provisioning */
309     private static final String INTENT_PROVISION = "com.android.internal.telephony.PROVISION";
310 
311     /**
312      * Extra containing the phone ID for INTENT_PROVISION
313      * Must be kept consistent with NetworkNotificationManager#setProvNotificationVisible.
314      * TODO: refactor the deprecated API to prevent hardcoding values.
315      */
316     private static final String EXTRA_PROVISION_PHONE_ID = "provision.phone.id";
317 
318     /* Intent for the provisioning apn alarm */
319     private static final String INTENT_PROVISIONING_APN_ALARM =
320             "com.android.internal.telephony.provisioning_apn_alarm";
321 
322     /* Tag for tracking stale alarms */
323     private static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag";
324 
325     /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */
326     private static final String DEBUG_PROV_APN_ALARM = "persist.debug.prov_apn_alarm";
327 
328     /* Default for the provisioning apn alarm timeout */
329     private static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15;
330 
331     /* The provision apn alarm intent used to disable the provisioning apn */
332     private PendingIntent mProvisioningApnAlarmIntent = null;
333 
334     /* Used to track stale provisioning apn alarms */
335     private int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime();
336 
337     private AsyncChannel mReplyAc = new AsyncChannel();
338 
339     private final LocalLog mDataRoamingLeakageLog = new LocalLog(32);
340     private final LocalLog mApnSettingsInitializationLog = new LocalLog(32);
341 
342     /* 5G connection reevaluation watchdog alarm constants */
343     private long mWatchdogTimeMs = 1000 * 60 * 60;
344     private boolean mWatchdog = false;
345 
346     /* Default for whether 5G frequencies are considered unmetered */
347     private boolean mNrNsaAllUnmetered = false;
348     private boolean mNrNsaMmwaveUnmetered = false;
349     private boolean mNrNsaSub6Unmetered = false;
350     private boolean mNrSaAllUnmetered = false;
351     private boolean mNrSaMmwaveUnmetered = false;
352     private boolean mNrSaSub6Unmetered = false;
353     private boolean mNrNsaRoamingUnmetered = false;
354 
355     // it effect the PhysicalLinkStatusChanged
356     private boolean mLteEndcUsingUserDataForRrcDetection = false;
357 
358     /* List of SubscriptionPlans, updated when initialized and when plans are changed. */
359     private List<SubscriptionPlan> mSubscriptionPlans = new ArrayList<>();
360     /* List of network types an unmetered override applies to, set by onSubscriptionOverride
361      * and cleared when the device is rebooted or the override expires. */
362     private List<Integer> mUnmeteredNetworkTypes = null;
363     /* List of network types a congested override applies to, set by onSubscriptionOverride
364      * and cleared when the device is rebooted or the override expires. */
365     private List<Integer> mCongestedNetworkTypes = null;
366     /* Whether an unmetered override is currently active. */
367     private boolean mUnmeteredOverride = false;
368     /* Whether a congested override is currently active. */
369     private boolean mCongestedOverride = false;
370 
371     @SimState
372     private int mSimState = TelephonyManager.SIM_STATE_UNKNOWN;
373 
374     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () {
375         @Override
376         public void onReceive(Context context, Intent intent) {
377             String action = intent.getAction();
378 
379             if (action.equals(Intent.ACTION_SCREEN_ON)) {
380                 // TODO: Evaluate hooking this up with DeviceStateMonitor
381                 if (DBG) log("screen on");
382                 mIsScreenOn = true;
383                 stopNetStatPoll();
384                 startNetStatPoll();
385                 restartDataStallAlarm();
386             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
387                 if (DBG) log("screen off");
388                 mIsScreenOn = false;
389                 stopNetStatPoll();
390                 startNetStatPoll();
391                 restartDataStallAlarm();
392             } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
393                 onActionIntentDataStallAlarm(intent);
394             } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) {
395                 if (DBG) log("Provisioning apn alarm");
396                 onActionIntentProvisioningApnAlarm(intent);
397             } else if (action.equals(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED)
398                     || action.equals(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) {
399                 if (mPhone.getPhoneId() == intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
400                         SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
401                     int simState = intent.getIntExtra(TelephonyManager.EXTRA_SIM_STATE,
402                             TelephonyManager.SIM_STATE_UNKNOWN);
403                     sendMessage(obtainMessage(DctConstants.EVENT_SIM_STATE_UPDATED, simState, 0));
404                 }
405             } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
406                 if (mPhone.getPhoneId() == intent.getIntExtra(CarrierConfigManager.EXTRA_SLOT_INDEX,
407                         SubscriptionManager.INVALID_SIM_SLOT_INDEX)) {
408                     if (intent.getBooleanExtra(
409                             CarrierConfigManager.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
410                         // Ignore the rebroadcast one to prevent multiple carrier config changed
411                         // event during boot up.
412                         return;
413                     }
414                     int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
415                             SubscriptionManager.INVALID_SUBSCRIPTION_ID);
416                     if (SubscriptionManager.isValidSubscriptionId(subId)) {
417                         sendEmptyMessage(DctConstants.EVENT_CARRIER_CONFIG_CHANGED);
418                     }
419                 }
420             } else {
421                 if (DBG) log("onReceive: Unknown action=" + action);
422             }
423         }
424     };
425 
426     private final Runnable mPollNetStat = new Runnable() {
427         @Override
428         public void run() {
429             updateDataActivity();
430 
431             if (mIsScreenOn) {
432                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
433                         Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
434             } else {
435                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
436                         Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
437                         POLL_NETSTAT_SCREEN_OFF_MILLIS);
438             }
439 
440             if (mNetStatPollEnabled) {
441                 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
442             }
443         }
444     };
445 
446     private class ThrottleStatusChangedCallback implements DataThrottler.Callback {
447         @Override
onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses)448         public void onThrottleStatusChanged(List<ThrottleStatus> throttleStatuses) {
449             for (ThrottleStatus status : throttleStatuses) {
450                 if (status.getThrottleType() == ThrottleStatus.THROTTLE_TYPE_NONE) {
451                     setupDataOnConnectableApn(mApnContextsByType.get(status.getApnType()),
452                             Phone.REASON_DATA_UNTHROTTLED,
453                             RetryFailures.ALWAYS);
454                 }
455             }
456         }
457     }
458 
459     private NetworkPolicyManager mNetworkPolicyManager;
460     private final NetworkPolicyManager.SubscriptionCallback mSubscriptionCallback =
461             new NetworkPolicyManager.SubscriptionCallback() {
462         @Override
463         public void onSubscriptionOverride(int subId, int overrideMask, int overrideValue,
464                 int[] networkTypes) {
465             if (mPhone == null || mPhone.getSubId() != subId) return;
466 
467             List<Integer> tempList = new ArrayList<>();
468             for (int networkType : networkTypes) {
469                 tempList.add(networkType);
470             }
471 
472             log("Subscription override: overrideMask=" + overrideMask
473                     + ", overrideValue=" + overrideValue + ", networkTypes=" + tempList);
474 
475             if (overrideMask == SUBSCRIPTION_OVERRIDE_UNMETERED) {
476                 mUnmeteredNetworkTypes = tempList;
477                 mUnmeteredOverride = overrideValue != 0;
478                 reevaluateUnmeteredConnections();
479             } else if (overrideMask == SUBSCRIPTION_OVERRIDE_CONGESTED) {
480                 mCongestedNetworkTypes = tempList;
481                 mCongestedOverride = overrideValue != 0;
482                 reevaluateCongestedConnections();
483             }
484         }
485 
486         @Override
487         public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) {
488             if (mPhone == null || mPhone.getSubId() != subId) return;
489 
490             mSubscriptionPlans = Arrays.asList(plans);
491             if (DBG) log("SubscriptionPlans changed: " + mSubscriptionPlans);
492             reevaluateUnmeteredConnections();
493         }
494     };
495 
496     private final SettingsObserver mSettingsObserver;
497 
registerSettingsObserver()498     private void registerSettingsObserver() {
499         mSettingsObserver.unobserve();
500         String simSuffix = "";
501         if (TelephonyManager.getDefault().getSimCount() > 1) {
502             simSuffix = Integer.toString(mPhone.getSubId());
503         }
504 
505         mSettingsObserver.observe(
506                 Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix),
507                 DctConstants.EVENT_ROAMING_SETTING_CHANGE);
508         mSettingsObserver.observe(
509                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
510                 DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE);
511     }
512 
513     /**
514      * Maintain the sum of transmit and receive packets.
515      *
516      * The packet counts are initialized and reset to -1 and
517      * remain -1 until they can be updated.
518      */
519     public static class TxRxSum {
520         public long txPkts;
521         public long rxPkts;
522 
TxRxSum()523         public TxRxSum() {
524             reset();
525         }
526 
TxRxSum(long txPkts, long rxPkts)527         public TxRxSum(long txPkts, long rxPkts) {
528             this.txPkts = txPkts;
529             this.rxPkts = rxPkts;
530         }
531 
TxRxSum(TxRxSum sum)532         public TxRxSum(TxRxSum sum) {
533             txPkts = sum.txPkts;
534             rxPkts = sum.rxPkts;
535         }
536 
reset()537         public void reset() {
538             txPkts = -1;
539             rxPkts = -1;
540         }
541 
542         @Override
toString()543         public String toString() {
544             return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
545         }
546 
547         /**
548          * Get total Tx/Rx packet count from TrafficStats
549          */
updateTotalTxRxSum()550         public void updateTotalTxRxSum() {
551             this.txPkts = TrafficStats.getMobileTxPackets();
552             this.rxPkts = TrafficStats.getMobileRxPackets();
553         }
554     }
555 
onDataReconnect(ApnContext apnContextforRetry, int subId, @RequestNetworkType int requestType)556     private void onDataReconnect(ApnContext apnContextforRetry, int subId,
557             @RequestNetworkType int requestType) {
558         int phoneSubId = mPhone.getSubId();
559         String apnType = apnContextforRetry.getApnType();
560         String reason =  apnContextforRetry.getReason();
561 
562         if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != phoneSubId)) {
563             log("onDataReconnect: invalid subId");
564             return;
565         }
566 
567         ApnContext apnContext = mApnContexts.get(apnType);
568 
569         if (DBG) {
570             log("onDataReconnect: mState=" + mState + " reason=" + reason + " apnType=" + apnType
571                     + " apnContext=" + apnContext);
572         }
573 
574         if ((apnContext != null) && (apnContext.isEnabled())) {
575             apnContext.setReason(reason);
576             DctConstants.State apnContextState = apnContext.getState();
577             if (DBG) {
578                 log("onDataReconnect: apnContext state=" + apnContextState);
579             }
580             if ((apnContextState == DctConstants.State.FAILED)
581                     || (apnContextState == DctConstants.State.IDLE)) {
582                 if (DBG) {
583                     log("onDataReconnect: state is FAILED|IDLE, disassociate");
584                 }
585                 apnContext.releaseDataConnection("");
586             } else {
587                 if (DBG) log("onDataReconnect: keep associated");
588             }
589             // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
590             sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, requestType,
591                     0, apnContext));
592         }
593     }
594 
onActionIntentDataStallAlarm(Intent intent)595     private void onActionIntentDataStallAlarm(Intent intent) {
596         if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
597 
598         int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
599                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
600         if (!SubscriptionManager.isValidSubscriptionId(subId) || (subId != mPhone.getSubId())) {
601             return;
602         }
603 
604         int transportType = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, 0);
605         if (transportType != mTransportType) {
606             return;
607         }
608 
609         Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM,
610                 intent.getAction());
611         msg.arg1 = intent.getIntExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, 0);
612         sendMessage(msg);
613     }
614 
615     private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
616 
617     // member variables
618     protected final Phone mPhone;
619     private DctConstants.Activity mActivity = DctConstants.Activity.NONE;
620     private DctConstants.State mState = DctConstants.State.IDLE;
621     private final Handler mDataConnectionTracker;
622 
623     private long mTxPkts;
624     private long mRxPkts;
625     private int mNetStatPollPeriod;
626     private boolean mNetStatPollEnabled = false;
627 
628     private TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
629     // Used to track stale data stall alarms.
630     private int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
631     // The current data stall alarm intent
632     private PendingIntent mDataStallAlarmIntent = null;
633     // Number of packets sent since the last received packet
634     private long mSentSinceLastRecv;
635     // Controls when a simple recovery attempt it to be tried
636     private int mNoRecvPollCount = 0;
637     // Reference counter for enabling fail fast
638     private static int sEnableFailFastRefCounter = 0;
639     // True if data stall detection is enabled
640     private volatile boolean mDataStallNoRxEnabled = true;
641 
642     protected volatile boolean mFailFast = false;
643 
644     // True when in voice call
645     protected boolean mInVoiceCall = false;
646 
647     /** Intent sent when the reconnect alarm fires. */
648     private PendingIntent mReconnectIntent = null;
649 
650     // When false we will not auto attach and manually attaching is required.
651     protected boolean mAutoAttachOnCreationConfig = false;
652     private AtomicBoolean mAutoAttachEnabled = new AtomicBoolean(false);
653 
654     // State of screen
655     // (TODO: Reconsider tying directly to screen, maybe this is
656     //        really a lower power mode")
657     private boolean mIsScreenOn = true;
658 
659     /** Allows the generation of unique Id's for DataConnection objects */
660     private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
661 
662     /** The data connections. */
663     private HashMap<Integer, DataConnection> mDataConnections =
664             new HashMap<Integer, DataConnection>();
665 
666     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
667     private HashMap<String, Integer> mApnToDataConnectionId = new HashMap<String, Integer>();
668 
669     /** Phone.APN_TYPE_* ===> ApnContext */
670     protected ConcurrentHashMap<String, ApnContext> mApnContexts =
671             new ConcurrentHashMap<String, ApnContext>();
672 
673     private SparseArray<ApnContext> mApnContextsByType = new SparseArray<ApnContext>();
674 
675     private ArrayList<DataProfile> mLastDataProfileList = new ArrayList<>();
676 
677     /** RAT name ===> (downstream, upstream) bandwidth values from carrier config. */
678     private ConcurrentHashMap<String, Pair<Integer, Integer>> mBandwidths =
679             new ConcurrentHashMap<>();
680 
681     private boolean mConfigReady = false;
682 
683     /**
684      * Handles changes to the APN db.
685      */
686     private class ApnChangeObserver extends ContentObserver {
ApnChangeObserver()687         public ApnChangeObserver () {
688             super(mDataConnectionTracker);
689         }
690 
691         @Override
onChange(boolean selfChange)692         public void onChange(boolean selfChange) {
693             sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED));
694         }
695     }
696 
697     //***** Instance Variables
698 
699     private boolean mReregisterOnReconnectFailure = false;
700 
701 
702     //***** Constants
703 
704     private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000;
705 
706     static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID =
707                         Uri.parse("content://telephony/carriers/preferapn_no_update/subId/");
708     static final String APN_ID = "apn_id";
709 
710     private boolean mCanSetPreferApn = false;
711 
712     private AtomicBoolean mAttached = new AtomicBoolean(false);
713 
714     /** Watches for changes to the APN db. */
715     private ApnChangeObserver mApnObserver;
716 
717     private BroadcastReceiver mProvisionBroadcastReceiver;
718     private ProgressDialog mProvisioningSpinner;
719 
720     private final DataServiceManager mDataServiceManager;
721 
722     @AccessNetworkConstants.TransportType
723     private final int mTransportType;
724 
725     private DataStallRecoveryHandler mDsRecoveryHandler;
726     private HandlerThread mHandlerThread;
727 
728     private final DataThrottler mDataThrottler;
729 
730     private final ThrottleStatusChangedCallback mThrottleStatusCallback;
731 
732     /**
733      * Request network completion message map. Key is the APN type, value is the list of completion
734      * messages to be sent. Using a list because there might be multiple network requests for
735      * the same APN type.
736      */
737     private final Map<Integer, List<Message>> mHandoverCompletionMsgs = new HashMap<>();
738 
739     //***** Constructor
DcTracker(Phone phone, @TransportType int transportType)740     public DcTracker(Phone phone, @TransportType int transportType) {
741         super();
742         mPhone = phone;
743         if (DBG) log("DCT.constructor");
744         mTelephonyManager = TelephonyManager.from(phone.getContext())
745                 .createForSubscriptionId(phone.getSubId());
746         // The 'C' in tag indicates cellular, and 'I' indicates IWLAN. This is to distinguish
747         // between two DcTrackers, one for each.
748         String tagSuffix = "-" + ((transportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
749                 ? "C" : "I");
750         tagSuffix += "-" + mPhone.getPhoneId();
751         mLogTag = "DCT" + tagSuffix;
752 
753         mTransportType = transportType;
754         mDataServiceManager = new DataServiceManager(phone, transportType, tagSuffix);
755         mDataThrottler = new DataThrottler(mPhone, transportType);
756 
757         mResolver = mPhone.getContext().getContentResolver();
758         mAlarmManager =
759                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
760 
761         mDsRecoveryHandler = new DataStallRecoveryHandler();
762 
763         IntentFilter filter = new IntentFilter();
764         filter.addAction(Intent.ACTION_SCREEN_ON);
765         filter.addAction(Intent.ACTION_SCREEN_OFF);
766         filter.addAction(INTENT_DATA_STALL_ALARM);
767         filter.addAction(INTENT_PROVISIONING_APN_ALARM);
768         filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
769         filter.addAction(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
770         filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
771 
772         mDataEnabledSettings = mPhone.getDataEnabledSettings();
773 
774         mDataEnabledSettings.registerForDataEnabledChanged(this,
775                 DctConstants.EVENT_DATA_ENABLED_CHANGED, null);
776         mDataEnabledSettings.registerForDataEnabledOverrideChanged(this,
777                 DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED);
778 
779         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
780 
781         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
782         mAutoAttachEnabled.set(sp.getBoolean(Phone.DATA_DISABLED_ON_BOOT_KEY, false));
783 
784         mNetworkPolicyManager = (NetworkPolicyManager) mPhone.getContext()
785                 .getSystemService(Context.NETWORK_POLICY_SERVICE);
786         mNetworkPolicyManager.registerSubscriptionCallback(mSubscriptionCallback);
787 
788         mHandlerThread = new HandlerThread("DcHandlerThread");
789         mHandlerThread.start();
790         Handler dcHandler = new Handler(mHandlerThread.getLooper());
791         mDcc = DcController.makeDcc(mPhone, this, mDataServiceManager, dcHandler.getLooper(),
792                 tagSuffix);
793         mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler);
794 
795         mDataConnectionTracker = this;
796         registerForAllEvents();
797         mApnObserver = new ApnChangeObserver();
798         phone.getContext().getContentResolver().registerContentObserver(
799                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
800 
801         initApnContexts();
802 
803         addDefaultApnSettingsAsNeeded();
804 
805         mSettingsObserver = new SettingsObserver(mPhone.getContext(), this);
806         registerSettingsObserver();
807 
808         mThrottleStatusCallback = new ThrottleStatusChangedCallback();
809         mDataThrottler.registerForThrottleStatusChanges(mThrottleStatusCallback);
810     }
811 
812     @VisibleForTesting
DcTracker()813     public DcTracker() {
814         mLogTag = "DCT";
815         mTelephonyManager = null;
816         mAlarmManager = null;
817         mPhone = null;
818         mDataConnectionTracker = null;
819         mSettingsObserver = new SettingsObserver(null, this);
820         mDataEnabledSettings = null;
821         mTransportType = 0;
822         mDataServiceManager = null;
823         mDataThrottler = null;
824         mThrottleStatusCallback = null;
825     }
826 
registerServiceStateTrackerEvents()827     public void registerServiceStateTrackerEvents() {
828         mPhone.getServiceStateTracker().registerForDataConnectionAttached(mTransportType, this,
829                 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
830         mPhone.getServiceStateTracker().registerForDataConnectionDetached(mTransportType, this,
831                 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
832         mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
833                 DctConstants.EVENT_ROAMING_ON, null);
834         mPhone.getServiceStateTracker().registerForDataRoamingOff(this,
835                 DctConstants.EVENT_ROAMING_OFF, null, true);
836         mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
837                 DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
838         mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
839                 DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
840         mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(mTransportType, this,
841                 DctConstants.EVENT_DATA_RAT_CHANGED, null);
842     }
843 
unregisterServiceStateTrackerEvents()844     public void unregisterServiceStateTrackerEvents() {
845         mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(mTransportType, this);
846         mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(mTransportType, this);
847         mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this);
848         mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
849         mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
850         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
851         mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(mTransportType, this);
852         mPhone.getServiceStateTracker().unregisterForAirplaneModeChanged(this);
853     }
854 
registerForAllEvents()855     private void registerForAllEvents() {
856         if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
857             mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null);
858             mPhone.mCi.registerForOffOrNotAvailable(this,
859                     DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
860             mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null);
861         }
862 
863         // Note, this is fragile - the Phone is now presenting a merged picture
864         // of PS (volte) & CS and by diving into its internals you're just seeing
865         // the CS data.  This works well for the purposes this is currently used for
866         // but that may not always be the case.  Should probably be redesigned to
867         // accurately reflect what we're really interested in (registerForCSVoiceCallEnded).
868         mPhone.getCallTracker().registerForVoiceCallEnded(this,
869                 DctConstants.EVENT_VOICE_CALL_ENDED, null);
870         mPhone.getCallTracker().registerForVoiceCallStarted(this,
871                 DctConstants.EVENT_VOICE_CALL_STARTED, null);
872         mPhone.getDisplayInfoController().registerForTelephonyDisplayInfoChanged(this,
873                 DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED, null);
874         registerServiceStateTrackerEvents();
875         mDataServiceManager.registerForServiceBindingChanged(this,
876                 DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED, null);
877         mDataServiceManager.registerForApnUnthrottled(this, DctConstants.EVENT_APN_UNTHROTTLED);
878     }
879 
dispose()880     public void dispose() {
881         if (DBG) log("DCT.dispose");
882 
883         if (mProvisionBroadcastReceiver != null) {
884             mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
885             mProvisionBroadcastReceiver = null;
886         }
887         if (mProvisioningSpinner != null) {
888             mProvisioningSpinner.dismiss();
889             mProvisioningSpinner = null;
890         }
891 
892         cleanUpAllConnectionsInternal(true, null);
893 
894         mIsDisposed = true;
895         mPhone.getContext().unregisterReceiver(mIntentReceiver);
896         mSettingsObserver.unobserve();
897 
898         mNetworkPolicyManager.unregisterSubscriptionCallback(mSubscriptionCallback);
899         mDcTesterFailBringUpAll.dispose();
900 
901         mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver);
902         mApnContexts.clear();
903         mApnContextsByType.clear();
904         mPrioritySortedApnContexts.clear();
905         unregisterForAllEvents();
906 
907         destroyDataConnections();
908     }
909 
910     /**
911      * Stop the internal handler thread
912      *
913      * TESTING ONLY
914      */
915     @VisibleForTesting
stopHandlerThread()916     public void stopHandlerThread() {
917         mHandlerThread.quit();
918     }
919 
unregisterForAllEvents()920     private void unregisterForAllEvents() {
921          //Unregister for all events
922         if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
923             mPhone.mCi.unregisterForAvailable(this);
924             mPhone.mCi.unregisterForOffOrNotAvailable(this);
925             mPhone.mCi.unregisterForPcoData(this);
926         }
927 
928         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
929         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
930         mPhone.getDisplayInfoController().unregisterForTelephonyDisplayInfoChanged(this);
931         unregisterServiceStateTrackerEvents();
932         mDataServiceManager.unregisterForServiceBindingChanged(this);
933         mDataEnabledSettings.unregisterForDataEnabledChanged(this);
934         mDataEnabledSettings.unregisterForDataEnabledOverrideChanged(this);
935         mDataServiceManager.unregisterForApnUnthrottled(this);
936     }
937 
938     /**
939      * Reevaluate existing data connections when conditions change.
940      *
941      * For example, handle reverting restricted networks back to unrestricted. If we're changing
942      * user data to enabled and this makes data truly enabled (not disabled by other factors) we
943      * need to reevaluate and possibly add NET_CAPABILITY_NOT_RESTRICTED capability to the data
944      * connection. This allows non-privilege apps to use the network.
945      *
946      * Or when we brought up a unmetered data connection while data is off, we only limit this
947      * data connection for unmetered use only. When data is turned back on, we need to tear that
948      * down so a full capable data connection can be re-established.
949      */
reevaluateDataConnections()950     private void reevaluateDataConnections() {
951         for (DataConnection dataConnection : mDataConnections.values()) {
952             dataConnection.reevaluateRestrictedState();
953         }
954     }
955 
getSubId()956     public long getSubId() {
957         return mPhone.getSubId();
958     }
959 
getActivity()960     public DctConstants.Activity getActivity() {
961         return mActivity;
962     }
963 
setActivity(DctConstants.Activity activity)964     private void setActivity(DctConstants.Activity activity) {
965         log("setActivity = " + activity);
966         mActivity = activity;
967         mPhone.notifyDataActivity();
968     }
969 
970     /**
971      * Request a network
972      *
973      * @param networkRequest Network request from clients
974      * @param type The request type
975      * @param onHandoverCompleteMsg When request type is handover, this message will be sent when
976      * handover is completed. For normal request, this should be null.
977      */
requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type, Message onHandoverCompleteMsg)978     public void requestNetwork(NetworkRequest networkRequest, @RequestNetworkType int type,
979             Message onHandoverCompleteMsg) {
980         if (type != REQUEST_TYPE_HANDOVER && onHandoverCompleteMsg != null) {
981             throw new RuntimeException("request network with normal type request type but passing "
982                     + "handover complete message.");
983         }
984         final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
985         final ApnContext apnContext = mApnContextsByType.get(apnType);
986         if (apnContext != null) {
987             apnContext.requestNetwork(networkRequest, type, onHandoverCompleteMsg);
988         }
989     }
990 
releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type)991     public void releaseNetwork(NetworkRequest networkRequest, @ReleaseNetworkType int type) {
992         final int apnType = ApnContext.getApnTypeFromNetworkRequest(networkRequest);
993         final ApnContext apnContext = mApnContextsByType.get(apnType);
994         if (apnContext != null) {
995             apnContext.releaseNetwork(networkRequest, type);
996         }
997     }
998 
999     // Turn telephony radio on or off.
setRadio(boolean on)1000     private void setRadio(boolean on) {
1001         final ITelephony phone = ITelephony.Stub.asInterface(
1002                 TelephonyFrameworkInitializer
1003                         .getTelephonyServiceManager()
1004                         .getTelephonyServiceRegisterer()
1005                         .get());
1006         try {
1007             phone.setRadio(on);
1008         } catch (Exception e) {
1009             // Ignore.
1010         }
1011     }
1012 
1013     // Class to handle Intent dispatched with user selects the "Sign-in to network"
1014     // notification.
1015     private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver {
1016         private final String mNetworkOperator;
1017         // Mobile provisioning URL.  Valid while provisioning notification is up.
1018         // Set prior to notification being posted as URL contains ICCID which
1019         // disappears when radio is off (which is the case when notification is up).
1020         private final String mProvisionUrl;
1021 
ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator)1022         public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) {
1023             mNetworkOperator = networkOperator;
1024             mProvisionUrl = provisionUrl;
1025         }
1026 
setEnableFailFastMobileData(int enabled)1027         private void setEnableFailFastMobileData(int enabled) {
1028             sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0));
1029         }
1030 
enableMobileProvisioning()1031         private void enableMobileProvisioning() {
1032             final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING);
1033             Bundle bundle = new Bundle(1);
1034             bundle.putString(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl);
1035             msg.setData(bundle);
1036             sendMessage(msg);
1037         }
1038 
1039         @Override
onReceive(Context context, Intent intent)1040         public void onReceive(Context context, Intent intent) {
1041             if (mPhone.getPhoneId() != intent.getIntExtra(EXTRA_PROVISION_PHONE_ID,
1042                     SubscriptionManager.INVALID_PHONE_INDEX)) {
1043                 return;
1044             }
1045             // Turning back on the radio can take time on the order of a minute, so show user a
1046             // spinner so they know something is going on.
1047             log("onReceive : ProvisionNotificationBroadcastReceiver");
1048             mProvisioningSpinner = new ProgressDialog(context);
1049             mProvisioningSpinner.setTitle(mNetworkOperator);
1050             mProvisioningSpinner.setMessage(
1051                     // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version.
1052                     context.getText(com.android.internal.R.string.media_route_status_connecting));
1053             mProvisioningSpinner.setIndeterminate(true);
1054             mProvisioningSpinner.setCancelable(true);
1055             // Allow non-Activity Service Context to create a View.
1056             mProvisioningSpinner.getWindow().setType(
1057                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
1058             mProvisioningSpinner.show();
1059             // After timeout, hide spinner so user can at least use their device.
1060             // TODO: Indicate to user that it is taking an unusually long time to connect?
1061             sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER,
1062                     mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS);
1063             // This code is almost identical to the old
1064             // ConnectivityService.handleMobileProvisioningAction code.
1065             setRadio(true);
1066             setEnableFailFastMobileData(DctConstants.ENABLED);
1067             enableMobileProvisioning();
1068         }
1069     }
1070 
1071     @Override
finalize()1072     protected void finalize() {
1073         if(DBG && mPhone != null) log("finalize");
1074     }
1075 
initApnContexts()1076     private void initApnContexts() {
1077         PersistableBundle carrierConfig;
1078         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
1079                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
1080         if (configManager != null) {
1081             carrierConfig = configManager.getConfigForSubId(mPhone.getSubId());
1082         } else {
1083             carrierConfig = null;
1084         }
1085         initApnContexts(carrierConfig);
1086     }
1087 
1088     //Blows away any existing apncontexts that may exist, only use in ctor.
initApnContexts(PersistableBundle carrierConfig)1089     private void initApnContexts(PersistableBundle carrierConfig) {
1090         if (!mTelephonyManager.isDataCapable()) {
1091             log("initApnContexts: isDataCapable == false.  No Apn Contexts loaded");
1092             return;
1093         }
1094 
1095         log("initApnContexts: E");
1096         // Load device network attributes from resources
1097         final Collection<ApnConfigType> types =
1098                 new ApnConfigTypeRepository(carrierConfig).getTypes();
1099 
1100         for (ApnConfigType apnConfigType : types) {
1101             ApnContext apnContext = new ApnContext(mPhone, apnConfigType.getType(), mLogTag, this,
1102                     apnConfigType.getPriority());
1103             int bitmask = ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType());
1104             mPrioritySortedApnContexts.add(apnContext);
1105             mApnContexts.put(apnContext.getApnType(), apnContext);
1106             mApnContextsByType.put(bitmask, apnContext);
1107             // Notify listeners that all data is disconnected when DCT is initialized.
1108             // Once connections are established, DC will then notify that data is connected.
1109             // This is to prevent the case where the phone process crashed but we don't notify
1110             // listeners that data was disconnected, so they may be stuck in a connected state.
1111             mPhone.notifyDataConnection(new PreciseDataConnectionState.Builder()
1112                     .setTransportType(mTransportType)
1113                     .setState(TelephonyManager.DATA_DISCONNECTED)
1114                     .setApnSetting(new ApnSetting.Builder()
1115                             .setApnTypeBitmask(bitmask).buildWithoutCheck())
1116                     .setNetworkType(getDataRat())
1117                     .build());
1118             log("initApnContexts: apnContext=" + ApnSetting.getApnTypeString(
1119                     apnConfigType.getType()));
1120         }
1121         mPrioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority());
1122         logSortedApnContexts();
1123     }
1124 
sortApnContextByPriority()1125     private void sortApnContextByPriority() {
1126         if (!mTelephonyManager.isDataCapable()) {
1127             log("sortApnContextByPriority: isDataCapable == false.  No Apn Contexts loaded");
1128             return;
1129         }
1130 
1131         PersistableBundle carrierConfig;
1132         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
1133                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
1134         if (configManager != null) {
1135             carrierConfig = configManager.getConfigForSubId(mPhone.getSubId());
1136         } else {
1137             carrierConfig = null;
1138         }
1139 
1140         log("sortApnContextByPriority: E");
1141         // Load device network attributes from resources
1142         final Collection<ApnConfigType> types =
1143                 new ApnConfigTypeRepository(carrierConfig).getTypes();
1144         for (ApnConfigType apnConfigType : types) {
1145             if (mApnContextsByType.contains(apnConfigType.getType())) {
1146                 ApnContext apnContext = mApnContextsByType.get(apnConfigType.getType());
1147                 apnContext.setPriority(apnConfigType.getPriority());
1148             }
1149         }
1150 
1151         //Doing sorted in a different list to keep thread safety
1152         ArrayList<ApnContext> prioritySortedApnContexts =
1153                 new ArrayList<>(mPrioritySortedApnContexts);
1154         prioritySortedApnContexts.sort((c1, c2) -> c2.getPriority() - c1.getPriority());
1155         mPrioritySortedApnContexts = prioritySortedApnContexts;
1156         logSortedApnContexts();
1157     }
1158 
getLinkProperties(String apnType)1159     public LinkProperties getLinkProperties(String apnType) {
1160         ApnContext apnContext = mApnContexts.get(apnType);
1161         if (apnContext != null) {
1162             DataConnection dataConnection = apnContext.getDataConnection();
1163             if (dataConnection != null) {
1164                 if (DBG) log("return link properties for " + apnType);
1165                 return dataConnection.getLinkProperties();
1166             }
1167         }
1168         if (DBG) log("return new LinkProperties");
1169         return new LinkProperties();
1170     }
1171 
getNetworkCapabilities(String apnType)1172     public NetworkCapabilities getNetworkCapabilities(String apnType) {
1173         ApnContext apnContext = mApnContexts.get(apnType);
1174         if (apnContext!=null) {
1175             DataConnection dataConnection = apnContext.getDataConnection();
1176             if (dataConnection != null) {
1177                 if (DBG) {
1178                     log("get active pdp is not null, return NetworkCapabilities for " + apnType);
1179                 }
1180                 return dataConnection.getNetworkCapabilities();
1181             }
1182         }
1183         if (DBG) log("return new NetworkCapabilities");
1184         return new NetworkCapabilities();
1185     }
1186 
1187     // Return all active apn types
getActiveApnTypes()1188     public String[] getActiveApnTypes() {
1189         if (DBG) log("get all active apn types");
1190         ArrayList<String> result = new ArrayList<String>();
1191 
1192         for (ApnContext apnContext : mApnContexts.values()) {
1193             if (mAttached.get() && apnContext.isReady()) {
1194                 result.add(apnContext.getApnType());
1195             }
1196         }
1197 
1198         return result.toArray(new String[0]);
1199     }
1200 
1201     /**
1202      * Get ApnTypes with connected data connections.  This is different than getActiveApnTypes()
1203      * which returns apn types that with active apn contexts.
1204      * @return apn types
1205      */
getConnectedApnTypes()1206     public String[] getConnectedApnTypes() {
1207         return mApnContexts.values().stream()
1208                 .filter(ac -> ac.getState() == DctConstants.State.CONNECTED)
1209                 .map(ApnContext::getApnType)
1210                 .toArray(String[]::new);
1211     }
1212 
1213     @VisibleForTesting
getApnContexts()1214     public Collection<ApnContext> getApnContexts() {
1215         return mPrioritySortedApnContexts;
1216     }
1217 
1218     /** Return active ApnSetting of a specific apnType */
getActiveApnSetting(String apnType)1219     public ApnSetting getActiveApnSetting(String apnType) {
1220         if (VDBG) log("get active ApnSetting for type:" + apnType);
1221         ApnContext apnContext = mApnContexts.get(apnType);
1222         return (apnContext != null) ? apnContext.getApnSetting() : null;
1223     }
1224 
1225     // Return active apn of specific apn type
getActiveApnString(String apnType)1226     public String getActiveApnString(String apnType) {
1227         if (VDBG) log( "get active apn string for type:" + apnType);
1228         ApnSetting setting = getActiveApnSetting(apnType);
1229         return (setting != null) ? setting.getApnName() : null;
1230     }
1231 
1232     /**
1233      * Returns {@link DctConstants.State} based on the state of the {@link DataConnection} that
1234      * contains a {@link ApnSetting} that supported the given apn type {@code anpType}.
1235      *
1236      * <p>
1237      * Assumes there is less than one {@link ApnSetting} can support the given apn type.
1238      */
1239     // TODO: for enterprise this always returns IDLE, which is ok for now since it is never called
1240     // for enterprise
getState(String apnType)1241     public DctConstants.State getState(String apnType) {
1242         DctConstants.State state = DctConstants.State.IDLE;
1243         final int apnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(apnType);
1244         for (DataConnection dc : mDataConnections.values()) {
1245             ApnSetting apnSetting = dc.getApnSetting();
1246             if (apnSetting != null && apnSetting.canHandleType(apnTypeBitmask)) {
1247                 if (dc.isActive()) {
1248                     state = getBetterConnectionState(state, DctConstants.State.CONNECTED);
1249                 } else if (dc.isActivating()) {
1250                     state = getBetterConnectionState(state, DctConstants.State.CONNECTING);
1251                 } else if (dc.isInactive()) {
1252                     state = getBetterConnectionState(state, DctConstants.State.IDLE);
1253                 } else if (dc.isDisconnecting()) {
1254                     state = getBetterConnectionState(state, DctConstants.State.DISCONNECTING);
1255                 }
1256             }
1257         }
1258         return state;
1259     }
1260 
1261     /**
1262      * Return a better connection state between {@code stateA} and {@code stateB}. Check
1263      * {@link #DATA_CONNECTION_STATE_PRIORITIES} for the details.
1264      * @return the better connection state between {@code stateA} and {@code stateB}.
1265      */
getBetterConnectionState( DctConstants.State stateA, DctConstants.State stateB)1266     private static DctConstants.State getBetterConnectionState(
1267             DctConstants.State stateA, DctConstants.State stateB) {
1268         int idxA = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateA);
1269         int idxB = ArrayUtils.indexOf(DATA_CONNECTION_STATE_PRIORITIES, stateB);
1270         return idxA >= idxB ? stateA : stateB;
1271     }
1272 
1273     // Return if apn type is a provisioning apn.
isProvisioningApn(String apnType)1274     private boolean isProvisioningApn(String apnType) {
1275         ApnContext apnContext = mApnContexts.get(apnType);
1276         if (apnContext != null) {
1277             return apnContext.isProvisioningApn();
1278         }
1279         return false;
1280     }
1281 
1282     //****** Called from ServiceStateTracker
1283     /**
1284      * Invoked when ServiceStateTracker observes a transition from GPRS
1285      * attach to detach.
1286      */
onDataConnectionDetached()1287     private void onDataConnectionDetached() {
1288         /*
1289          * We presently believe it is unnecessary to tear down the PDP context
1290          * when GPRS detaches, but we should stop the network polling.
1291          */
1292         if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
1293         stopNetStatPoll();
1294         stopDataStallAlarm();
1295         mAttached.set(false);
1296     }
1297 
onDataConnectionAttached()1298     private void onDataConnectionAttached() {
1299         if (DBG) log("onDataConnectionAttached");
1300         mAttached.set(true);
1301         if (isAnyDataConnected()) {
1302             if (DBG) log("onDataConnectionAttached: start polling notify attached");
1303             startNetStatPoll();
1304             startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1305         }
1306         if (mAutoAttachOnCreationConfig) {
1307             mAutoAttachEnabled.set(true);
1308         }
1309         setupDataOnAllConnectableApns(Phone.REASON_DATA_ATTACHED, RetryFailures.ALWAYS);
1310     }
1311 
1312     /**
1313      * Check if it is allowed to make a data connection (without checking APN context specific
1314      * conditions).
1315      *
1316      * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output
1317      *                              param. It's okay to pass null here and no reasons will be
1318      *                              provided.
1319      * @return True if data connection is allowed, otherwise false.
1320      */
isDataAllowed(DataConnectionReasons dataConnectionReasons)1321     public boolean isDataAllowed(DataConnectionReasons dataConnectionReasons) {
1322         return isDataAllowed(null, REQUEST_TYPE_NORMAL, dataConnectionReasons);
1323     }
1324 
1325     /**
1326      * Check if it is allowed to make a data connection for a given APN type.
1327      *
1328      * @param apnContext APN context. If passing null, then will only check general but not APN
1329      *                   specific conditions (e.g. APN state, metered/unmetered APN).
1330      * @param requestType Setup data request type.
1331      * @param dataConnectionReasons Data connection allowed or disallowed reasons as the output
1332      *                              param. It's okay to pass null here and no reasons will be
1333      *                              provided.
1334      * @return True if data connection is allowed, otherwise false.
1335      */
isDataAllowed(ApnContext apnContext, @RequestNetworkType int requestType, DataConnectionReasons dataConnectionReasons)1336     public boolean isDataAllowed(ApnContext apnContext, @RequestNetworkType int requestType,
1337                                  DataConnectionReasons dataConnectionReasons) {
1338         // Step 1: Get all environment conditions.
1339         // Step 2: Special handling for emergency APN.
1340         // Step 3. Build disallowed reasons.
1341         // Step 4: Determine if data should be allowed in some special conditions.
1342 
1343         DataConnectionReasons reasons = new DataConnectionReasons();
1344 
1345         int requestApnType = 0;
1346         if (apnContext != null) {
1347             requestApnType = apnContext.getApnTypeBitmask();
1348         }
1349 
1350         // Step 1: Get all environment conditions.
1351         final boolean internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
1352         boolean attachedState = mAttached.get();
1353         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
1354         boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
1355         // TODO: Remove this hack added by ag/641832.
1356         int dataRat = getDataRat();
1357         if (dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
1358             desiredPowerState = true;
1359             radioStateFromCarrier = true;
1360         }
1361 
1362         boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(
1363                 SubscriptionManager.getDefaultDataSubscriptionId());
1364 
1365         boolean isMeteredApnType = apnContext == null
1366                 || ApnSettingUtils.isMeteredApnType(requestApnType, mPhone);
1367 
1368         PhoneConstants.State phoneState = PhoneConstants.State.IDLE;
1369         // Note this is explicitly not using mPhone.getState.  See b/19090488.
1370         // mPhone.getState reports the merge of CS and PS (volte) voice call state
1371         // but we only care about CS calls here for data/voice concurrency issues.
1372         // Calling getCallTracker currently gives you just the CS side where the
1373         // ImsCallTracker is held internally where applicable.
1374         // This should be redesigned to ask explicitly what we want:
1375         // voiceCallStateAllowDataCall, or dataCallAllowed or something similar.
1376         if (mPhone.getCallTracker() != null) {
1377             phoneState = mPhone.getCallTracker().getState();
1378         }
1379 
1380         // Step 2: Special handling for emergency APN.
1381         if (apnContext != null
1382                 && requestApnType == ApnSetting.TYPE_EMERGENCY
1383                 && apnContext.isConnectable()) {
1384             // If this is an emergency APN, as long as the APN is connectable, we
1385             // should allow it.
1386             if (dataConnectionReasons != null) {
1387                 dataConnectionReasons.add(DataAllowedReasonType.EMERGENCY_APN);
1388             }
1389             // Bail out without further checks.
1390             return true;
1391         }
1392 
1393         // Step 3. Build disallowed reasons.
1394         if (apnContext != null && !apnContext.isConnectable()) {
1395             DctConstants.State state = apnContext.getState();
1396             if (state == DctConstants.State.CONNECTED) {
1397                 reasons.add(DataDisallowedReasonType.DATA_ALREADY_CONNECTED);
1398             } else if (state == DctConstants.State.DISCONNECTING) {
1399                 reasons.add(DataDisallowedReasonType.DATA_IS_DISCONNECTING);
1400             } else if (state == DctConstants.State.CONNECTING) {
1401                 reasons.add(DataDisallowedReasonType.DATA_IS_CONNECTING);
1402             } else {
1403                 reasons.add(DataDisallowedReasonType.APN_NOT_CONNECTABLE);
1404             }
1405         }
1406 
1407         // In legacy mode, if RAT is IWLAN then don't allow default/IA PDP at all.
1408         // Rest of APN types can be evaluated for remaining conditions.
1409         if ((apnContext != null && requestApnType == ApnSetting.TYPE_DEFAULT
1410                 || requestApnType == ApnSetting.TYPE_ENTERPRISE
1411                 || requestApnType == ApnSetting.TYPE_IA)
1412                 && mPhone.getAccessNetworksManager().isInLegacyMode()
1413                 && dataRat == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
1414             reasons.add(DataDisallowedReasonType.ON_IWLAN);
1415         }
1416 
1417         // If device is not on NR, don't allow enterprise
1418         if (apnContext != null && requestApnType == ApnSetting.TYPE_ENTERPRISE
1419                 && dataRat != ServiceState.RIL_RADIO_TECHNOLOGY_NR) {
1420             reasons.add(DataDisallowedReasonType.NOT_ON_NR);
1421         }
1422 
1423         if (shouldRestrictDataForEcbm() || mPhone.isInEmergencyCall()) {
1424             reasons.add(DataDisallowedReasonType.IN_ECBM);
1425         }
1426 
1427         if (!attachedState && !shouldAutoAttach() && requestType != REQUEST_TYPE_HANDOVER) {
1428             reasons.add(DataDisallowedReasonType.NOT_ATTACHED);
1429         }
1430         if (mPhone.getSubId() == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1431             reasons.add(DataDisallowedReasonType.SIM_NOT_READY);
1432         }
1433         if (phoneState != PhoneConstants.State.IDLE
1434                 && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
1435             reasons.add(DataDisallowedReasonType.INVALID_PHONE_STATE);
1436             reasons.add(DataDisallowedReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
1437         }
1438         if (!internalDataEnabled) {
1439             reasons.add(DataDisallowedReasonType.INTERNAL_DATA_DISABLED);
1440         }
1441         if (!defaultDataSelected) {
1442             reasons.add(DataDisallowedReasonType.DEFAULT_DATA_UNSELECTED);
1443         }
1444         if (mPhone.getServiceState().getDataRoaming() && !getDataRoamingEnabled()) {
1445             reasons.add(DataDisallowedReasonType.ROAMING_DISABLED);
1446         }
1447         if (mIsPsRestricted) {
1448             reasons.add(DataDisallowedReasonType.PS_RESTRICTED);
1449         }
1450         if (!desiredPowerState) {
1451             reasons.add(DataDisallowedReasonType.UNDESIRED_POWER_STATE);
1452         }
1453         if (!radioStateFromCarrier) {
1454             reasons.add(DataDisallowedReasonType.RADIO_DISABLED_BY_CARRIER);
1455         }
1456         if (!mDataServiceBound) {
1457             reasons.add(DataDisallowedReasonType.DATA_SERVICE_NOT_READY);
1458         }
1459 
1460         if (apnContext != null) {
1461             if (mPhone.getAccessNetworksManager().getPreferredTransport(
1462                     apnContext.getApnTypeBitmask())
1463                     == AccessNetworkConstants.TRANSPORT_TYPE_INVALID) {
1464                 // If QNS explicitly specified this APN type is not allowed on either cellular or
1465                 // IWLAN, we should not allow data setup.
1466                 reasons.add(DataDisallowedReasonType.DISABLED_BY_QNS);
1467             } else if (mTransportType != mPhone.getAccessNetworksManager().getPreferredTransport(
1468                     apnContext.getApnTypeBitmask())) {
1469                 // If the latest preference has already switched to other transport, we should not
1470                 // allow data setup.
1471                 reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT);
1472             }
1473 
1474             // If the transport has been already switched to the other transport, we should not
1475             // allow the data setup. The only exception is the handover case, where we setup
1476             // handover data connection before switching the transport.
1477             if (mTransportType != mPhone.getAccessNetworksManager().getCurrentTransport(
1478                     apnContext.getApnTypeBitmask()) && requestType != REQUEST_TYPE_HANDOVER) {
1479                 reasons.add(DataDisallowedReasonType.ON_OTHER_TRANSPORT);
1480             }
1481 
1482             // Check if the device is under data throttling.
1483             long retryTime = mDataThrottler.getRetryTime(apnContext.getApnTypeBitmask());
1484             if (retryTime > SystemClock.elapsedRealtime()) {
1485                 reasons.add(DataDisallowedReasonType.DATA_THROTTLED);
1486             }
1487         }
1488 
1489         boolean isDataEnabled = apnContext == null ? mDataEnabledSettings.isDataEnabled()
1490                 : mDataEnabledSettings.isDataEnabled(requestApnType);
1491 
1492         if (!isDataEnabled) {
1493             reasons.add(DataDisallowedReasonType.DATA_DISABLED);
1494         }
1495 
1496         // If there are hard disallowed reasons, we should not allow data connection no matter what.
1497         if (reasons.containsHardDisallowedReasons()) {
1498             if (dataConnectionReasons != null) {
1499                 dataConnectionReasons.copyFrom(reasons);
1500             }
1501             return false;
1502         }
1503 
1504         // Step 4: Determine if data should be allowed in some special conditions.
1505 
1506         // At this point, if data is not allowed, it must be because of the soft reasons. We
1507         // should start to check some special conditions that data will be allowed.
1508         if (!reasons.allowed()) {
1509             // Check if the transport is WLAN ie wifi (for AP-assisted mode devices)
1510             if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
1511                 reasons.add(DataAllowedReasonType.UNMETERED_APN);
1512             // Or if the data is on cellular, and the APN type is determined unmetered by the
1513             // configuration.
1514             } else if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN
1515                     && !isMeteredApnType && requestApnType != ApnSetting.TYPE_DEFAULT
1516                     && requestApnType != ApnSetting.TYPE_ENTERPRISE) {
1517                 reasons.add(DataAllowedReasonType.UNMETERED_APN);
1518             }
1519 
1520             // If the request is restricted and there are only soft disallowed reasons (e.g. data
1521             // disabled, data roaming disabled) existing, we should allow the data. ENTERPRISE is
1522             // an exception and should not be treated as restricted for this purpose; it should be
1523             // treated same as DEFAULT.
1524             if (apnContext != null
1525                     && apnContext.hasRestrictedRequests(true)
1526                     && !apnContext.getApnType().equals(ApnSetting.TYPE_ENTERPRISE_STRING)
1527                     && !reasons.allowed()) {
1528                 reasons.add(DataAllowedReasonType.RESTRICTED_REQUEST);
1529             }
1530         } else {
1531             // If there is no disallowed reasons, then we should allow the data request with
1532             // normal reason.
1533             reasons.add(DataAllowedReasonType.NORMAL);
1534         }
1535 
1536         if (dataConnectionReasons != null) {
1537             dataConnectionReasons.copyFrom(reasons);
1538         }
1539 
1540         return reasons.allowed();
1541     }
1542 
1543     // arg for setupDataOnAllConnectableApns
1544     protected enum RetryFailures {
1545         // retry failed networks always (the old default)
1546         ALWAYS,
1547         // retry only when a substantial change has occurred.  Either:
1548         // 1) we were restricted by voice/data concurrency and aren't anymore
1549         // 2) our apn list has change
1550         ONLY_ON_CHANGE
1551     };
1552 
setupDataOnAllConnectableApns(String reason, RetryFailures retryFailures)1553     protected void setupDataOnAllConnectableApns(String reason, RetryFailures retryFailures) {
1554         if (VDBG) log("setupDataOnAllConnectableApns: " + reason);
1555 
1556         if (DBG && !VDBG) {
1557             StringBuilder sb = new StringBuilder(120);
1558             for (ApnContext apnContext : mPrioritySortedApnContexts) {
1559                 sb.append(apnContext.getApnType());
1560                 sb.append(":[state=");
1561                 sb.append(apnContext.getState());
1562                 sb.append(",enabled=");
1563                 sb.append(apnContext.isEnabled());
1564                 sb.append("] ");
1565             }
1566             log("setupDataOnAllConnectableApns: " + reason + " " + sb);
1567         }
1568 
1569         for (ApnContext apnContext : mPrioritySortedApnContexts) {
1570             setupDataOnConnectableApn(apnContext, reason, retryFailures);
1571         }
1572     }
1573 
setupDataOnConnectableApn(ApnContext apnContext, String reason, RetryFailures retryFailures)1574     protected void setupDataOnConnectableApn(ApnContext apnContext, String reason,
1575             RetryFailures retryFailures) {
1576         if (VDBG) log("setupDataOnAllConnectableApns: apnContext " + apnContext);
1577 
1578         if (apnContext.getState() == DctConstants.State.FAILED
1579                 || apnContext.getState() == DctConstants.State.RETRYING) {
1580             if (retryFailures == RetryFailures.ALWAYS) {
1581                 apnContext.releaseDataConnection(reason);
1582             } else if (!apnContext.isConcurrentVoiceAndDataAllowed()
1583                     && mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
1584                 // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed
1585                 apnContext.releaseDataConnection(reason);
1586             }
1587         }
1588         if (apnContext.isConnectable()) {
1589             log("isConnectable() call trySetupData");
1590             apnContext.setReason(reason);
1591             trySetupData(apnContext, REQUEST_TYPE_NORMAL, null);
1592         }
1593     }
1594 
shouldRestrictDataForEcbm()1595     private boolean shouldRestrictDataForEcbm() {
1596         boolean isInEcm = mPhone.isInEcm();
1597         boolean isInImsEcm = mPhone.getImsPhone() != null && mPhone.getImsPhone().isInImsEcm();
1598         log("shouldRestrictDataForEcbm: isInEcm=" + isInEcm + " isInImsEcm=" + isInImsEcm);
1599         return isInEcm && !isInImsEcm;
1600     }
1601 
isHandoverPending(@pnType int apnType)1602     private boolean isHandoverPending(@ApnType int apnType) {
1603         List<Message> messageList = mHandoverCompletionMsgs.get(apnType);
1604         return messageList != null && messageList.size() > 0;
1605     }
1606 
trySetupData(ApnContext apnContext, @RequestNetworkType int requestType, @Nullable Message onHandoverCompleteMsg)1607     private void trySetupData(ApnContext apnContext, @RequestNetworkType int requestType,
1608             @Nullable Message onHandoverCompleteMsg) {
1609         if (onHandoverCompleteMsg != null) {
1610             addHandoverCompleteMsg(onHandoverCompleteMsg, apnContext.getApnTypeBitmask());
1611         }
1612 
1613         if (mPhone.getSimulatedRadioControl() != null) {
1614             // Assume data is connected on the simulator
1615             log("trySetupData: X We're on the simulator; assuming connected retValue=true");
1616             return;
1617         }
1618 
1619         DataConnectionReasons dataConnectionReasons = new DataConnectionReasons();
1620         boolean isDataAllowed = isDataAllowed(apnContext, requestType, dataConnectionReasons);
1621         String logStr = "trySetupData for APN type " + apnContext.getApnType() + ", reason: "
1622                 + apnContext.getReason() + ", requestType=" + requestTypeToString(requestType)
1623                 + ". " + dataConnectionReasons.toString();
1624         if (dataConnectionReasons.contains(DataDisallowedReasonType.DISABLED_BY_QNS)
1625                 || dataConnectionReasons.contains(DataDisallowedReasonType.ON_OTHER_TRANSPORT)) {
1626             logStr += ", current transport=" + AccessNetworkConstants.transportTypeToString(
1627                     mPhone.getAccessNetworksManager().getCurrentTransport(
1628                             apnContext.getApnTypeBitmask()));
1629             logStr += ", preferred transport=" + AccessNetworkConstants.transportTypeToString(
1630                     mPhone.getAccessNetworksManager().getPreferredTransport(
1631                             apnContext.getApnTypeBitmask()));
1632         }
1633         if (DBG) log(logStr);
1634         ApnContext.requestLog(apnContext, logStr);
1635         if (!isDataAllowed) {
1636             StringBuilder str = new StringBuilder();
1637 
1638             str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType()
1639                     + ", mState=" + apnContext.getState() + ", apnEnabled="
1640                     + apnContext.isEnabled() + ", mDependencyMet="
1641                     + apnContext.isDependencyMet() + "] ");
1642 
1643             if (!mDataEnabledSettings.isDataEnabled()) {
1644                 str.append("isDataEnabled() = false. " + mDataEnabledSettings);
1645             }
1646 
1647             // Check if it fails because of the existing data is still disconnecting.
1648             if (dataConnectionReasons.contains(DataDisallowedReasonType.DATA_IS_DISCONNECTING)
1649                     && isHandoverPending(apnContext.getApnTypeBitmask())) {
1650                 // Normally we don't retry when isDataAllow() returns false, because that's consider
1651                 // pre-condition not met, for example, data not enabled by the user, or airplane
1652                 // mode is on. If we retry in those cases, there will be significant power impact.
1653                 // DATA_IS_DISCONNECTING is a special case we want to retry, and for the handover
1654                 // case only.
1655                 log("Data is disconnecting. Will retry handover later.");
1656                 return;
1657             }
1658 
1659             // If this is a data retry, we should set the APN state to FAILED so it won't stay
1660             // in RETRYING forever.
1661             if (apnContext.getState() == DctConstants.State.RETRYING) {
1662                 apnContext.setState(DctConstants.State.FAILED);
1663                 str.append(" Stop retrying.");
1664             }
1665 
1666             if (DBG) log(str.toString());
1667             ApnContext.requestLog(apnContext, str.toString());
1668             if (requestType == REQUEST_TYPE_HANDOVER) {
1669                 // If fails due to latest preference already changed back to source transport, then
1670                 // just fallback (will not attempt handover anymore, and will not tear down the
1671                 // data connection on source transport.
1672                 boolean fallback = dataConnectionReasons.contains(
1673                         DataDisallowedReasonType.ON_OTHER_TRANSPORT);
1674                 sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, fallback);
1675             }
1676             return;
1677         }
1678 
1679         if (apnContext.getState() == DctConstants.State.FAILED) {
1680             String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
1681             if (DBG) log(str);
1682             ApnContext.requestLog(apnContext, str);
1683             apnContext.setState(DctConstants.State.IDLE);
1684         }
1685         int radioTech = getDataRat();
1686         if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN && mPhone.getServiceState()
1687                 .getState() == ServiceState.STATE_IN_SERVICE) {
1688             radioTech = getVoiceRat();
1689         }
1690         log("service state=" + mPhone.getServiceState());
1691         apnContext.setConcurrentVoiceAndDataAllowed(mPhone.getServiceStateTracker()
1692                 .isConcurrentVoiceAndDataAllowed());
1693         if (apnContext.getState() == DctConstants.State.IDLE) {
1694             ArrayList<ApnSetting> waitingApns =
1695                     buildWaitingApns(apnContext.getApnType(), radioTech);
1696             if (waitingApns.isEmpty()) {
1697                 String str = "trySetupData: X No APN found retValue=false";
1698                 if (DBG) log(str);
1699                 ApnContext.requestLog(apnContext, str);
1700                 if (requestType == REQUEST_TYPE_HANDOVER) {
1701                     sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false,
1702                             false);
1703                 }
1704                 return;
1705             } else {
1706                 apnContext.setWaitingApns(waitingApns);
1707                 if (DBG) {
1708                     log("trySetupData: Create from mAllApnSettings : "
1709                                 + apnListToString(mAllApnSettings));
1710                 }
1711             }
1712         }
1713 
1714         if (!setupData(apnContext, radioTech, requestType)
1715                 && requestType == REQUEST_TYPE_HANDOVER) {
1716             sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false);
1717         }
1718     }
1719 
1720     /**
1721      * Clean up all data connections. Note this is just detach the APN context from the data
1722      * connection. After all APN contexts are detached from the data connection, the data
1723      * connection will be torn down.
1724      *
1725      * @param reason Reason for the clean up.
1726      */
cleanUpAllConnections(String reason)1727     public void cleanUpAllConnections(String reason) {
1728         log("cleanUpAllConnections");
1729         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
1730         msg.obj = reason;
1731         sendMessage(msg);
1732     }
1733 
1734     /**
1735      * Clean up all data connections by detaching the APN contexts from the data connections, which
1736      * eventually tearing down all data connections after all APN contexts are detached from the
1737      * data connections.
1738      *
1739      * @param detach {@code true} if detaching APN context from the underlying data connection (when
1740      * no other APN context is attached to the data connection, the data connection will be torn
1741      * down.) {@code false} to only reset the data connection's state machine.
1742      *
1743      * @param reason reason for the clean up.
1744      * @return boolean - true if we did cleanup any connections, false if they
1745      *                   were already all disconnected.
1746      */
cleanUpAllConnectionsInternal(boolean detach, String reason)1747     private boolean cleanUpAllConnectionsInternal(boolean detach, String reason) {
1748         if (DBG) log("cleanUpAllConnectionsInternal: detach=" + detach + " reason=" + reason);
1749         boolean didDisconnect = false;
1750         boolean disableMeteredOnly = false;
1751 
1752         // reasons that only metered apn will be torn down
1753         if (!TextUtils.isEmpty(reason)) {
1754             disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) ||
1755                     reason.equals(Phone.REASON_ROAMING_ON) ||
1756                     reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
1757         }
1758 
1759         for (ApnContext apnContext : mApnContexts.values()) {
1760             // Exclude the IMS APN from single data connection case.
1761             if (reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION)
1762                     && apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) {
1763                 continue;
1764             }
1765 
1766             if (shouldCleanUpConnection(apnContext, disableMeteredOnly,
1767                     reason.equals(Phone.REASON_SINGLE_PDN_ARBITRATION))) {
1768                 // TODO - only do cleanup if not disconnected
1769                 if (apnContext.isDisconnected() == false) didDisconnect = true;
1770                 apnContext.setReason(reason);
1771                 cleanUpConnectionInternal(detach, RELEASE_TYPE_DETACH, apnContext);
1772             } else if (DBG) {
1773                 log("cleanUpAllConnectionsInternal: APN type " + apnContext.getApnType()
1774                         + " shouldn't be cleaned up.");
1775             }
1776         }
1777 
1778         stopNetStatPoll();
1779         stopDataStallAlarm();
1780 
1781         // TODO: Do we need mRequestedApnType?
1782         mRequestedApnType = ApnSetting.TYPE_DEFAULT;
1783 
1784         if (areAllDataDisconnected()) {
1785             notifyAllDataDisconnected();
1786         }
1787 
1788         return didDisconnect;
1789     }
1790 
shouldCleanUpConnection(ApnContext apnContext, boolean disableMeteredOnly, boolean singlePdn)1791     boolean shouldCleanUpConnection(ApnContext apnContext, boolean disableMeteredOnly,
1792             boolean singlePdn) {
1793         if (apnContext == null) return false;
1794 
1795         // If APN setting is not null and the reason is single PDN arbitration, clean up connection.
1796         ApnSetting apnSetting = apnContext.getApnSetting();
1797         if (apnSetting != null && singlePdn) return true;
1798 
1799         // If meteredOnly is false, clean up all connections.
1800         if (!disableMeteredOnly) return true;
1801 
1802         // If meteredOnly is true, and apnSetting is null or it's un-metered, no need to clean up.
1803         if (apnSetting == null || !ApnSettingUtils.isMetered(apnSetting, mPhone)) return false;
1804 
1805         boolean isRoaming = mPhone.getServiceState().getDataRoaming();
1806         boolean isDataRoamingDisabled = !getDataRoamingEnabled();
1807         boolean isDataDisabled = !mDataEnabledSettings.isDataEnabled(
1808                 apnSetting.getApnTypeBitmask());
1809 
1810         // Should clean up if its data is disabled, or data roaming is disabled while roaming.
1811         return isDataDisabled || (isRoaming && isDataRoamingDisabled);
1812     }
1813 
1814     /**
1815      * Detach the APN context from the associated data connection. This data connection might be
1816      * torn down if no other APN context is attached to it.
1817      *
1818      * @param apnContext The APN context to be detached
1819      */
cleanUpConnection(ApnContext apnContext)1820     void cleanUpConnection(ApnContext apnContext) {
1821         if (DBG) log("cleanUpConnection: apnContext=" + apnContext);
1822         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
1823         msg.arg2 = 0;
1824         msg.obj = apnContext;
1825         sendMessage(msg);
1826     }
1827 
1828     /**
1829      * Detach the APN context from the associated data connection. This data connection will be
1830      * torn down if no other APN context is attached to it.
1831      *
1832      * @param detach {@code true} if detaching APN context from the underlying data connection (when
1833      * no other APN context is attached to the data connection, the data connection will be torn
1834      * down.) {@code false} to only reset the data connection's state machine.
1835      * @param releaseType Data release type.
1836      * @param apnContext The APN context to be detached.
1837      */
cleanUpConnectionInternal(boolean detach, @ReleaseNetworkType int releaseType, ApnContext apnContext)1838     private void cleanUpConnectionInternal(boolean detach, @ReleaseNetworkType int releaseType,
1839                                            ApnContext apnContext) {
1840         if (apnContext == null) {
1841             if (DBG) log("cleanUpConnectionInternal: apn context is null");
1842             return;
1843         }
1844 
1845         DataConnection dataConnection = apnContext.getDataConnection();
1846         String str = "cleanUpConnectionInternal: detach=" + detach + " reason="
1847                 + apnContext.getReason();
1848         if (VDBG) log(str + " apnContext=" + apnContext);
1849         ApnContext.requestLog(apnContext, str);
1850         if (detach) {
1851             if (apnContext.isDisconnected()) {
1852                 // The request is detach and but ApnContext is not connected.
1853                 // If apnContext is not enabled anymore, break the linkage to the data connection.
1854                 apnContext.releaseDataConnection("");
1855             } else {
1856                 // Connection is still there. Try to clean up.
1857                 if (dataConnection != null) {
1858                     if (apnContext.getState() != DctConstants.State.DISCONNECTING) {
1859                         boolean disconnectAll = false;
1860                         if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType())
1861                                 && ServiceState.isCdma(getDataRat())) {
1862                             if (DBG) {
1863                                 log("cleanUpConnectionInternal: disconnectAll DUN connection");
1864                             }
1865                             // For CDMA DUN, we need to tear it down immediately. A new data
1866                             // connection will be reestablished with correct profile id.
1867                             disconnectAll = true;
1868                         }
1869                         final int generation = apnContext.getConnectionGeneration();
1870                         str = "cleanUpConnectionInternal: tearing down"
1871                                 + (disconnectAll ? " all" : "") + " using gen#" + generation;
1872                         if (DBG) log(str + "apnContext=" + apnContext);
1873                         ApnContext.requestLog(apnContext, str);
1874                         Pair<ApnContext, Integer> pair = new Pair<>(apnContext, generation);
1875                         Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
1876 
1877                         if (disconnectAll || releaseType == RELEASE_TYPE_HANDOVER) {
1878                             dataConnection.tearDownAll(apnContext.getReason(), releaseType, msg);
1879                         } else {
1880                             dataConnection.tearDown(apnContext, apnContext.getReason(), msg);
1881                         }
1882 
1883                         apnContext.setState(DctConstants.State.DISCONNECTING);
1884                     }
1885                 } else {
1886                     // apn is connected but no reference to the data connection.
1887                     // Should not be happen, but reset the state in case.
1888                     apnContext.setState(DctConstants.State.IDLE);
1889                     ApnContext.requestLog(
1890                             apnContext, "cleanUpConnectionInternal: connected, bug no dc");
1891                 }
1892             }
1893         } else {
1894             // force clean up the data connection.
1895             if (dataConnection != null) dataConnection.reset();
1896             apnContext.setState(DctConstants.State.IDLE);
1897             apnContext.setDataConnection(null);
1898         }
1899 
1900         // If there is any outstanding handover request, we need to respond it.
1901         sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false, false);
1902 
1903         // Make sure reconnection alarm is cleaned up if there is no ApnContext
1904         // associated to the connection.
1905         if (dataConnection != null) {
1906             cancelReconnect(apnContext);
1907         }
1908         str = "cleanUpConnectionInternal: X detach=" + detach + " reason="
1909                 + apnContext.getReason();
1910         if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
1911     }
1912 
getPreferredApnCursor(int subId)1913     private Cursor getPreferredApnCursor(int subId) {
1914         Cursor cursor = null;
1915         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1916             cursor = mPhone.getContext().getContentResolver().query(
1917                     Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID,
1918                             String.valueOf(subId)), null, null, null,
1919                     Telephony.Carriers.DEFAULT_SORT_ORDER);
1920         }
1921         return cursor;
1922     }
1923 
getPreferredApnFromDB()1924     private ApnSetting getPreferredApnFromDB() {
1925         ApnSetting preferredApn = null;
1926         Cursor cursor = getPreferredApnCursor(mPhone.getSubId());
1927         if (cursor != null) {
1928             if (cursor.getCount() > 0) {
1929                 cursor.moveToFirst();
1930                 preferredApn = ApnSetting.makeApnSetting(cursor);
1931             }
1932             cursor.close();
1933         }
1934         if (VDBG) log("getPreferredApnFromDB: preferredApn=" + preferredApn);
1935         return preferredApn;
1936     }
1937 
setDefaultPreferredApnIfNeeded()1938     private void setDefaultPreferredApnIfNeeded() {
1939         ApnSetting defaultPreferredApn = null;
1940         PersistableBundle bundle = getCarrierConfig();
1941         String defaultPreferredApnName = bundle.getString(CarrierConfigManager
1942                 .KEY_DEFAULT_PREFERRED_APN_NAME_STRING);
1943 
1944         if (TextUtils.isEmpty(defaultPreferredApnName) || getPreferredApnFromDB() != null) {
1945             return;
1946         }
1947 
1948         String selection = Telephony.Carriers.APN + " = \"" + defaultPreferredApnName + "\" AND "
1949                 + Telephony.Carriers.EDITED_STATUS + " = " + Telephony.Carriers.UNEDITED;
1950         Cursor cursor = mPhone.getContext().getContentResolver().query(
1951                 Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI,
1952                         "filtered/subId/" + mPhone.getSubId()),
1953                 null, selection, null, Telephony.Carriers._ID);
1954 
1955         if (cursor != null) {
1956             if (cursor.getCount() > 0) {
1957                 if (cursor.moveToFirst()) {
1958                     defaultPreferredApn = ApnSetting.makeApnSetting(cursor);
1959                 }
1960             }
1961             cursor.close();
1962         }
1963 
1964         if (defaultPreferredApn != null
1965                 && defaultPreferredApn.canHandleType(mRequestedApnType)) {
1966             log("setDefaultPreferredApnIfNeeded: For APN type "
1967                     + ApnSetting.getApnTypeString(mRequestedApnType)
1968                     + " found default apnSetting "
1969                     + defaultPreferredApn);
1970 
1971             setPreferredApn(defaultPreferredApn.getId(), true);
1972         }
1973 
1974         return;
1975     }
1976 
1977     /**
1978      * Check if preferred apn is allowed to edit by user.
1979      * @return {@code true} if it is allowed to edit.
1980      */
1981     @VisibleForTesting
isPreferredApnUserEdited()1982     public boolean isPreferredApnUserEdited() {
1983         boolean isUserEdited = false;
1984         Cursor cursor = getPreferredApnCursor(mPhone.getSubId());
1985         if (cursor != null) {
1986             if (cursor.getCount() > 0) {
1987                 if (cursor.moveToFirst()) {
1988                     isUserEdited = cursor.getInt(
1989                             cursor.getColumnIndexOrThrow(Telephony.Carriers.EDITED_STATUS))
1990                             == Telephony.Carriers.USER_EDITED;
1991                 }
1992             }
1993             cursor.close();
1994         }
1995         if (VDBG) log("isPreferredApnUserEdited: isUserEdited=" + isUserEdited);
1996         return isUserEdited;
1997     }
1998 
1999     /**
2000      * Fetch the DUN apns
2001      * @return a list of DUN ApnSetting objects
2002      */
2003     @VisibleForTesting
fetchDunApns()2004     public @NonNull ArrayList<ApnSetting> fetchDunApns() {
2005         if (mPhone.getServiceState().getRoaming() && !isPreferredApnUserEdited()
2006                 && getCarrierConfig().getBoolean(CarrierConfigManager
2007                 .KEY_DISABLE_DUN_APN_WHILE_ROAMING_WITH_PRESET_APN_BOOL)) {
2008             if (VDBG) log("fetchDunApns: Dun apn is not used in roaming network");
2009             return new ArrayList<ApnSetting>(0);
2010         }
2011 
2012         int bearer = getDataRat();
2013         ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
2014         ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
2015 
2016         if (dunCandidates.isEmpty()) {
2017             if (!ArrayUtils.isEmpty(mAllApnSettings)) {
2018                 for (ApnSetting apn : mAllApnSettings) {
2019                     if (apn.canHandleType(ApnSetting.TYPE_DUN)) {
2020                         dunCandidates.add(apn);
2021                     }
2022                 }
2023                 if (VDBG) log("fetchDunApns: dunCandidates from database: " + dunCandidates);
2024             }
2025         }
2026 
2027         int preferredApnSetId = getPreferredApnSetId();
2028         ApnSetting preferredApn = getPreferredApnFromDB();
2029         for (ApnSetting dunSetting : dunCandidates) {
2030             if (dunSetting.canSupportNetworkType(
2031                     ServiceState.rilRadioTechnologyToNetworkType(bearer))) {
2032                 if (preferredApnSetId == dunSetting.getApnSetId()) {
2033                     if (preferredApn != null && preferredApn.equals(dunSetting)) {
2034                         // If there is a preferred APN can handled DUN type, prepend it to list to
2035                         // use it preferred.
2036                         retDunSettings.add(0, dunSetting);
2037                     } else {
2038                         retDunSettings.add(dunSetting);
2039                     }
2040                 }
2041             }
2042         }
2043 
2044         if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings);
2045         return retDunSettings;
2046     }
2047 
getPreferredApnSetId()2048     private int getPreferredApnSetId() {
2049         // preferapnset uri returns all APNs for the current carrier which have an apn_set_id
2050         // equal to the preferred APN (if no preferred APN, or if the preferred APN has no set id,
2051         // the query will return null)
2052         Cursor c = mPhone.getContext().getContentResolver()
2053                 .query(Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI,
2054                     "preferapnset/subId/" + mPhone.getSubId()),
2055                         new String[] {Telephony.Carriers.APN_SET_ID}, null, null, null);
2056         if (c == null) {
2057             loge("getPreferredApnSetId: cursor is null");
2058             return Telephony.Carriers.NO_APN_SET_ID;
2059         }
2060 
2061         int setId;
2062         if (c.getCount() < 1) {
2063             loge("getPreferredApnSetId: no APNs found");
2064             setId = Telephony.Carriers.NO_APN_SET_ID;
2065         } else {
2066             c.moveToFirst();
2067             setId = c.getInt(0 /* index of Telephony.Carriers.APN_SET_ID */);
2068         }
2069 
2070         if (!c.isClosed()) {
2071             c.close();
2072         }
2073         return setId;
2074     }
2075 
hasMatchedTetherApnSetting()2076     public boolean hasMatchedTetherApnSetting() {
2077         ArrayList<ApnSetting> matches = fetchDunApns();
2078         log("hasMatchedTetherApnSetting: APNs=" + matches);
2079         return matches.size() > 0;
2080     }
2081 
2082     /**
2083      * @return the {@link DataConnection} with the given context id {@code cid}.
2084      */
getDataConnectionByContextId(int cid)2085     public DataConnection getDataConnectionByContextId(int cid) {
2086         return mDcc.getActiveDcByCid(cid);
2087     }
2088 
2089     /**
2090      * @return the {@link DataConnection} with the given APN context. Null if no data connection
2091      * is found.
2092      */
getDataConnectionByApnType(String apnType)2093     public @Nullable DataConnection getDataConnectionByApnType(String apnType) {
2094         // TODO: Clean up all APN type in string usage
2095         ApnContext apnContext = mApnContexts.get(apnType);
2096         if (apnContext != null) {
2097             return apnContext.getDataConnection();
2098         }
2099         return null;
2100     }
2101 
2102     /**
2103      * Check if the data fail cause is a permanent failure (i.e. Frameworks will not retry data
2104      * setup).
2105      *
2106      * @param dcFailCause The data fail cause
2107      * @return {@code true} if the data fail cause is a permanent failure.
2108      */
2109     @VisibleForTesting
isPermanentFailure(@ataFailureCause int dcFailCause)2110     public boolean isPermanentFailure(@DataFailureCause int dcFailCause) {
2111         return (DataFailCause.isPermanentFailure(mPhone.getContext(), dcFailCause,
2112                 mPhone.getSubId())
2113                 && (mAttached.get() == false || dcFailCause != DataFailCause.SIGNAL_LOST));
2114     }
2115 
findFreeDataConnection()2116     private DataConnection findFreeDataConnection() {
2117         for (DataConnection dataConnection : mDataConnections.values()) {
2118             boolean inUse = false;
2119             for (ApnContext apnContext : mApnContexts.values()) {
2120                 if (apnContext.getDataConnection() == dataConnection) {
2121                     inUse = true;
2122                     break;
2123                 }
2124             }
2125             if (!inUse) {
2126                 if (DBG) {
2127                     log("findFreeDataConnection: found free DataConnection=" + dataConnection);
2128                 }
2129                 return dataConnection;
2130             }
2131         }
2132         log("findFreeDataConnection: NO free DataConnection");
2133         return null;
2134     }
2135 
2136     /**
2137      * Setup a data connection based on given APN type.
2138      *
2139      * @param apnContext APN context
2140      * @param radioTech RAT of the data connection
2141      * @param requestType Data request type
2142      * @return True if successful, otherwise false.
2143      */
setupData(ApnContext apnContext, int radioTech, @RequestNetworkType int requestType)2144     private boolean setupData(ApnContext apnContext, int radioTech,
2145                               @RequestNetworkType int requestType) {
2146         if (DBG) {
2147             log("setupData: apnContext=" + apnContext + ", requestType="
2148                     + requestTypeToString(requestType));
2149         }
2150         ApnContext.requestLog(
2151                 apnContext, "setupData. requestType=" + requestTypeToString(requestType));
2152         ApnSetting apnSetting;
2153         DataConnection dataConnection = null;
2154 
2155         apnSetting = apnContext.getNextApnSetting();
2156 
2157         if (apnSetting == null) {
2158             if (DBG) log("setupData: return for no apn found!");
2159             return false;
2160         }
2161 
2162         // profile id is only meaningful when the profile is persistent on the modem.
2163         int profileId = DATA_PROFILE_INVALID;
2164         if (apnSetting.isPersistent()) {
2165             profileId = apnSetting.getProfileId();
2166             if (profileId == DATA_PROFILE_DEFAULT) {
2167                 profileId = getApnProfileID(apnContext.getApnType());
2168             }
2169         }
2170 
2171         // On CDMA, if we're explicitly asking for DUN, we need have
2172         // a dun-profiled connection so we can't share an existing one
2173         // On GSM/LTE we can share existing apn connections provided they support
2174         // this type.
2175         // If asking for ENTERPRISE, there are no compatible data connections, so skip this check
2176         if ((apnContext.getApnTypeBitmask() != ApnSetting.TYPE_DUN
2177                 || ServiceState.isGsm(getDataRat()))
2178                 && apnContext.getApnTypeBitmask() != ApnSetting.TYPE_ENTERPRISE) {
2179             dataConnection = checkForCompatibleDataConnection(apnContext, apnSetting);
2180             if (dataConnection != null) {
2181                 // Get the apn setting used by the data connection
2182                 ApnSetting dataConnectionApnSetting = dataConnection.getApnSetting();
2183                 if (dataConnectionApnSetting != null) {
2184                     // Setting is good, so use it.
2185                     apnSetting = dataConnectionApnSetting;
2186                 }
2187             }
2188         }
2189         if (dataConnection == null) {
2190             if (isOnlySingleDcAllowed(radioTech)) {
2191                 if (isHigherPriorityApnContextActive(apnContext)) {
2192                     if (DBG) {
2193                         log("setupData: Higher priority ApnContext active.  Ignoring call");
2194                     }
2195                     return false;
2196                 }
2197 
2198                 // Should not start cleanUp if the setupData is for IMS APN
2199                 // or retry of same APN(State==RETRYING).
2200                 if (!apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)
2201                         && (apnContext.getState() != DctConstants.State.RETRYING)) {
2202                     // Only lower priority calls left.  Disconnect them all in this single PDP case
2203                     // so that we can bring up the requested higher priority call (once we receive
2204                     // response for deactivate request for the calls we are about to disconnect
2205                     if (cleanUpAllConnectionsInternal(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
2206                         // If any call actually requested to be disconnected, means we can't
2207                         // bring up this connection yet as we need to wait for those data calls
2208                         // to be disconnected.
2209                         if (DBG) log("setupData: Some calls are disconnecting first."
2210                                 + " Wait and retry");
2211                         return false;
2212                     }
2213                 }
2214 
2215                 // No other calls are active, so proceed
2216                 if (DBG) log("setupData: Single pdp. Continue setting up data call.");
2217             }
2218 
2219             dataConnection = findFreeDataConnection();
2220 
2221             if (dataConnection == null) {
2222                 dataConnection = createDataConnection();
2223             }
2224 
2225             if (dataConnection == null) {
2226                 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
2227                 return false;
2228             }
2229         }
2230         final int generation = apnContext.incAndGetConnectionGeneration();
2231         if (DBG) {
2232             log("setupData: dc=" + dataConnection + " apnSetting=" + apnSetting + " gen#="
2233                     + generation);
2234         }
2235 
2236         apnContext.setDataConnection(dataConnection);
2237         apnContext.setApnSetting(apnSetting);
2238         apnContext.setState(DctConstants.State.CONNECTING);
2239 
2240         Message msg = obtainMessage();
2241         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
2242         msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
2243 
2244         ApnSetting preferredApn = getPreferredApn();
2245         boolean isPreferredApn = apnSetting.equals(preferredApn);
2246         dataConnection.bringUp(apnContext, profileId, radioTech, msg, generation, requestType,
2247                 mPhone.getSubId(), isPreferredApn);
2248 
2249         if (DBG) {
2250             if (isPreferredApn) {
2251                 log("setupData: initing! isPreferredApn=" + isPreferredApn
2252                         + ", apnSetting={" + apnSetting.toString() + "}");
2253             } else {
2254                 String preferredApnStr = preferredApn == null ? "null" : preferredApn.toString();
2255                 log("setupData: initing! isPreferredApn=" + isPreferredApn
2256                         + ", apnSetting={" + apnSetting + "}"
2257                         + ", preferredApn={" + preferredApnStr + "}");
2258             }
2259         }
2260         return true;
2261     }
2262 
2263     // Get the allowed APN types for initial attach. The order in the returned list represent
2264     // the order of APN types that should be used for initial attach.
getAllowedInitialAttachApnTypes()2265     private @NonNull @ApnType List<Integer> getAllowedInitialAttachApnTypes() {
2266         PersistableBundle bundle = getCarrierConfig();
2267         if (bundle != null) {
2268             String[] apnTypesArray = bundle.getStringArray(
2269                     CarrierConfigManager.KEY_ALLOWED_INITIAL_ATTACH_APN_TYPES_STRING_ARRAY);
2270             if (apnTypesArray != null) {
2271                 return Arrays.stream(apnTypesArray)
2272                         .map(ApnSetting::getApnTypesBitmaskFromString)
2273                         .collect(Collectors.toList());
2274             }
2275         }
2276 
2277         return Collections.emptyList();
2278     }
2279 
setInitialAttachApn()2280     protected void setInitialAttachApn() {
2281         ApnSetting apnSetting = null;
2282         int preferredApnSetId = getPreferredApnSetId();
2283         ArrayList<ApnSetting> allApnSettings = new ArrayList<>();
2284         if (mPreferredApn != null) {
2285             // Put the preferred apn at the beginning of the list. It's okay to have a duplicate
2286             // when later on mAllApnSettings get added. That would not change the selection result.
2287             allApnSettings.add(mPreferredApn);
2288         }
2289         allApnSettings.addAll(mAllApnSettings);
2290 
2291         // Get the allowed APN types for initial attach. Note that if none of the APNs has the
2292         // allowed APN types, then the initial attach will not be performed.
2293         List<Integer> allowedApnTypes = getAllowedInitialAttachApnTypes();
2294         for (int allowedApnType : allowedApnTypes) {
2295             apnSetting = allApnSettings.stream()
2296                     .filter(apn -> apn.canHandleType(allowedApnType))
2297                     .filter(apn -> (apn.getApnSetId() == preferredApnSetId
2298                             || apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID))
2299                     .findFirst()
2300                     .orElse(null);
2301             if (apnSetting != null) break;
2302         }
2303 
2304         if (DBG) {
2305             log("setInitialAttachApn: Allowed APN types=" + allowedApnTypes.stream()
2306                     .map(ApnSetting::getApnTypeString)
2307                     .collect(Collectors.joining(",")));
2308         }
2309 
2310         if (apnSetting == null) {
2311             if (DBG) log("setInitialAttachApn: X There in no available apn.");
2312         } else {
2313             if (DBG) log("setInitialAttachApn: X selected APN=" + apnSetting);
2314             mDataServiceManager.setInitialAttachApn(new DataProfile.Builder()
2315                     .setApnSetting(apnSetting)
2316                     .setPreferred(apnSetting.equals(getPreferredApn()))
2317                     .build(),
2318                     mPhone.getServiceState().getDataRoamingFromRegistration(), null);
2319         }
2320     }
2321 
2322     /**
2323      * Handles changes to the APN database.
2324      */
onApnChanged()2325     private void onApnChanged() {
2326         if (mPhone instanceof GsmCdmaPhone) {
2327             // The "current" may no longer be valid.  MMS depends on this to send properly. TBD
2328             ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider();
2329         }
2330 
2331         // TODO: It'd be nice to only do this if the changed entrie(s)
2332         // match the current operator.
2333         if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
2334         mDataThrottler.reset();
2335         setDefaultPreferredApnIfNeeded();
2336         createAllApnList();
2337         setDataProfilesAsNeeded();
2338         setInitialAttachApn();
2339         cleanUpConnectionsOnUpdatedApns(isAnyDataConnected(), Phone.REASON_APN_CHANGED);
2340 
2341         // FIXME: See bug 17426028 maybe no conditional is needed.
2342         if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) {
2343             setupDataOnAllConnectableApns(Phone.REASON_APN_CHANGED, RetryFailures.ALWAYS);
2344         }
2345     }
2346 
2347     /**
2348      * "Active" here means ApnContext isEnabled() and not in FAILED state
2349      * @param apnContext to compare with
2350      * @return true if higher priority active apn found
2351      */
isHigherPriorityApnContextActive(ApnContext apnContext)2352     private boolean isHigherPriorityApnContextActive(ApnContext apnContext) {
2353         if (apnContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) {
2354             return false;
2355         }
2356 
2357         for (ApnContext otherContext : mPrioritySortedApnContexts) {
2358             if (otherContext.getApnType().equals(ApnSetting.TYPE_IMS_STRING)) {
2359                 continue;
2360             }
2361             if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false;
2362             if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) {
2363                 return true;
2364             }
2365         }
2366         return false;
2367     }
2368 
2369     /**
2370      * Reports if we support multiple connections or not.
2371      * This is a combination of factors, based on carrier and RAT.
2372      * @param rilRadioTech the RIL Radio Tech currently in use
2373      * @return true if only single DataConnection is allowed
2374      */
isOnlySingleDcAllowed(int rilRadioTech)2375     private boolean isOnlySingleDcAllowed(int rilRadioTech) {
2376         int networkType = ServiceState.rilRadioTechnologyToNetworkType(rilRadioTech);
2377         // Default single dc rats with no knowledge of carrier
2378         int[] singleDcRats = null;
2379         // get the carrier specific value, if it exists, from CarrierConfigManager.
2380         // generally configManager and bundle should not be null, but if they are it should be okay
2381         // to leave singleDcRats null as well
2382         CarrierConfigManager configManager = (CarrierConfigManager)
2383                 mPhone.getContext().getSystemService(Context.CARRIER_CONFIG_SERVICE);
2384         if (configManager != null) {
2385             PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId());
2386             if (bundle != null) {
2387                 singleDcRats = bundle.getIntArray(
2388                         CarrierConfigManager.KEY_ONLY_SINGLE_DC_ALLOWED_INT_ARRAY);
2389             }
2390         }
2391         boolean onlySingleDcAllowed = false;
2392         if (TelephonyUtils.IS_DEBUGGABLE
2393                 && SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) {
2394             onlySingleDcAllowed = true;
2395         }
2396         if (singleDcRats != null) {
2397             for (int i = 0; i < singleDcRats.length && !onlySingleDcAllowed; i++) {
2398                 if (networkType == singleDcRats[i]) {
2399                     onlySingleDcAllowed = true;
2400                 }
2401             }
2402         }
2403 
2404         if (DBG) {
2405             log("isOnlySingleDcAllowed(" + TelephonyManager.getNetworkTypeName(networkType) + "): "
2406                     + onlySingleDcAllowed);
2407         }
2408         return onlySingleDcAllowed;
2409     }
2410 
sendRestartRadio()2411     void sendRestartRadio() {
2412         if (DBG)log("sendRestartRadio:");
2413         Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO);
2414         sendMessage(msg);
2415     }
2416 
restartRadio()2417     private void restartRadio() {
2418         if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
2419         cleanUpAllConnectionsInternal(true, Phone.REASON_RADIO_TURNED_OFF);
2420         mPhone.getServiceStateTracker().powerOffRadioSafely();
2421         /* Note: no need to call setRadioPower(true).  Assuming the desired
2422          * radio power state is still ON (as tracked by ServiceStateTracker),
2423          * ServiceStateTracker will call setRadioPower when it receives the
2424          * RADIO_STATE_CHANGED notification for the power off.  And if the
2425          * desired power state has changed in the interim, we don't want to
2426          * override it with an unconditional power on.
2427          */
2428     }
2429 
2430     /**
2431      * Return true if data connection need to be setup after disconnected due to
2432      * reason.
2433      *
2434      * @param apnContext APN context
2435      * @return true if try setup data connection is need for this reason
2436      */
retryAfterDisconnected(ApnContext apnContext)2437     private boolean retryAfterDisconnected(ApnContext apnContext) {
2438         boolean retry = true;
2439         String reason = apnContext.getReason();
2440 
2441         if (Phone.REASON_RADIO_TURNED_OFF.equals(reason) || (isOnlySingleDcAllowed(getDataRat())
2442                 && isHigherPriorityApnContextActive(apnContext))) {
2443             retry = false;
2444         }
2445         return retry;
2446     }
2447 
startReconnect(long delay, ApnContext apnContext, @RequestNetworkType int requestType)2448     protected void startReconnect(long delay, ApnContext apnContext,
2449             @RequestNetworkType int requestType) {
2450         apnContext.setState(DctConstants.State.RETRYING);
2451         Message msg = obtainMessage(DctConstants.EVENT_DATA_RECONNECT,
2452                        mPhone.getSubId(), requestType, apnContext);
2453         cancelReconnect(apnContext);
2454 
2455         // Wait a bit before trying the next APN, so that
2456         // we're not tying up the RIL command channel
2457         sendMessageDelayed(msg, delay);
2458 
2459         if (DBG) {
2460             log("startReconnect: delay=" + delay + ", apn="
2461                     + apnContext + ", reason=" + apnContext.getReason()
2462                     + ", subId=" + mPhone.getSubId() + ", request type="
2463                     + requestTypeToString(requestType));
2464         }
2465     }
2466 
2467     /**
2468      * Cancels the alarm associated with apnContext.
2469      *
2470      * @param apnContext on which the alarm should be stopped.
2471      */
cancelReconnect(ApnContext apnContext)2472     protected void cancelReconnect(ApnContext apnContext) {
2473         if (apnContext == null) return;
2474 
2475         if (DBG) {
2476             log("cancelReconnect: apn=" + apnContext);
2477         }
2478         removeMessages(DctConstants.EVENT_DATA_RECONNECT, apnContext);
2479     }
2480 
2481     /**
2482      * Read configuration. Note this must be called after carrier config is ready.
2483      */
readConfiguration()2484     private void readConfiguration() {
2485         log("readConfiguration");
2486         if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
2487             // Auto attach is for cellular only.
2488             mAutoAttachOnCreationConfig = mPhone.getContext().getResources()
2489                     .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation);
2490         }
2491 
2492         mAutoAttachEnabled.set(false);
2493         setDefaultPreferredApnIfNeeded();
2494         read5GConfiguration();
2495         registerSettingsObserver();
2496         SubscriptionPlan[] plans = mNetworkPolicyManager.getSubscriptionPlans(
2497                 mPhone.getSubId(), mPhone.getContext().getOpPackageName());
2498         mSubscriptionPlans = plans == null ? Collections.emptyList() : Arrays.asList(plans);
2499         if (DBG) log("SubscriptionPlans initialized: " + mSubscriptionPlans);
2500         reevaluateUnmeteredConnections();
2501         mConfigReady = true;
2502     }
2503 
2504     /**
2505      * @return {@code true} if carrier config has been applied.
2506      */
isCarrierConfigApplied()2507     private boolean isCarrierConfigApplied() {
2508         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
2509                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
2510         if (configManager != null) {
2511             PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
2512             if (b != null) {
2513                 return CarrierConfigManager.isConfigForIdentifiedCarrier(b);
2514             }
2515         }
2516         return false;
2517     }
2518 
onCarrierConfigChanged()2519     private void onCarrierConfigChanged() {
2520         if (DBG) log("onCarrierConfigChanged");
2521 
2522         if (!isCarrierConfigApplied()) {
2523             log("onCarrierConfigChanged: Carrier config is not ready yet.");
2524             return;
2525         }
2526 
2527         readConfiguration();
2528 
2529         if (mSimState == TelephonyManager.SIM_STATE_LOADED) {
2530             setDefaultDataRoamingEnabled();
2531             createAllApnList();
2532             setDataProfilesAsNeeded();
2533             setInitialAttachApn();
2534             sortApnContextByPriority();
2535             cleanUpConnectionsOnUpdatedApns(true, Phone.REASON_CARRIER_CHANGE);
2536             setupDataOnAllConnectableApns(Phone.REASON_CARRIER_CHANGE, RetryFailures.ALWAYS);
2537         } else {
2538             log("onCarrierConfigChanged: SIM is not loaded yet.");
2539         }
2540     }
2541 
onSimAbsent()2542     private void onSimAbsent() {
2543         if (DBG) log("onSimAbsent");
2544 
2545         mConfigReady = false;
2546         cleanUpAllConnectionsInternal(true, Phone.REASON_SIM_NOT_READY);
2547         mAllApnSettings.clear();
2548         mAutoAttachOnCreationConfig = false;
2549         // Clear auto attach as modem is expected to do a new attach once SIM is ready
2550         mAutoAttachEnabled.set(false);
2551         // In no-sim case, we should still send the emergency APN to the modem, if there is any.
2552         createAllApnList();
2553         setDataProfilesAsNeeded();
2554     }
2555 
onSimStateUpdated(@imState int simState)2556     private void onSimStateUpdated(@SimState int simState) {
2557         mSimState = simState;
2558 
2559         if (DBG) {
2560             log("onSimStateUpdated: state=" + SubscriptionInfoUpdater.simStateString(mSimState));
2561         }
2562 
2563         if (mSimState == TelephonyManager.SIM_STATE_ABSENT) {
2564             onSimAbsent();
2565         } else if (mSimState == TelephonyManager.SIM_STATE_LOADED) {
2566             mDataThrottler.reset();
2567             if (mConfigReady) {
2568                 createAllApnList();
2569                 setDataProfilesAsNeeded();
2570                 setInitialAttachApn();
2571                 setupDataOnAllConnectableApns(Phone.REASON_SIM_LOADED, RetryFailures.ALWAYS);
2572             } else {
2573                 log("onSimStateUpdated: config not ready yet.");
2574             }
2575         }
2576     }
2577 
onApnUnthrottled(String apn)2578     private void onApnUnthrottled(String apn) {
2579         if (apn != null) {
2580             ApnSetting apnSetting = mAllApnSettings.stream()
2581                     .filter(as -> apn.equals(as.getApnName()))
2582                     .findFirst()
2583                     .orElse(null);
2584             if (apnSetting != null) {
2585                 @ApnType int apnTypes = apnSetting.getApnTypeBitmask();
2586                 mDataThrottler.setRetryTime(apnTypes, RetryManager.NO_SUGGESTED_RETRY_DELAY,
2587                         REQUEST_TYPE_NORMAL);
2588             } else {
2589                 loge("EVENT_APN_UNTHROTTLED: Invalid APN passed: " + apn);
2590             }
2591         } else {
2592             loge("EVENT_APN_UNTHROTTLED: apn is null");
2593         }
2594     }
2595 
onTrafficDescriptorsUpdated()2596     private void onTrafficDescriptorsUpdated() {
2597         for (ApnContext apnContext : mPrioritySortedApnContexts) {
2598             if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE
2599                     && apnContext.getApnSetting().getPermanentFailed()) {
2600                 setupDataOnConnectableApn(
2601                         apnContext, Phone.REASON_TRAFFIC_DESCRIPTORS_UPDATED, RetryFailures.ALWAYS);
2602             }
2603         }
2604     }
2605 
checkForCompatibleDataConnection(ApnContext apnContext, ApnSetting nextApn)2606     private DataConnection checkForCompatibleDataConnection(ApnContext apnContext,
2607             ApnSetting nextApn) {
2608         int apnType = apnContext.getApnTypeBitmask();
2609         ArrayList<ApnSetting> dunSettings = null;
2610 
2611         if (ApnSetting.TYPE_DUN == apnType) {
2612             dunSettings = fetchDunApns();
2613         }
2614         if (DBG) {
2615             log("checkForCompatibleDataConnection: apnContext=" + apnContext);
2616         }
2617 
2618         DataConnection potentialDc = null;
2619         for (DataConnection curDc : mDataConnections.values()) {
2620             if (curDc != null) {
2621                 ApnSetting apnSetting = curDc.getApnSetting();
2622                 log("apnSetting: " + apnSetting);
2623                 if (dunSettings != null && dunSettings.size() > 0) {
2624                     for (ApnSetting dunSetting : dunSettings) {
2625                         //This ignore network type as a check which is ok because that's checked
2626                         //when calculating dun candidates.
2627                         if (areCompatible(dunSetting, apnSetting)) {
2628                             if (curDc.isActive()) {
2629                                 if (DBG) {
2630                                     log("checkForCompatibleDataConnection:"
2631                                             + " found dun conn=" + curDc);
2632                                 }
2633                                 return curDc;
2634                             } else if (curDc.isActivating()) {
2635                                 potentialDc = curDc;
2636                             }
2637                         }
2638                     }
2639                 } else if (isApnSettingCompatible(curDc, apnType)) {
2640                     if (curDc.isActive()) {
2641                         if (DBG) {
2642                             log("checkForCompatibleDataConnection:"
2643                                     + " found canHandle conn=" + curDc);
2644                         }
2645                         return curDc;
2646                     } else if (curDc.isActivating()
2647                             || (apnSetting !=  null && apnSetting.equals(nextApn))) {
2648                         potentialDc = curDc;
2649                     }
2650                 }
2651             }
2652         }
2653 
2654         if (DBG) {
2655             log("checkForCompatibleDataConnection: potential dc=" + potentialDc);
2656         }
2657         return potentialDc;
2658     }
2659 
isApnSettingCompatible(DataConnection dc, int apnType)2660     private boolean isApnSettingCompatible(DataConnection dc, int apnType) {
2661         ApnSetting apnSetting = dc.getApnSetting();
2662         if (apnSetting == null) return false;
2663 
2664         // Nothing can be compatible with type ENTERPRISE
2665         for (ApnContext apnContext : dc.getApnContexts()) {
2666             if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_ENTERPRISE) {
2667                 return false;
2668             }
2669         }
2670 
2671         return apnSetting.canHandleType(apnType);
2672     }
2673 
addHandoverCompleteMsg(Message onCompleteMsg, @ApnType int apnType)2674     private void addHandoverCompleteMsg(Message onCompleteMsg,
2675             @ApnType int apnType) {
2676         if (onCompleteMsg != null) {
2677             List<Message> messageList = mHandoverCompletionMsgs.get(apnType);
2678             if (messageList == null) messageList = new ArrayList<>();
2679             messageList.add(onCompleteMsg);
2680             mHandoverCompletionMsgs.put(apnType, messageList);
2681         }
2682     }
2683 
sendHandoverCompleteMessages(@pnType int apnType, boolean success, boolean fallbackOnFailedHandover)2684     private void sendHandoverCompleteMessages(@ApnType int apnType, boolean success,
2685             boolean fallbackOnFailedHandover) {
2686         List<Message> messageList = mHandoverCompletionMsgs.get(apnType);
2687         if (messageList != null) {
2688             for (Message msg : messageList) {
2689                 sendHandoverCompleteMsg(msg, success, mTransportType, fallbackOnFailedHandover);
2690             }
2691             messageList.clear();
2692         }
2693     }
2694 
sendHandoverCompleteMsg(Message message, boolean success, @TransportType int transport, boolean doFallbackOnFailedHandover)2695     private void sendHandoverCompleteMsg(Message message, boolean success,
2696             @TransportType int transport, boolean doFallbackOnFailedHandover) {
2697         if (message == null) return;
2698 
2699         Bundle b = message.getData();
2700         b.putBoolean(DATA_COMPLETE_MSG_EXTRA_SUCCESS, success);
2701         b.putInt(DATA_COMPLETE_MSG_EXTRA_TRANSPORT_TYPE, transport);
2702         b.putBoolean(DATA_COMPLETE_MSG_EXTRA_HANDOVER_FAILURE_FALLBACK, doFallbackOnFailedHandover);
2703         message.sendToTarget();
2704     }
2705 
shouldFallbackOnFailedHandover( @andoverFailureMode int handoverFailureMode, @RequestNetworkType int requestType, @DataFailureCause int cause)2706     private static boolean shouldFallbackOnFailedHandover(
2707                                @HandoverFailureMode int handoverFailureMode,
2708                                @RequestNetworkType int requestType,
2709                                @DataFailureCause int cause) {
2710         if (requestType != REQUEST_TYPE_HANDOVER) {
2711             //The fallback is only relevant if the request is a handover
2712             return false;
2713         } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_DO_FALLBACK) {
2714             return true;
2715         } else if (handoverFailureMode == HANDOVER_FAILURE_MODE_LEGACY) {
2716             return cause == DataFailCause.HANDOFF_PREFERENCE_CHANGED;
2717         } else {
2718             return false;
2719         }
2720     }
2721 
2722     /**
2723      * Calculates the new request type that will be used the next time a data connection retries
2724      * after a failed data call attempt.
2725      */
2726     @RequestNetworkType
calculateNewRetryRequestType(@andoverFailureMode int handoverFailureMode, @RequestNetworkType int requestType, @DataFailureCause int cause)2727     public static int calculateNewRetryRequestType(@HandoverFailureMode int handoverFailureMode,
2728             @RequestNetworkType int requestType,
2729             @DataFailureCause int cause) {
2730         boolean fallbackOnFailedHandover =
2731                 shouldFallbackOnFailedHandover(handoverFailureMode, requestType, cause);
2732         if (requestType != REQUEST_TYPE_HANDOVER) {
2733             //The fallback is only relevant if the request is a handover
2734             return requestType;
2735         }
2736 
2737         if (fallbackOnFailedHandover) {
2738             // Since fallback is happening, the request type is really "NONE".
2739             return REQUEST_TYPE_NORMAL;
2740         }
2741 
2742         if (handoverFailureMode == HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_SETUP_NORMAL) {
2743             return REQUEST_TYPE_NORMAL;
2744         }
2745 
2746         return REQUEST_TYPE_HANDOVER;
2747     }
2748 
enableApn(@pnType int apnType, @RequestNetworkType int requestType, Message onHandoverCompleteMsg)2749     public void enableApn(@ApnType int apnType, @RequestNetworkType int requestType,
2750             Message onHandoverCompleteMsg) {
2751         sendMessage(obtainMessage(DctConstants.EVENT_ENABLE_APN, apnType, requestType,
2752                 onHandoverCompleteMsg));
2753     }
2754 
onEnableApn(@pnType int apnType, @RequestNetworkType int requestType, Message onHandoverCompleteMsg)2755     private void onEnableApn(@ApnType int apnType, @RequestNetworkType int requestType,
2756             Message onHandoverCompleteMsg) {
2757         ApnContext apnContext = mApnContextsByType.get(apnType);
2758         if (apnContext == null) {
2759             loge("onEnableApn(" + apnType + "): NO ApnContext");
2760             if (onHandoverCompleteMsg != null) {
2761                 sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false);
2762             }
2763             return;
2764         }
2765 
2766         String str = "onEnableApn: apnType=" + ApnSetting.getApnTypeString(apnType)
2767                 + ", request type=" + requestTypeToString(requestType);
2768         if (DBG) log(str);
2769         ApnContext.requestLog(apnContext, str);
2770 
2771         if (!apnContext.isDependencyMet()) {
2772             apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
2773             apnContext.setEnabled(true);
2774             str = "onEnableApn: dependency is not met.";
2775             if (DBG) log(str);
2776             ApnContext.requestLog(apnContext, str);
2777             if (onHandoverCompleteMsg != null) {
2778                 sendHandoverCompleteMsg(onHandoverCompleteMsg, false, mTransportType, false);
2779             }
2780             return;
2781         }
2782 
2783         if (apnContext.isReady()) {
2784             DctConstants.State state = apnContext.getState();
2785             switch(state) {
2786                 case CONNECTING:
2787                     if (onHandoverCompleteMsg != null) {
2788                         if (DBG) {
2789                             log("onEnableApn: already in CONNECTING state. Handover request "
2790                                     + "will be responded after connected.");
2791                         }
2792                         addHandoverCompleteMsg(onHandoverCompleteMsg, apnType);
2793                     } else {
2794                         if (DBG) log("onEnableApn: in CONNECTING state. Exit now.");
2795                     }
2796                     return;
2797                 case CONNECTED:
2798                     if (onHandoverCompleteMsg != null) {
2799                         sendHandoverCompleteMsg(onHandoverCompleteMsg, true, mTransportType,
2800                                 false);
2801                         if (DBG) {
2802                             log("onEnableApn: already in CONNECTED state. Consider as handover "
2803                                     + "succeeded");
2804                         }
2805                     } else {
2806                         if (DBG) log("onEnableApn: APN in CONNECTED state. Exit now.");
2807                     }
2808                     return;
2809                 case IDLE:
2810                 case FAILED:
2811                 case RETRYING:
2812                     // We're "READY" but not active so disconnect (cleanup = true) and
2813                     // connect (trySetup = true) to be sure we retry the connection.
2814                     apnContext.setReason(Phone.REASON_DATA_ENABLED);
2815                     break;
2816             }
2817         } else {
2818             if (apnContext.isEnabled()) {
2819                 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
2820             } else {
2821                 apnContext.setReason(Phone.REASON_DATA_ENABLED);
2822             }
2823             if (apnContext.getState() == DctConstants.State.FAILED) {
2824                 apnContext.setState(DctConstants.State.IDLE);
2825             }
2826         }
2827         apnContext.setEnabled(true);
2828         apnContext.resetErrorCodeRetries();
2829 
2830         if (mConfigReady || apnContext.getApnTypeBitmask() == ApnSetting.TYPE_EMERGENCY) {
2831             trySetupData(apnContext, requestType, onHandoverCompleteMsg);
2832         } else {
2833             log("onEnableApn: config not ready yet.");
2834         }
2835     }
2836 
disableApn(@pnType int apnType, @ReleaseNetworkType int releaseType)2837     public void disableApn(@ApnType int apnType, @ReleaseNetworkType int releaseType) {
2838         sendMessage(obtainMessage(DctConstants.EVENT_DISABLE_APN, apnType, releaseType));
2839     }
2840 
onDisableApn(@pnType int apnType, @ReleaseNetworkType int releaseType)2841     private void onDisableApn(@ApnType int apnType,
2842                               @ReleaseNetworkType int releaseType) {
2843         ApnContext apnContext = mApnContextsByType.get(apnType);
2844         if (apnContext == null) {
2845             loge("disableApn(" + apnType + "): NO ApnContext");
2846             return;
2847         }
2848 
2849         boolean cleanup = false;
2850         String str = "onDisableApn: apnType=" + ApnSetting.getApnTypeString(apnType)
2851                 + ", release type=" + releaseTypeToString(releaseType);
2852         if (DBG) log(str);
2853         ApnContext.requestLog(apnContext, str);
2854 
2855         if (apnContext.isReady()) {
2856             cleanup = (releaseType == RELEASE_TYPE_DETACH
2857                     || releaseType == RELEASE_TYPE_HANDOVER);
2858             if (apnContext.isDependencyMet()) {
2859                 apnContext.setReason(Phone.REASON_DATA_DISABLED_INTERNAL);
2860                 // If ConnectivityService has disabled this network, stop trying to bring
2861                 // it up, but do not tear it down - ConnectivityService will do that
2862                 // directly by talking with the DataConnection.
2863                 //
2864                 // This doesn't apply to DUN. When the user disable tethering, we would like to
2865                 // detach the APN context from the data connection so the data connection can be
2866                 // torn down if no other APN context attached to it.
2867                 if (ApnSetting.TYPE_DUN_STRING.equals(apnContext.getApnType())
2868                         || apnContext.getState() != DctConstants.State.CONNECTED) {
2869                     str = "Clean up the connection. Apn type = " + apnContext.getApnType()
2870                             + ", state = " + apnContext.getState();
2871                     if (DBG) log(str);
2872                     ApnContext.requestLog(apnContext, str);
2873                     cleanup = true;
2874                 }
2875             } else {
2876                 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
2877             }
2878         }
2879 
2880         apnContext.setEnabled(false);
2881         if (cleanup) {
2882             cleanUpConnectionInternal(true, releaseType, apnContext);
2883         }
2884 
2885         if (isOnlySingleDcAllowed(getDataRat()) && !isHigherPriorityApnContextActive(apnContext)) {
2886             if (DBG) log("disableApn:isOnlySingleDcAllowed true & higher priority APN disabled");
2887             // If the highest priority APN is disabled and only single
2888             // data call is allowed, try to setup data call on other connectable APN.
2889             setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION,
2890                     RetryFailures.ALWAYS);
2891         }
2892     }
2893 
2894     /**
2895      * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value for user modification only
2896      */
setDataRoamingEnabledByUser(boolean enabled)2897     public void setDataRoamingEnabledByUser(boolean enabled) {
2898         mDataEnabledSettings.setDataRoamingEnabled(enabled);
2899         setDataRoamingFromUserAction(true);
2900         if (DBG) {
2901             log("setDataRoamingEnabledByUser: set phoneSubId=" + mPhone.getSubId()
2902                     + " isRoaming=" + enabled);
2903         }
2904     }
2905 
2906     /**
2907      * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
2908      */
getDataRoamingEnabled()2909     public boolean getDataRoamingEnabled() {
2910         boolean isDataRoamingEnabled = mDataEnabledSettings.getDataRoamingEnabled();
2911 
2912         if (VDBG) {
2913             log("getDataRoamingEnabled: phoneSubId=" + mPhone.getSubId()
2914                     + " isDataRoamingEnabled=" + isDataRoamingEnabled);
2915         }
2916         return isDataRoamingEnabled;
2917     }
2918 
2919     /**
2920      * Set default value for {@link android.provider.Settings.Global#DATA_ROAMING}
2921      * if the setting is not from user actions. default value is based on carrier config and system
2922      * properties.
2923      */
setDefaultDataRoamingEnabled()2924     private void setDefaultDataRoamingEnabled() {
2925         // For single SIM phones, this is a per phone property.
2926         String setting = Settings.Global.DATA_ROAMING;
2927         boolean useCarrierSpecificDefault = false;
2928         if (mTelephonyManager.getSimCount() != 1) {
2929             setting = setting + mPhone.getSubId();
2930             try {
2931                 Settings.Global.getInt(mResolver, setting);
2932             } catch (SettingNotFoundException ex) {
2933                 // For msim, update to carrier default if uninitialized.
2934                 useCarrierSpecificDefault = true;
2935             }
2936         } else if (!isDataRoamingFromUserAction()) {
2937             // for single sim device, update to carrier default if user action is not set
2938             useCarrierSpecificDefault = true;
2939         }
2940         log("setDefaultDataRoamingEnabled: useCarrierSpecificDefault "
2941                 + useCarrierSpecificDefault);
2942         if (useCarrierSpecificDefault) {
2943             boolean defaultVal = mDataEnabledSettings.getDefaultDataRoamingEnabled();
2944             mDataEnabledSettings.setDataRoamingEnabled(defaultVal);
2945         }
2946     }
2947 
isDataRoamingFromUserAction()2948     private boolean isDataRoamingFromUserAction() {
2949         final SharedPreferences sp = PreferenceManager
2950                 .getDefaultSharedPreferences(mPhone.getContext());
2951         // since we don't want to unset user preference from system update, pass true as the default
2952         // value if shared pref does not exist and set shared pref to false explicitly from factory
2953         // reset.
2954         if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) {
2955             sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit();
2956         }
2957         return sp.getBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, true);
2958     }
2959 
setDataRoamingFromUserAction(boolean isUserAction)2960     private void setDataRoamingFromUserAction(boolean isUserAction) {
2961         final SharedPreferences.Editor sp = PreferenceManager
2962                 .getDefaultSharedPreferences(mPhone.getContext()).edit();
2963         sp.putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, isUserAction).commit();
2964     }
2965 
2966     // When the data roaming status changes from roaming to non-roaming.
onDataRoamingOff()2967     private void onDataRoamingOff() {
2968         if (DBG) log("onDataRoamingOff");
2969 
2970         reevaluateDataConnections();
2971 
2972         if (!getDataRoamingEnabled()) {
2973             // TODO: Remove this once all old vendor RILs are gone. We don't need to set initial apn
2974             // attach and send the data profile again as the modem should have both roaming and
2975             // non-roaming protocol in place. Modem should choose the right protocol based on the
2976             // roaming condition.
2977             setDataProfilesAsNeeded();
2978             setInitialAttachApn();
2979 
2980             // If the user did not enable data roaming, now when we transit from roaming to
2981             // non-roaming, we should try to reestablish the data connection.
2982 
2983             setupDataOnAllConnectableApns(Phone.REASON_ROAMING_OFF, RetryFailures.ALWAYS);
2984         }
2985     }
2986 
2987     // This method is called
2988     // 1. When the data roaming status changes from non-roaming to roaming.
2989     // 2. When allowed data roaming settings is changed by the user.
onDataRoamingOnOrSettingsChanged(int messageType)2990     private void onDataRoamingOnOrSettingsChanged(int messageType) {
2991         if (DBG) log("onDataRoamingOnOrSettingsChanged");
2992         // Used to differentiate data roaming turned on vs settings changed.
2993         boolean settingChanged = (messageType == DctConstants.EVENT_ROAMING_SETTING_CHANGE);
2994 
2995         // Check if the device is actually data roaming
2996         if (!mPhone.getServiceState().getDataRoaming()) {
2997             if (DBG) log("device is not roaming. ignored the request.");
2998             return;
2999         }
3000 
3001         checkDataRoamingStatus(settingChanged);
3002 
3003         if (getDataRoamingEnabled()) {
3004             // If the restricted data was brought up when data roaming is disabled, and now users
3005             // enable data roaming, we need to re-evaluate the conditions and possibly change the
3006             // network's capability.
3007             if (settingChanged) {
3008                 reevaluateDataConnections();
3009             }
3010 
3011             if (DBG) log("onDataRoamingOnOrSettingsChanged: setup data on roaming");
3012 
3013             setupDataOnAllConnectableApns(Phone.REASON_ROAMING_ON, RetryFailures.ALWAYS);
3014         } else {
3015             // If the user does not turn on data roaming, when we transit from non-roaming to
3016             // roaming, we need to tear down the data connection otherwise the user might be
3017             // charged for data roaming usage.
3018             if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming.");
3019             cleanUpAllConnectionsInternal(true, Phone.REASON_ROAMING_ON);
3020         }
3021     }
3022 
3023     // We want to track possible roaming data leakage. Which is, if roaming setting
3024     // is disabled, yet we still setup a roaming data connection or have a connected ApnContext
3025     // switched to roaming. When this happens, we log it in a local log.
checkDataRoamingStatus(boolean settingChanged)3026     private void checkDataRoamingStatus(boolean settingChanged) {
3027         if (!settingChanged && !getDataRoamingEnabled()
3028                 && mPhone.getServiceState().getDataRoaming()) {
3029             for (ApnContext apnContext : mApnContexts.values()) {
3030                 if (apnContext.getState() == DctConstants.State.CONNECTED) {
3031                     mDataRoamingLeakageLog.log("PossibleRoamingLeakage "
3032                             + " connection params: " + (apnContext.getDataConnection() != null
3033                             ? apnContext.getDataConnection().getConnectionParams() : ""));
3034                 }
3035             }
3036         }
3037     }
3038 
onRadioAvailable()3039     private void onRadioAvailable() {
3040         if (DBG) log("onRadioAvailable");
3041         if (!areAllDataDisconnected()) {
3042             cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, null);
3043         }
3044     }
3045 
onRadioOffOrNotAvailable()3046     private void onRadioOffOrNotAvailable() {
3047         // Make sure our reconnect delay starts at the initial value
3048         // next time the radio comes on
3049 
3050         mReregisterOnReconnectFailure = false;
3051 
3052         // Clear auto attach as modem is expected to do a new attach
3053         mAutoAttachEnabled.set(false);
3054 
3055         if (mPhone.getSimulatedRadioControl() != null) {
3056             // Assume data is connected on the simulator
3057             // FIXME  this can be improved
3058             log("We're on the simulator; assuming radio off is meaningless");
3059         } else {
3060             if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
3061             cleanUpAllConnectionsInternal(false, Phone.REASON_RADIO_TURNED_OFF);
3062         }
3063     }
3064 
completeConnection(ApnContext apnContext, @RequestNetworkType int type)3065     private void completeConnection(ApnContext apnContext, @RequestNetworkType int type) {
3066 
3067         if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext);
3068 
3069         if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) {
3070             if (DBG) {
3071                 log("completeConnection: MOBILE_PROVISIONING_ACTION url="
3072                         + mProvisioningUrl);
3073             }
3074             Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
3075                     Intent.CATEGORY_APP_BROWSER);
3076             newIntent.setData(Uri.parse(mProvisioningUrl));
3077             newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
3078                     Intent.FLAG_ACTIVITY_NEW_TASK);
3079             try {
3080                 mPhone.getContext().startActivity(newIntent);
3081             } catch (ActivityNotFoundException e) {
3082                 loge("completeConnection: startActivityAsUser failed" + e);
3083             }
3084         }
3085         mIsProvisioning = false;
3086         mProvisioningUrl = null;
3087         if (mProvisioningSpinner != null) {
3088             sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER,
3089                     mProvisioningSpinner));
3090         }
3091 
3092         startNetStatPoll();
3093         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
3094 
3095         PersistableBundle b = getCarrierConfig();
3096         if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT
3097                 && b.getBoolean(CarrierConfigManager
3098                 .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) {
3099             NotificationManager notificationManager = (NotificationManager)
3100                     mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
3101             notificationManager.cancel(Integer.toString(mPhone.getSubId()),
3102                     NO_DATA_NOTIFICATION);
3103         }
3104     }
3105 
3106     /**
3107      * A SETUP (aka bringUp) has completed, possibly with an error. If
3108      * there is an error this method will call {@link #onDataSetupCompleteError}.
3109      */
onDataSetupComplete(ApnContext apnContext, boolean success, @DataFailureCause int cause, @RequestNetworkType int requestType, @HandoverFailureMode int handoverFailureMode)3110     protected void onDataSetupComplete(ApnContext apnContext, boolean success,
3111             @DataFailureCause int cause, @RequestNetworkType int requestType,
3112             @HandoverFailureMode int handoverFailureMode) {
3113         boolean fallbackOnFailedHandover = shouldFallbackOnFailedHandover(
3114                 handoverFailureMode, requestType, cause);
3115 
3116         if (success && (handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_UNKNOWN
3117                 && handoverFailureMode != DataCallResponse.HANDOVER_FAILURE_MODE_LEGACY)) {
3118             Log.wtf(mLogTag, "bad failure mode: "
3119                     + DataCallResponse.failureModeToString(handoverFailureMode));
3120         } else if (handoverFailureMode
3121                 != DataCallResponse.HANDOVER_FAILURE_MODE_NO_FALLBACK_RETRY_HANDOVER
3122                 && cause != DataFailCause.SERVICE_TEMPORARILY_UNAVAILABLE) {
3123             sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), success,
3124                     fallbackOnFailedHandover);
3125         }
3126 
3127         if (success) {
3128             DataConnection dataConnection = apnContext.getDataConnection();
3129 
3130             if (RADIO_TESTS) {
3131                 // Note: To change radio.test.onDSC.null.dcac from command line you need to
3132                 // adb root and adb remount and from the command line you can only change the
3133                 // value to 1 once. To change it a second time you can reboot or execute
3134                 // adb shell stop and then adb shell start. The command line to set the value is:
3135                 // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"
3136                 ContentResolver cr = mPhone.getContext().getContentResolver();
3137                 String radioTestProperty = "radio.test.onDSC.null.dcac";
3138                 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) {
3139                     log("onDataSetupComplete: " + radioTestProperty +
3140                             " is true, set dcac to null and reset property to false");
3141                     dataConnection = null;
3142                     Settings.System.putInt(cr, radioTestProperty, 0);
3143                     log("onDataSetupComplete: " + radioTestProperty + "=" +
3144                             Settings.System.getInt(mPhone.getContext().getContentResolver(),
3145                                     radioTestProperty, -1));
3146                 }
3147             }
3148             if (dataConnection == null) {
3149                 log("onDataSetupComplete: no connection to DC, handle as error");
3150                 onDataSetupCompleteError(apnContext, requestType, false);
3151             } else {
3152                 ApnSetting apn = apnContext.getApnSetting();
3153                 if (DBG) {
3154                     log("onDataSetupComplete: success apn=" + (apn == null ? "unknown"
3155                             : apn.getApnName()));
3156                 }
3157 
3158                 // everything is setup
3159                 if (TextUtils.equals(apnContext.getApnType(), ApnSetting.TYPE_DEFAULT_STRING)
3160                         && mCanSetPreferApn && mPreferredApn == null) {
3161                     if (DBG) log("onDataSetupComplete: PREFERRED APN is null");
3162                     mPreferredApn = apn;
3163                     if (mPreferredApn != null) {
3164                         setPreferredApn(mPreferredApn.getId());
3165                     }
3166                 }
3167 
3168                 // A connection is setup
3169                 apnContext.setState(DctConstants.State.CONNECTED);
3170 
3171                 checkDataRoamingStatus(false);
3172 
3173                 boolean isProvApn = apnContext.isProvisioningApn();
3174                 final ConnectivityManager cm = (ConnectivityManager) mPhone.getContext()
3175                         .getSystemService(Context.CONNECTIVITY_SERVICE);
3176                 if (mProvisionBroadcastReceiver != null) {
3177                     mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
3178                     mProvisionBroadcastReceiver = null;
3179                 }
3180 
3181                 if ((!isProvApn) || mIsProvisioning) {
3182                     if (mIsProvisioning) {
3183                         // Hide any notification that was showing previously
3184                         hideProvisioningNotification();
3185                     }
3186 
3187                     // Complete the connection normally notifying the world we're connected.
3188                     // We do this if this isn't a special provisioning apn or if we've been
3189                     // told its time to provision.
3190                     completeConnection(apnContext, requestType);
3191                 } else {
3192                     // This is a provisioning APN that we're reporting as connected. Later
3193                     // when the user desires to upgrade this to a "default" connection,
3194                     // mIsProvisioning == true, we'll go through the code path above.
3195                     // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING
3196                     // is sent to the DCT.
3197                     if (DBG) {
3198                         log("onDataSetupComplete: successful, BUT send connected to prov apn as"
3199                                 + " mIsProvisioning:" + mIsProvisioning + " == false"
3200                                 + " && (isProvisioningApn:" + isProvApn + " == true");
3201                     }
3202 
3203                     // While radio is up, grab provisioning URL.  The URL contains ICCID which
3204                     // disappears when radio is off.
3205                     mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver(
3206                             mPhone.getMobileProvisioningUrl(),
3207                             mTelephonyManager.getNetworkOperatorName());
3208                     mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver,
3209                             new IntentFilter(INTENT_PROVISION));
3210 
3211                     // Put up user notification that sign-in is required.
3212                     showProvisioningNotification();
3213 
3214                     // Turn off radio to save battery and avoid wasting carrier resources.
3215                     // The network isn't usable and network validation will just fail anyhow.
3216                     setRadio(false);
3217                 }
3218                 if (DBG) {
3219                     log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType());
3220                 }
3221                 if (TelephonyUtils.IS_DEBUGGABLE) {
3222                     // adb shell setprop persist.radio.test.pco [pco_val]
3223                     String radioTestProperty = "persist.radio.test.pco";
3224                     int pcoVal = SystemProperties.getInt(radioTestProperty, -1);
3225                     if (pcoVal != -1) {
3226                         log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal);
3227                         final byte[] value = new byte[1];
3228                         value[0] = (byte) pcoVal;
3229                         final Intent intent =
3230                                 new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE);
3231                         intent.putExtra(TelephonyManager.EXTRA_APN_TYPE, ApnSetting.TYPE_DEFAULT);
3232                         intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL,
3233                                 ApnSetting.PROTOCOL_IPV4V6);
3234                         intent.putExtra(TelephonyManager.EXTRA_PCO_ID, 0xFF00);
3235                         intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, value);
3236                         mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
3237                     }
3238                 }
3239             }
3240         } else {
3241             if (DBG) {
3242                 ApnSetting apn = apnContext.getApnSetting();
3243                 log("onDataSetupComplete: error apn=" + apn.getApnName() + ", cause="
3244                         + DataFailCause.toString(cause) + ", requestType="
3245                         + requestTypeToString(requestType));
3246             }
3247             if (DataFailCause.isEventLoggable(cause)) {
3248                 // Log this failure to the Event Logs.
3249                 int cid = getCellLocationId();
3250                 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
3251                         cause, cid, mTelephonyManager.getNetworkType());
3252             }
3253             ApnSetting apn = apnContext.getApnSetting();
3254 
3255             // Compose broadcast intent send to the specific carrier signaling receivers
3256             Intent intent = new Intent(TelephonyManager
3257                     .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED);
3258             intent.putExtra(TelephonyManager.EXTRA_DATA_FAIL_CAUSE, cause);
3259             intent.putExtra(TelephonyManager.EXTRA_APN_TYPE,
3260                     ApnSetting.getApnTypesBitmaskFromString(apnContext.getApnType()));
3261             mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
3262 
3263             if (DataFailCause.isRadioRestartFailure(mPhone.getContext(), cause, mPhone.getSubId())
3264                     || apnContext.restartOnError(cause)) {
3265                 if (DBG) log("Modem restarted.");
3266                 sendRestartRadio();
3267             }
3268 
3269             // If the data call failure cause is a permanent failure, we mark the APN as permanent
3270             // failed.
3271             if (isPermanentFailure(cause)) {
3272                 log("cause=" + DataFailCause.toString(cause)
3273                         + ", mark apn as permanent failed. apn = " + apn);
3274                 apnContext.markApnPermanentFailed(apn);
3275 
3276                 PersistableBundle b = getCarrierConfig();
3277                 if (apnContext.getApnTypeBitmask() == ApnSetting.TYPE_DEFAULT
3278                         && b.getBoolean(CarrierConfigManager
3279                         .KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL)) {
3280                     NotificationManager notificationManager = (NotificationManager)
3281                             mPhone.getContext().getSystemService(Context.NOTIFICATION_SERVICE);
3282 
3283                     CharSequence title = mPhone.getContext().getText(
3284                             com.android.internal.R.string.RestrictedOnDataTitle);
3285                     CharSequence details = mPhone.getContext().getText(
3286                             com.android.internal.R.string.RestrictedStateContent);
3287 
3288                     Notification notification = new Notification.Builder(mPhone.getContext(),
3289                             NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS)
3290                             .setWhen(System.currentTimeMillis())
3291                             .setAutoCancel(true)
3292                             .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
3293                             .setTicker(title)
3294                             .setColor(mPhone.getContext().getResources().getColor(
3295                                     com.android.internal.R.color.system_notification_accent_color))
3296                             .setContentTitle(title)
3297                             .setStyle(new Notification.BigTextStyle().bigText(details))
3298                             .setContentText(details)
3299                             .build();
3300                     notificationManager.notify(Integer.toString(mPhone.getSubId()),
3301                             NO_DATA_NOTIFICATION, notification);
3302                 }
3303             }
3304 
3305             int newRequestType = calculateNewRetryRequestType(handoverFailureMode, requestType,
3306                     cause);
3307             onDataSetupCompleteError(apnContext, newRequestType, fallbackOnFailedHandover);
3308         }
3309     }
3310 
3311 
3312 
3313     /**
3314      * Error has occurred during the SETUP {aka bringUP} request and the DCT
3315      * should either try the next waiting APN or start over from the
3316      * beginning if the list is empty. Between each SETUP request there will
3317      * be a delay defined by {@link ApnContext#getDelayForNextApn(boolean)}.
3318      */
onDataSetupCompleteError(ApnContext apnContext, @RequestNetworkType int requestType, boolean fallbackOnFailedHandover)3319     protected void onDataSetupCompleteError(ApnContext apnContext,
3320             @RequestNetworkType int requestType, boolean fallbackOnFailedHandover) {
3321         long delay = apnContext.getDelayForNextApn(mFailFast);
3322         // Check if we need to retry or not.
3323         if (delay >= 0 && delay != RetryManager.NO_RETRY && !fallbackOnFailedHandover) {
3324             if (DBG) {
3325                 log("onDataSetupCompleteError: APN type=" + apnContext.getApnType()
3326                         + ". Request type=" + requestTypeToString(requestType) + ", Retry in "
3327                         + delay + "ms.");
3328             }
3329             startReconnect(delay, apnContext, requestType);
3330         } else {
3331             // If we are not going to retry any APN, set this APN context to failed state.
3332             // This would be the final state of a data connection.
3333             apnContext.setState(DctConstants.State.FAILED);
3334             apnContext.setDataConnection(null);
3335             log("onDataSetupCompleteError: Stop retrying APNs. delay=" + delay
3336                     + ", requestType=" + requestTypeToString(requestType));
3337             //send request network complete messages as needed
3338             sendHandoverCompleteMessages(apnContext.getApnTypeBitmask(), false,
3339                     fallbackOnFailedHandover);
3340         }
3341     }
3342 
3343     /**
3344      * Called when EVENT_NETWORK_STATUS_CHANGED is received.
3345      *
3346      * @param status One of {@code NetworkAgent.VALID_NETWORK} or
3347      * {@code NetworkAgent.INVALID_NETWORK}.
3348      * @param cid context id {@code cid}
3349      * @param redirectUrl If the Internet probe was redirected, this
3350      * is the destination it was redirected to, otherwise {@code null}
3351      */
onNetworkStatusChanged(int status, int cid, String redirectUrl)3352     private void onNetworkStatusChanged(int status, int cid, String redirectUrl) {
3353         if (!TextUtils.isEmpty(redirectUrl)) {
3354             Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_REDIRECTED);
3355             intent.putExtra(TelephonyManager.EXTRA_REDIRECTION_URL, redirectUrl);
3356             mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
3357             log("Notify carrier signal receivers with redirectUrl: " + redirectUrl);
3358         } else {
3359             final boolean isValid = status == NetworkAgent.VALIDATION_STATUS_VALID;
3360             final DataConnection dc = getDataConnectionByContextId(cid);
3361             if (!mDsRecoveryHandler.isRecoveryOnBadNetworkEnabled()) {
3362                 if (DBG) log("Skip data stall recovery on network status change with in threshold");
3363                 return;
3364             }
3365             if (mTransportType != AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
3366                 if (DBG) log("Skip data stall recovery on non WWAN");
3367                 return;
3368             }
3369             if (dc != null && dc.isValidationRequired()) {
3370                 mDsRecoveryHandler.processNetworkStatusChanged(isValid);
3371             }
3372         }
3373     }
3374 
3375     /**
3376      * Called when EVENT_DISCONNECT_DONE is received.
3377      */
onDisconnectDone(ApnContext apnContext)3378     private void onDisconnectDone(ApnContext apnContext) {
3379         if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
3380         apnContext.setState(DctConstants.State.IDLE);
3381         // If all data connection are gone, check whether Airplane mode request was pending.
3382         if (areAllDataDisconnected()
3383                 && mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
3384             if (DBG) log("onDisconnectDone: radio will be turned off, no retries");
3385             // Radio will be turned off. No need to retry data setup
3386             apnContext.setApnSetting(null);
3387             apnContext.setDataConnection(null);
3388 
3389             // Need to notify disconnect as well, in the case of switching Airplane mode.
3390             // Otherwise, it would cause 30s delayed to turn on Airplane mode.
3391             notifyAllDataDisconnected();
3392             return;
3393         }
3394         // If APN is still enabled, try to bring it back up automatically
3395         if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) {
3396             // Wait a bit before trying the next APN, so that
3397             // we're not tying up the RIL command channel.
3398             // This also helps in any external dependency to turn off the context.
3399             if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect");
3400 
3401             // See if there are still handover request pending that we need to retry handover
3402             // after previous data gets disconnected.
3403             if (isHandoverPending(apnContext.getApnTypeBitmask())) {
3404                 if (DBG) log("Handover request pending. Retry handover immediately.");
3405                 startReconnect(0, apnContext, REQUEST_TYPE_HANDOVER);
3406             } else {
3407                 long delay = apnContext.getRetryAfterDisconnectDelay();
3408                 if (delay > 0) {
3409                     // Data connection is in IDLE state, so when we reconnect later, we'll rebuild
3410                     // the waiting APN list, which will also reset/reconfigure the retry manager.
3411                     startReconnect(delay, apnContext, REQUEST_TYPE_NORMAL);
3412                 }
3413             }
3414         } else {
3415             boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean(
3416                     com.android.internal.R.bool.config_restartRadioAfterProvisioning);
3417 
3418             if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) {
3419                 log("onDisconnectDone: restartRadio after provisioning");
3420                 restartRadio();
3421             }
3422             apnContext.setApnSetting(null);
3423             apnContext.setDataConnection(null);
3424             if (isOnlySingleDcAllowed(getDataRat())) {
3425                 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn");
3426                 setupDataOnAllConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION,
3427                         RetryFailures.ALWAYS);
3428             } else {
3429                 if(DBG) log("onDisconnectDone: not retrying");
3430             }
3431         }
3432 
3433         if (areAllDataDisconnected()) {
3434             apnContext.setConcurrentVoiceAndDataAllowed(
3435                     mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed());
3436             notifyAllDataDisconnected();
3437         }
3438 
3439     }
3440 
onVoiceCallStarted()3441     private void onVoiceCallStarted() {
3442         if (DBG) log("onVoiceCallStarted");
3443         mInVoiceCall = true;
3444         if (isAnyDataConnected()
3445                 && !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
3446             if (DBG) log("onVoiceCallStarted stop polling");
3447             stopNetStatPoll();
3448             stopDataStallAlarm();
3449         }
3450     }
3451 
onVoiceCallEnded()3452     protected void onVoiceCallEnded() {
3453         if (DBG) log("onVoiceCallEnded");
3454         mInVoiceCall = false;
3455         if (isAnyDataConnected()) {
3456             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
3457                 startNetStatPoll();
3458                 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
3459             } else {
3460                 // clean slate after call end.
3461                 resetPollStats();
3462             }
3463         }
3464         // reset reconnect timer
3465         setupDataOnAllConnectableApns(Phone.REASON_VOICE_CALL_ENDED, RetryFailures.ALWAYS);
3466     }
3467     /**
3468      * @return {@code true} if there is any data in connected state.
3469      */
3470     @VisibleForTesting
isAnyDataConnected()3471     public boolean isAnyDataConnected() {
3472         for (DataConnection dc : mDataConnections.values()) {
3473             if (dc.isActive()) {
3474                 return true;
3475             }
3476         }
3477         return false;
3478     }
3479 
3480     /**
3481      * @return {@code true} if all data connections are in disconnected state.
3482      */
areAllDataDisconnected()3483     public boolean areAllDataDisconnected() {
3484         for (DataConnection dc : mDataConnections.values()) {
3485             if (!dc.isInactive()) {
3486                 if (DBG) log("areAllDataDisconnected false due to DC: " + dc.getName());
3487                 return false;
3488             }
3489         }
3490         return true;
3491     }
3492 
setDataProfilesAsNeeded()3493     protected void setDataProfilesAsNeeded() {
3494         if (DBG) log("setDataProfilesAsNeeded");
3495 
3496         ArrayList<DataProfile> dataProfileList = new ArrayList<>();
3497 
3498         int preferredApnSetId = getPreferredApnSetId();
3499         for (ApnSetting apn : mAllApnSettings) {
3500             if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID
3501                     || preferredApnSetId == apn.getApnSetId()) {
3502                 DataProfile dp = new DataProfile.Builder()
3503                         .setApnSetting(apn)
3504                         .setPreferred(apn.equals(getPreferredApn()))
3505                         .build();
3506                 if (!dataProfileList.contains(dp)) {
3507                     dataProfileList.add(dp);
3508                 }
3509             } else {
3510                 if (VDBG) {
3511                     log("setDataProfilesAsNeeded: APN set id " + apn.getApnSetId()
3512                             + " does not match the preferred set id " + preferredApnSetId);
3513                 }
3514             }
3515         }
3516 
3517         // Check if the data profiles we are sending are same as we did last time. We don't want to
3518         // send the redundant profiles to the modem. Also if there the list is empty, we don't
3519         // send it to the modem.
3520         if (!dataProfileList.isEmpty()
3521                 && (dataProfileList.size() != mLastDataProfileList.size()
3522                 || !mLastDataProfileList.containsAll(dataProfileList))) {
3523             mDataServiceManager.setDataProfile(dataProfileList,
3524                     mPhone.getServiceState().getDataRoamingFromRegistration(), null);
3525         }
3526     }
3527 
3528     /**
3529      * Based on the sim operator numeric, create a list for all possible
3530      * Data Connections and setup the preferredApn.
3531      */
createAllApnList()3532     protected void createAllApnList() {
3533         mAllApnSettings.clear();
3534         String operator = mPhone.getOperatorNumeric();
3535 
3536         // ORDER BY Telephony.Carriers._ID ("_id")
3537         Cursor cursor = mPhone.getContext().getContentResolver().query(
3538                 Uri.withAppendedPath(Telephony.Carriers.SIM_APN_URI, "filtered/subId/"
3539                         + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID);
3540 
3541         if (cursor != null) {
3542             while (cursor.moveToNext()) {
3543                 ApnSetting apn = ApnSetting.makeApnSetting(cursor);
3544                 if (apn == null) {
3545                     continue;
3546                 }
3547                 mAllApnSettings.add(apn);
3548             }
3549             cursor.close();
3550         } else {
3551             if (DBG) log("createAllApnList: cursor is null");
3552             mApnSettingsInitializationLog.log("cursor is null for carrier, operator: "
3553                     + operator);
3554         }
3555 
3556         dedupeApnSettings();
3557 
3558         if (mAllApnSettings.isEmpty()) {
3559             log("createAllApnList: No APN found for carrier, operator: " + operator);
3560             mApnSettingsInitializationLog.log("no APN found for carrier, operator: "
3561                     + operator);
3562             mPreferredApn = null;
3563         } else {
3564             mPreferredApn = getPreferredApn();
3565             if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
3566         }
3567 
3568         addDefaultApnSettingsAsNeeded();
3569         if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);
3570     }
3571 
dedupeApnSettings()3572     private void dedupeApnSettings() {
3573         ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>();
3574 
3575         // coalesce APNs if they are similar enough to prevent
3576         // us from bringing up two data calls with the same interface
3577         int i = 0;
3578         while (i < mAllApnSettings.size() - 1) {
3579             ApnSetting first = mAllApnSettings.get(i);
3580             ApnSetting second = null;
3581             int j = i + 1;
3582             while (j < mAllApnSettings.size()) {
3583                 second = mAllApnSettings.get(j);
3584                 if (first.similar(second)) {
3585                     ApnSetting newApn = mergeApns(first, second);
3586                     mAllApnSettings.set(i, newApn);
3587                     first = newApn;
3588                     mAllApnSettings.remove(j);
3589                 } else {
3590                     j++;
3591                 }
3592             }
3593             i++;
3594         }
3595     }
3596 
mergeApns(ApnSetting dest, ApnSetting src)3597     private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) {
3598         int id = dest.getId();
3599         if ((src.getApnTypeBitmask() & ApnSetting.TYPE_DEFAULT) == ApnSetting.TYPE_DEFAULT) {
3600             id = src.getId();
3601         }
3602         final int resultApnType = src.getApnTypeBitmask() | dest.getApnTypeBitmask();
3603         Uri mmsc = (dest.getMmsc() == null ? src.getMmsc() : dest.getMmsc());
3604         String mmsProxy = TextUtils.isEmpty(dest.getMmsProxyAddressAsString())
3605                 ? src.getMmsProxyAddressAsString() : dest.getMmsProxyAddressAsString();
3606         int mmsPort = dest.getMmsProxyPort() == -1 ? src.getMmsProxyPort() : dest.getMmsProxyPort();
3607         String proxy = TextUtils.isEmpty(dest.getProxyAddressAsString())
3608                 ? src.getProxyAddressAsString() : dest.getProxyAddressAsString();
3609         int port = dest.getProxyPort() == -1 ? src.getProxyPort() : dest.getProxyPort();
3610         int protocol = src.getProtocol() == ApnSetting.PROTOCOL_IPV4V6 ? src.getProtocol()
3611                 : dest.getProtocol();
3612         int roamingProtocol = src.getRoamingProtocol() == ApnSetting.PROTOCOL_IPV4V6
3613                 ? src.getRoamingProtocol() : dest.getRoamingProtocol();
3614         int networkTypeBitmask = (dest.getNetworkTypeBitmask() == 0
3615                 || src.getNetworkTypeBitmask() == 0)
3616                 ? 0 : (dest.getNetworkTypeBitmask() | src.getNetworkTypeBitmask());
3617         return new ApnSetting.Builder()
3618                 .setId(id)
3619                 .setOperatorNumeric(dest.getOperatorNumeric())
3620                 .setEntryName(dest.getEntryName())
3621                 .setApnName(dest.getApnName())
3622                 .setProxyAddress(proxy)
3623                 .setProxyPort(port)
3624                 .setMmsc(mmsc)
3625                 .setMmsProxyAddress(mmsProxy)
3626                 .setMmsProxyPort(mmsPort)
3627                 .setUser(dest.getUser())
3628                 .setPassword(dest.getPassword())
3629                 .setAuthType(dest.getAuthType())
3630                 .setApnTypeBitmask(resultApnType)
3631                 .setProtocol(protocol)
3632                 .setRoamingProtocol(roamingProtocol)
3633                 .setCarrierEnabled(dest.isEnabled())
3634                 .setNetworkTypeBitmask(networkTypeBitmask)
3635                 .setProfileId(dest.getProfileId())
3636                 .setModemCognitive(dest.isPersistent() || src.isPersistent())
3637                 .setMaxConns(dest.getMaxConns())
3638                 .setWaitTime(dest.getWaitTime())
3639                 .setMaxConnsTime(dest.getMaxConnsTime())
3640                 .setMtuV4(dest.getMtuV4())
3641                 .setMtuV6(dest.getMtuV6())
3642                 .setMvnoType(dest.getMvnoType())
3643                 .setMvnoMatchData(dest.getMvnoMatchData())
3644                 .setApnSetId(dest.getApnSetId())
3645                 .setCarrierId(dest.getCarrierId())
3646                 .setSkip464Xlat(dest.getSkip464Xlat())
3647                 .build();
3648     }
3649 
createDataConnection()3650     private DataConnection createDataConnection() {
3651         if (DBG) log("createDataConnection E");
3652 
3653         int id = mUniqueIdGenerator.getAndIncrement();
3654         DataConnection dataConnection = DataConnection.makeDataConnection(mPhone, id, this,
3655                 mDataServiceManager, mDcTesterFailBringUpAll, mDcc);
3656         mDataConnections.put(id, dataConnection);
3657         if (DBG) log("createDataConnection() X id=" + id + " dc=" + dataConnection);
3658         return dataConnection;
3659     }
3660 
destroyDataConnections()3661     private void destroyDataConnections() {
3662         if(mDataConnections != null) {
3663             if (DBG) log("destroyDataConnections: clear mDataConnectionList");
3664             mDataConnections.clear();
3665         } else {
3666             if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore");
3667         }
3668     }
3669 
3670     /**
3671      * Build a list of APNs to be used to create PDP's.
3672      *
3673      * @param requestedApnType
3674      * @return waitingApns list to be used to create PDP
3675      *          error when waitingApns.isEmpty()
3676      */
buildWaitingApns(String requestedApnType, int radioTech)3677     private @NonNull ArrayList<ApnSetting> buildWaitingApns(String requestedApnType,
3678             int radioTech) {
3679         if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType);
3680         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
3681 
3682         int requestedApnTypeBitmask = ApnSetting.getApnTypesBitmaskFromString(requestedApnType);
3683         if (requestedApnTypeBitmask == ApnSetting.TYPE_ENTERPRISE) {
3684             requestedApnTypeBitmask = ApnSetting.TYPE_DEFAULT;
3685         }
3686         if (requestedApnTypeBitmask == ApnSetting.TYPE_DUN) {
3687             ArrayList<ApnSetting> dunApns = fetchDunApns();
3688             if (dunApns.size() > 0) {
3689                 for (ApnSetting dun : dunApns) {
3690                     apnList.add(dun);
3691                     if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
3692                 }
3693                 return apnList;
3694             }
3695         }
3696 
3697         String operator = mPhone.getOperatorNumeric();
3698 
3699         // This is a workaround for a bug (7305641) where we don't failover to other
3700         // suitable APNs if our preferred APN fails.  On prepaid ATT sims we need to
3701         // failover to a provisioning APN, but once we've used their default data
3702         // connection we are locked to it for life.  This change allows ATT devices
3703         // to say they don't want to use preferred at all.
3704         boolean usePreferred = true;
3705         try {
3706             usePreferred = !mPhone.getContext().getResources().getBoolean(com.android
3707                     .internal.R.bool.config_dontPreferApn);
3708         } catch (Resources.NotFoundException e) {
3709             if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true");
3710             usePreferred = true;
3711         }
3712         if (usePreferred) {
3713             mPreferredApn = getPreferredApn();
3714         }
3715         if (DBG) {
3716             log("buildWaitingApns: usePreferred=" + usePreferred
3717                     + " canSetPreferApn=" + mCanSetPreferApn
3718                     + " mPreferredApn=" + mPreferredApn
3719                     + " operator=" + operator + " radioTech=" + radioTech);
3720         }
3721 
3722         if (usePreferred && mCanSetPreferApn && mPreferredApn != null &&
3723                 mPreferredApn.canHandleType(requestedApnTypeBitmask)) {
3724             if (DBG) {
3725                 log("buildWaitingApns: Preferred APN:" + operator + ":"
3726                         + mPreferredApn.getOperatorNumeric() + ":" + mPreferredApn);
3727             }
3728 
3729             if (TextUtils.equals(mPreferredApn.getOperatorNumeric(), operator)
3730                     || mPreferredApn.getCarrierId() == mPhone.getCarrierId()) {
3731                 if (mPreferredApn.canSupportNetworkType(
3732                         ServiceState.rilRadioTechnologyToNetworkType(radioTech))) {
3733                     // Create a new instance of ApnSetting for ENTERPRISE because each
3734                     // DataConnection should have its own ApnSetting. ENTERPRISE uses the same
3735                     // APN as DEFAULT but is a separate DataConnection
3736                     if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType)
3737                             == ApnSetting.TYPE_ENTERPRISE) {
3738                         apnList.add(ApnSetting.makeApnSetting(mPreferredApn));
3739                     } else {
3740                         apnList.add(mPreferredApn);
3741                     }
3742                     if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
3743                     return apnList;
3744                 }
3745             }
3746             if (DBG) log("buildWaitingApns: no preferred APN");
3747             setPreferredApn(-1);
3748             mPreferredApn = null;
3749         }
3750 
3751         if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
3752         int preferredApnSetId = getPreferredApnSetId();
3753         for (ApnSetting apn : mAllApnSettings) {
3754             if (apn.canHandleType(requestedApnTypeBitmask)) {
3755                 if (apn.canSupportNetworkType(
3756                         ServiceState.rilRadioTechnologyToNetworkType(radioTech))) {
3757                     if (apn.getApnSetId() == Telephony.Carriers.MATCH_ALL_APN_SET_ID
3758                             || preferredApnSetId == apn.getApnSetId()) {
3759                         if (VDBG) log("buildWaitingApns: adding apn=" + apn);
3760                         // Create a new instance of ApnSetting for ENTERPRISE because each
3761                         // DataConnection should have its own ApnSetting. ENTERPRISE uses the same
3762                         // APN as DEFAULT but is a separate DataConnection
3763                         if (ApnSetting.getApnTypesBitmaskFromString(requestedApnType)
3764                                 == ApnSetting.TYPE_ENTERPRISE) {
3765                             apnList.add(ApnSetting.makeApnSetting(apn));
3766                         } else {
3767                             apnList.add(apn);
3768                         }
3769                     } else {
3770                         log("buildWaitingApns: APN set id " + apn.getApnSetId()
3771                                 + " does not match the preferred set id " + preferredApnSetId);
3772                     }
3773                 } else {
3774                     if (DBG) {
3775                         log("buildWaitingApns: networkTypeBitmask:"
3776                                 + apn.getNetworkTypeBitmask()
3777                                 + " does not include radioTech:"
3778                                 + ServiceState.rilRadioTechnologyToString(radioTech));
3779                     }
3780                 }
3781             } else if (VDBG) {
3782                 log("buildWaitingApns: couldn't handle requested ApnType="
3783                         + requestedApnType);
3784             }
3785         }
3786 
3787         if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList);
3788         return apnList;
3789     }
3790 
apnListToString(ArrayList<ApnSetting> apns)3791     private String apnListToString (ArrayList<ApnSetting> apns) {
3792         StringBuilder result = new StringBuilder();
3793         for (int i = 0, size = apns.size(); i < size; i++) {
3794             result.append('[')
3795                   .append(apns.get(i).toString())
3796                   .append(']');
3797         }
3798         return result.toString();
3799     }
3800 
setPreferredApn(int pos)3801     private void setPreferredApn(int pos) {
3802         setPreferredApn(pos, false);
3803     }
3804 
setPreferredApn(int pos, boolean force)3805     private void setPreferredApn(int pos, boolean force) {
3806         if (!force && !mCanSetPreferApn) {
3807             log("setPreferredApn: X !canSEtPreferApn");
3808             return;
3809         }
3810 
3811         String subId = Long.toString(mPhone.getSubId());
3812         Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
3813         log("setPreferredApn: delete");
3814         ContentResolver resolver = mPhone.getContext().getContentResolver();
3815         resolver.delete(uri, null, null);
3816 
3817         if (pos >= 0) {
3818             log("setPreferredApn: insert");
3819             ContentValues values = new ContentValues();
3820             values.put(APN_ID, pos);
3821             resolver.insert(uri, values);
3822         }
3823     }
3824 
3825     @Nullable
getPreferredApn()3826     ApnSetting getPreferredApn() {
3827         //Only call this method from main thread
3828         if (mAllApnSettings == null || mAllApnSettings.isEmpty()) {
3829             log("getPreferredApn: mAllApnSettings is empty");
3830             return null;
3831         }
3832 
3833         String subId = Long.toString(mPhone.getSubId());
3834         Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
3835         Cursor cursor = mPhone.getContext().getContentResolver().query(
3836                 uri, new String[] { "_id", "name", "apn" },
3837                 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
3838 
3839         if (cursor != null) {
3840             mCanSetPreferApn = true;
3841         } else {
3842             mCanSetPreferApn = false;
3843         }
3844 
3845         if (VDBG) {
3846             log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor
3847                     + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0));
3848         }
3849 
3850         if (mCanSetPreferApn && cursor.getCount() > 0) {
3851             int pos;
3852             cursor.moveToFirst();
3853             pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
3854             for(ApnSetting p : mAllApnSettings) {
3855                 if (p.getId() == pos && p.canHandleType(mRequestedApnType)) {
3856                     log("getPreferredApn: For APN type "
3857                             + ApnSetting.getApnTypeString(mRequestedApnType)
3858                             + " found apnSetting " + p);
3859                     cursor.close();
3860                     return p;
3861                 }
3862             }
3863         }
3864 
3865         if (cursor != null) {
3866             cursor.close();
3867         }
3868 
3869         log("getPreferredApn: X not found");
3870         return null;
3871     }
3872 
3873     @Override
handleMessage(Message msg)3874     public void handleMessage (Message msg) {
3875         if (VDBG) log("handleMessage msg=" + msg);
3876 
3877         AsyncResult ar;
3878         Pair<ApnContext, Integer> pair;
3879         ApnContext apnContext;
3880         int generation;
3881         int requestType;
3882         int handoverFailureMode;
3883         switch (msg.what) {
3884             case DctConstants.EVENT_DATA_CONNECTION_DETACHED:
3885                 onDataConnectionDetached();
3886                 break;
3887 
3888             case DctConstants.EVENT_DATA_CONNECTION_ATTACHED:
3889                 onDataConnectionAttached();
3890                 break;
3891 
3892             case DctConstants.EVENT_DO_RECOVERY:
3893                 mDsRecoveryHandler.doRecovery();
3894                 break;
3895 
3896             case DctConstants.EVENT_APN_CHANGED:
3897                 onApnChanged();
3898                 break;
3899 
3900             case DctConstants.EVENT_PS_RESTRICT_ENABLED:
3901                 /**
3902                  * We don't need to explicitly to tear down the PDP context
3903                  * when PS restricted is enabled. The base band will deactive
3904                  * PDP context and notify us with PDP_CONTEXT_CHANGED.
3905                  * But we should stop the network polling and prevent reset PDP.
3906                  */
3907                 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
3908                 stopNetStatPoll();
3909                 stopDataStallAlarm();
3910                 mIsPsRestricted = true;
3911                 break;
3912 
3913             case DctConstants.EVENT_PS_RESTRICT_DISABLED:
3914                 /**
3915                  * When PS restrict is removed, we need setup PDP connection if
3916                  * PDP connection is down.
3917                  */
3918                 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
3919                 mIsPsRestricted  = false;
3920                 if (isAnyDataConnected()) {
3921                     startNetStatPoll();
3922                     startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
3923                 } else {
3924                     // TODO: Should all PDN states be checked to fail?
3925                     if (mState == DctConstants.State.FAILED) {
3926                         cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED);
3927                         mReregisterOnReconnectFailure = false;
3928                     }
3929                     apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
3930                     if (apnContext != null) {
3931                         apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
3932                         trySetupData(apnContext, REQUEST_TYPE_NORMAL, null);
3933                     } else {
3934                         loge("**** Default ApnContext not found ****");
3935                         if (TelephonyUtils.IS_DEBUGGABLE) {
3936                             throw new RuntimeException("Default ApnContext not found");
3937                         }
3938                     }
3939                 }
3940                 break;
3941 
3942             case DctConstants.EVENT_TRY_SETUP_DATA:
3943                 apnContext = (ApnContext) msg.obj;
3944                 requestType = msg.arg1;
3945                 trySetupData(apnContext, requestType, null);
3946                 break;
3947             case DctConstants.EVENT_CLEAN_UP_CONNECTION:
3948                 if (DBG) log("EVENT_CLEAN_UP_CONNECTION");
3949                 cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, (ApnContext) msg.obj);
3950                 break;
3951             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS:
3952                 if ((msg.obj != null) && (msg.obj instanceof String == false)) {
3953                     msg.obj = null;
3954                 }
3955                 cleanUpAllConnectionsInternal(true, (String) msg.obj);
3956                 break;
3957 
3958             case DctConstants.EVENT_DATA_RAT_CHANGED:
3959                 if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
3960                     // unknown rat is an exception for data rat change. It's only received when out
3961                     // of service and is not applicable for apn bearer bitmask. We should bypass the
3962                     // check of waiting apn list and keep the data connection on, and no need to
3963                     // setup a new one.
3964                     break;
3965                 }
3966                 cleanUpConnectionsOnUpdatedApns(false, Phone.REASON_NW_TYPE_CHANGED);
3967                 //May new Network allow setupData, so try it here
3968                 setupDataOnAllConnectableApns(Phone.REASON_NW_TYPE_CHANGED,
3969                         RetryFailures.ONLY_ON_CHANGE);
3970                 break;
3971 
3972             case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER:
3973                 // Check message sender intended to clear the current spinner.
3974                 if (mProvisioningSpinner == msg.obj) {
3975                     mProvisioningSpinner.dismiss();
3976                     mProvisioningSpinner = null;
3977                 }
3978                 break;
3979 
3980             case DctConstants.EVENT_ENABLE_APN:
3981                 onEnableApn(msg.arg1, msg.arg2, (Message) msg.obj);
3982                 break;
3983 
3984             case DctConstants.EVENT_DISABLE_APN:
3985                 onDisableApn(msg.arg1, msg.arg2);
3986                 break;
3987 
3988             case DctConstants.EVENT_DATA_STALL_ALARM:
3989                 onDataStallAlarm(msg.arg1);
3990                 break;
3991 
3992             case DctConstants.EVENT_ROAMING_OFF:
3993                 onDataRoamingOff();
3994                 break;
3995 
3996             case DctConstants.EVENT_ROAMING_ON:
3997             case DctConstants.EVENT_ROAMING_SETTING_CHANGE:
3998                 onDataRoamingOnOrSettingsChanged(msg.what);
3999                 break;
4000 
4001             case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE:
4002                 // Update sharedPreference to false when exits new device provisioning, indicating
4003                 // no users modifications on the settings for new devices. Thus carrier specific
4004                 // default roaming settings can be applied for new devices till user modification.
4005                 final SharedPreferences sp = PreferenceManager
4006                         .getDefaultSharedPreferences(mPhone.getContext());
4007                 if (!sp.contains(Phone.DATA_ROAMING_IS_USER_SETTING_KEY)) {
4008                     sp.edit().putBoolean(Phone.DATA_ROAMING_IS_USER_SETTING_KEY, false).commit();
4009                 }
4010                 break;
4011 
4012             case DctConstants.EVENT_NETWORK_STATUS_CHANGED:
4013                 int status = msg.arg1;
4014                 int cid = msg.arg2;
4015                 String url = (String) msg.obj;
4016                 onNetworkStatusChanged(status, cid, url);
4017                 break;
4018 
4019             case DctConstants.EVENT_RADIO_AVAILABLE:
4020                 onRadioAvailable();
4021                 break;
4022 
4023             case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
4024                 onRadioOffOrNotAvailable();
4025                 break;
4026 
4027             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
4028                 ar = (AsyncResult) msg.obj;
4029                 pair = (Pair<ApnContext, Integer>) ar.userObj;
4030                 apnContext = pair.first;
4031                 generation = pair.second;
4032                 requestType = msg.arg1;
4033                 handoverFailureMode = msg.arg2;
4034                 if (apnContext.getConnectionGeneration() == generation) {
4035                     boolean success = true;
4036                     int cause = DataFailCause.UNKNOWN;
4037                     if (ar.exception != null) {
4038                         success = false;
4039                         cause = (int) ar.result;
4040                     }
4041                     onDataSetupComplete(apnContext, success, cause, requestType,
4042                             handoverFailureMode);
4043                 } else {
4044                     loge("EVENT_DATA_SETUP_COMPLETE: Dropped the event because generation "
4045                             + "did not match.");
4046                 }
4047                 break;
4048 
4049             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
4050                 ar = (AsyncResult) msg.obj;
4051                 pair = (Pair<ApnContext, Integer>) ar.userObj;
4052                 apnContext = pair.first;
4053                 generation = pair.second;
4054                 handoverFailureMode = msg.arg2;
4055                 if (apnContext.getConnectionGeneration() == generation) {
4056                     onDataSetupCompleteError(apnContext, handoverFailureMode, false);
4057                 } else {
4058                     loge("EVENT_DATA_SETUP_COMPLETE_ERROR: Dropped the event because generation "
4059                             + "did not match.");
4060                 }
4061                 break;
4062 
4063             case DctConstants.EVENT_DISCONNECT_DONE:
4064                 log("EVENT_DISCONNECT_DONE msg=" + msg);
4065                 ar = (AsyncResult) msg.obj;
4066                 pair = (Pair<ApnContext, Integer>) ar.userObj;
4067                 apnContext = pair.first;
4068                 generation = pair.second;
4069                 if (apnContext.getConnectionGeneration() == generation) {
4070                     onDisconnectDone(apnContext);
4071                 } else {
4072                     loge("EVENT_DISCONNECT_DONE: Dropped the event because generation "
4073                             + "did not match.");
4074                 }
4075                 break;
4076 
4077             case DctConstants.EVENT_VOICE_CALL_STARTED:
4078                 onVoiceCallStarted();
4079                 break;
4080 
4081             case DctConstants.EVENT_VOICE_CALL_ENDED:
4082                 onVoiceCallEnded();
4083                 break;
4084             case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
4085                 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1;
4086                 if (DBG) {
4087                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
4088                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
4089                 }
4090                 if (sEnableFailFastRefCounter < 0) {
4091                     final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
4092                             + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0";
4093                     loge(s);
4094                     sEnableFailFastRefCounter = 0;
4095                 }
4096                 final boolean enabled = sEnableFailFastRefCounter > 0;
4097                 if (DBG) {
4098                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled
4099                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
4100                 }
4101                 if (mFailFast != enabled) {
4102                     mFailFast = enabled;
4103 
4104                     mDataStallNoRxEnabled = !enabled;
4105                     if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled()
4106                             && isAnyDataConnected()
4107                             && (!mInVoiceCall ||
4108                                     mPhone.getServiceStateTracker()
4109                                         .isConcurrentVoiceAndDataAllowed())) {
4110                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall");
4111                         stopDataStallAlarm();
4112                         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
4113                     } else {
4114                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall");
4115                         stopDataStallAlarm();
4116                     }
4117                 }
4118 
4119                 break;
4120             }
4121             case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: {
4122                 Bundle bundle = msg.getData();
4123                 if (bundle != null) {
4124                     try {
4125                         mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY);
4126                     } catch(ClassCastException e) {
4127                         loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e);
4128                         mProvisioningUrl = null;
4129                     }
4130                 }
4131                 if (TextUtils.isEmpty(mProvisioningUrl)) {
4132                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring");
4133                     mIsProvisioning = false;
4134                     mProvisioningUrl = null;
4135                 } else {
4136                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl);
4137                     mIsProvisioning = true;
4138                     startProvisioningApnAlarm();
4139                 }
4140                 break;
4141             }
4142             case DctConstants.EVENT_PROVISIONING_APN_ALARM: {
4143                 if (DBG) log("EVENT_PROVISIONING_APN_ALARM");
4144                 ApnContext apnCtx = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
4145                 if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) {
4146                     if (mProvisioningApnAlarmTag == msg.arg1) {
4147                         if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting");
4148                         mIsProvisioning = false;
4149                         mProvisioningUrl = null;
4150                         stopProvisioningApnAlarm();
4151                         cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnCtx);
4152                     } else {
4153                         if (DBG) {
4154                             log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
4155                                     + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag
4156                                     + " != arg1:" + msg.arg1);
4157                         }
4158                     }
4159                 } else {
4160                     if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore");
4161                 }
4162                 break;
4163             }
4164             case DctConstants.CMD_IS_PROVISIONING_APN: {
4165                 if (DBG) log("CMD_IS_PROVISIONING_APN");
4166                 boolean isProvApn;
4167                 try {
4168                     String apnType = null;
4169                     Bundle bundle = msg.getData();
4170                     if (bundle != null) {
4171                         apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
4172                     }
4173                     if (TextUtils.isEmpty(apnType)) {
4174                         loge("CMD_IS_PROVISIONING_APN: apnType is empty");
4175                         isProvApn = false;
4176                     } else {
4177                         isProvApn = isProvisioningApn(apnType);
4178                     }
4179                 } catch (ClassCastException e) {
4180                     loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring");
4181                     isProvApn = false;
4182                 }
4183                 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn);
4184                 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN,
4185                         isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED);
4186                 break;
4187             }
4188             case DctConstants.EVENT_RESTART_RADIO: {
4189                 restartRadio();
4190                 break;
4191             }
4192             case DctConstants.CMD_NET_STAT_POLL: {
4193                 if (msg.arg1 == DctConstants.ENABLED) {
4194                     handleStartNetStatPoll((DctConstants.Activity)msg.obj);
4195                 } else if (msg.arg1 == DctConstants.DISABLED) {
4196                     handleStopNetStatPoll((DctConstants.Activity)msg.obj);
4197                 }
4198                 break;
4199             }
4200             case DctConstants.EVENT_PCO_DATA_RECEIVED: {
4201                 handlePcoData((AsyncResult)msg.obj);
4202                 break;
4203             }
4204             case DctConstants.EVENT_DATA_RECONNECT:
4205                 if (DBG) {
4206                     log("EVENT_DATA_RECONNECT: subId=" + msg.arg1 + ", type="
4207                             + requestTypeToString(msg.arg2));
4208                 }
4209                 onDataReconnect((ApnContext) msg.obj, msg.arg1, msg.arg2);
4210                 break;
4211             case DctConstants.EVENT_DATA_SERVICE_BINDING_CHANGED:
4212                 onDataServiceBindingChanged((Boolean) ((AsyncResult) msg.obj).result);
4213                 break;
4214             case DctConstants.EVENT_DATA_ENABLED_CHANGED:
4215                 ar = (AsyncResult) msg.obj;
4216                 if (ar.result instanceof Pair) {
4217                     Pair<Boolean, Integer> p = (Pair<Boolean, Integer>) ar.result;
4218                     boolean enabled = p.first;
4219                     int reason = p.second;
4220                     onDataEnabledChanged(enabled, reason);
4221                 }
4222                 break;
4223             case DctConstants.EVENT_DATA_ENABLED_OVERRIDE_RULES_CHANGED:
4224                 onDataEnabledOverrideRulesChanged();
4225                 break;
4226             case DctConstants.EVENT_NR_TIMER_WATCHDOG:
4227                 mWatchdog = false;
4228                 reevaluateUnmeteredConnections();
4229                 break;
4230             case DctConstants.EVENT_TELEPHONY_DISPLAY_INFO_CHANGED:
4231                 reevaluateCongestedConnections();
4232                 reevaluateUnmeteredConnections();
4233                 break;
4234             case DctConstants.EVENT_CARRIER_CONFIG_CHANGED:
4235                 onCarrierConfigChanged();
4236                 break;
4237             case DctConstants.EVENT_SIM_STATE_UPDATED:
4238                 int simState = msg.arg1;
4239                 onSimStateUpdated(simState);
4240                 break;
4241             case DctConstants.EVENT_APN_UNTHROTTLED:
4242                 ar = (AsyncResult) msg.obj;
4243                 String apn = (String) ar.result;
4244                 onApnUnthrottled(apn);
4245                 break;
4246             case DctConstants.EVENT_TRAFFIC_DESCRIPTORS_UPDATED:
4247                 onTrafficDescriptorsUpdated();
4248                 break;
4249             default:
4250                 Rlog.e("DcTracker", "Unhandled event=" + msg);
4251                 break;
4252 
4253         }
4254     }
4255 
getApnProfileID(String apnType)4256     private int getApnProfileID(String apnType) {
4257         if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) {
4258             return RILConstants.DATA_PROFILE_IMS;
4259         } else if (TextUtils.equals(apnType, ApnSetting.TYPE_FOTA_STRING)) {
4260             return RILConstants.DATA_PROFILE_FOTA;
4261         } else if (TextUtils.equals(apnType, ApnSetting.TYPE_CBS_STRING)) {
4262             return RILConstants.DATA_PROFILE_CBS;
4263         } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IA_STRING)) {
4264             return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now
4265         } else if (TextUtils.equals(apnType, ApnSetting.TYPE_DUN_STRING)) {
4266             return RILConstants.DATA_PROFILE_TETHERED;
4267         } else {
4268             return RILConstants.DATA_PROFILE_DEFAULT;
4269         }
4270     }
4271 
getCellLocationId()4272     private int getCellLocationId() {
4273         int cid = -1;
4274         CellLocation loc = mPhone.getCurrentCellIdentity().asCellLocation();
4275 
4276         if (loc != null) {
4277             if (loc instanceof GsmCellLocation) {
4278                 cid = ((GsmCellLocation)loc).getCid();
4279             } else if (loc instanceof CdmaCellLocation) {
4280                 cid = ((CdmaCellLocation)loc).getBaseStationId();
4281             }
4282         }
4283         return cid;
4284     }
4285 
4286     /**
4287      * Update link bandwidth estimate default values from carrier config.
4288      * @param bandwidths String array of "RAT:upstream,downstream" for each RAT
4289      * @param useLte For NR NSA, whether to use LTE value for upstream or not
4290      */
updateLinkBandwidths(String[] bandwidths, boolean useLte)4291     private void updateLinkBandwidths(String[] bandwidths, boolean useLte) {
4292         ConcurrentHashMap<String, Pair<Integer, Integer>> temp = new ConcurrentHashMap<>();
4293         for (String config : bandwidths) {
4294             int downstream = 14;
4295             int upstream = 14;
4296             String[] kv = config.split(":");
4297             if (kv.length == 2) {
4298                 String[] split = kv[1].split(",");
4299                 if (split.length == 2) {
4300                     try {
4301                         downstream = Integer.parseInt(split[0]);
4302                         upstream = Integer.parseInt(split[1]);
4303                     } catch (NumberFormatException ignored) {
4304                     }
4305                 }
4306                 temp.put(kv[0], new Pair<>(downstream, upstream));
4307             }
4308         }
4309         if (useLte) {
4310             Pair<Integer, Integer> ltePair =
4311                     temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_LTE);
4312             if (ltePair != null) {
4313                 if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA)) {
4314                     temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA, new Pair<>(
4315                             temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA).first,
4316                             ltePair.second));
4317                 }
4318                 if (temp.containsKey(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE)) {
4319                     temp.put(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE, new Pair<>(
4320                             temp.get(DataConfigManager.DATA_CONFIG_NETWORK_TYPE_NR_NSA_MMWAVE)
4321                                     .first, ltePair.second));
4322                 }
4323             }
4324         }
4325         mBandwidths = temp;
4326         for (DataConnection dc : mDataConnections.values()) {
4327             dc.sendMessage(DataConnection.EVENT_CARRIER_CONFIG_LINK_BANDWIDTHS_CHANGED);
4328         }
4329     }
4330 
4331     /**
4332      * Return the link upstream/downstream values from CarrierConfig for the given RAT name.
4333      * @param ratName RAT name from ServiceState#rilRadioTechnologyToString.
4334      * @return pair of downstream/upstream values (kbps), or null if the config is not defined.
4335      */
getLinkBandwidthsFromCarrierConfig(String ratName)4336     public Pair<Integer, Integer> getLinkBandwidthsFromCarrierConfig(String ratName) {
4337         return mBandwidths.get(ratName);
4338     }
4339 
4340     @VisibleForTesting
shouldAutoAttach()4341     public boolean shouldAutoAttach() {
4342         if (mAutoAttachEnabled.get()) return true;
4343 
4344         PhoneSwitcher phoneSwitcher = PhoneSwitcher.getInstance();
4345         ServiceState serviceState = mPhone.getServiceState();
4346 
4347         if (phoneSwitcher == null || serviceState == null) return false;
4348 
4349         // If voice is also not in service, don't auto attach.
4350         if (serviceState.getState() != ServiceState.STATE_IN_SERVICE) return false;
4351 
4352         // If voice is on LTE or NR, don't auto attach as for LTE / NR data would be attached.
4353         if (serviceState.getVoiceNetworkType() == NETWORK_TYPE_LTE
4354                 || serviceState.getVoiceNetworkType() == NETWORK_TYPE_NR) return false;
4355 
4356         // If phone is non default phone, modem may have detached from data for optimization.
4357         // If phone is in voice call, for DSDS case DDS switch may be limited so we do try our
4358         // best to setup data connection and allow auto-attach.
4359         return (mPhone.getPhoneId() != phoneSwitcher.getPreferredDataPhoneId()
4360                 || mPhone.getState() != PhoneConstants.State.IDLE);
4361     }
4362 
notifyAllDataDisconnected()4363     private void notifyAllDataDisconnected() {
4364         sEnableFailFastRefCounter = 0;
4365         mFailFast = false;
4366         log("notify all data disconnected");
4367         mAllDataDisconnectedRegistrants.notifyRegistrants();
4368     }
4369 
registerForAllDataDisconnected(Handler h, int what)4370     public void registerForAllDataDisconnected(Handler h, int what) {
4371         mAllDataDisconnectedRegistrants.addUnique(h, what, null);
4372 
4373         if (areAllDataDisconnected()) {
4374             notifyAllDataDisconnected();
4375         }
4376     }
4377 
unregisterForAllDataDisconnected(Handler h)4378     public void unregisterForAllDataDisconnected(Handler h) {
4379         mAllDataDisconnectedRegistrants.remove(h);
4380     }
4381 
onDataEnabledChanged(boolean enable, @DataEnabledChangedReason int enabledChangedReason)4382     private void onDataEnabledChanged(boolean enable,
4383                                       @DataEnabledChangedReason int enabledChangedReason) {
4384         if (DBG) {
4385             log("onDataEnabledChanged: enable=" + enable + ", enabledChangedReason="
4386                     + enabledChangedReason);
4387         }
4388 
4389         if (enable) {
4390             reevaluateDataConnections();
4391             setupDataOnAllConnectableApns(Phone.REASON_DATA_ENABLED, RetryFailures.ALWAYS);
4392         } else {
4393             String cleanupReason;
4394             switch (enabledChangedReason) {
4395                 case DataEnabledSettings.REASON_INTERNAL_DATA_ENABLED:
4396                     cleanupReason = Phone.REASON_DATA_DISABLED_INTERNAL;
4397                     break;
4398                 case DataEnabledSettings.REASON_DATA_ENABLED_BY_CARRIER:
4399                     cleanupReason = Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN;
4400                     break;
4401                 case DataEnabledSettings.REASON_USER_DATA_ENABLED:
4402                 case DataEnabledSettings.REASON_POLICY_DATA_ENABLED:
4403                 case DataEnabledSettings.REASON_PROVISIONED_CHANGED:
4404                 case DataEnabledSettings.REASON_PROVISIONING_DATA_ENABLED_CHANGED:
4405                 default:
4406                     cleanupReason = Phone.REASON_DATA_SPECIFIC_DISABLED;
4407                     break;
4408 
4409             }
4410             cleanUpAllConnectionsInternal(true, cleanupReason);
4411         }
4412     }
4413 
reevaluateCongestedConnections()4414     private void reevaluateCongestedConnections() {
4415         log("reevaluateCongestedConnections");
4416         int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType();
4417         // congested override and either network is specified or unknown and all networks specified
4418         boolean isCongested = mCongestedOverride && (mCongestedNetworkTypes.contains(rat)
4419                 || mCongestedNetworkTypes.containsAll(Arrays.stream(
4420                 TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet())));
4421         for (DataConnection dataConnection : mDataConnections.values()) {
4422             dataConnection.onCongestednessChanged(isCongested);
4423         }
4424     }
4425 
reevaluateUnmeteredConnections()4426     private void reevaluateUnmeteredConnections() {
4427         log("reevaluateUnmeteredConnections");
4428         int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType();
4429         if (isNrUnmetered() && (!mPhone.getServiceState().getRoaming() || mNrNsaRoamingUnmetered)) {
4430             setDataConnectionUnmetered(true);
4431             if (!mWatchdog) {
4432                 startWatchdogAlarm();
4433             }
4434         } else {
4435             stopWatchdogAlarm();
4436             setDataConnectionUnmetered(isNetworkTypeUnmetered(rat));
4437         }
4438     }
4439 
setDataConnectionUnmetered(boolean isUnmetered)4440     private void setDataConnectionUnmetered(boolean isUnmetered) {
4441         if (!isUnmetered || isTempNotMeteredSupportedByCarrier()) {
4442             for (DataConnection dataConnection : mDataConnections.values()) {
4443                 dataConnection.onMeterednessChanged(isUnmetered);
4444             }
4445         }
4446     }
4447 
isNetworkTypeUnmetered(@etworkType int networkType)4448     private boolean isNetworkTypeUnmetered(@NetworkType int networkType) {
4449         boolean isUnmetered;
4450         if (mUnmeteredNetworkTypes == null || !mUnmeteredOverride) {
4451             // check SubscriptionPlans if override is not defined
4452             isUnmetered = isNetworkTypeUnmeteredViaSubscriptionPlan(networkType);
4453             log("isNetworkTypeUnmeteredViaSubscriptionPlan: networkType=" + networkType
4454                     + ", isUnmetered=" + isUnmetered);
4455             return isUnmetered;
4456         }
4457         // unmetered override and either network is specified or unknown and all networks specified
4458         isUnmetered = mUnmeteredNetworkTypes.contains(networkType)
4459                 || mUnmeteredNetworkTypes.containsAll(Arrays.stream(
4460                 TelephonyManager.getAllNetworkTypes()).boxed().collect(Collectors.toSet()));
4461         if (DBG) {
4462             log("isNetworkTypeUnmetered: networkType=" + networkType
4463                     + ", isUnmetered=" + isUnmetered);
4464         }
4465         return isUnmetered;
4466     }
4467 
isNetworkTypeUnmeteredViaSubscriptionPlan(@etworkType int networkType)4468     private boolean isNetworkTypeUnmeteredViaSubscriptionPlan(@NetworkType int networkType) {
4469         if (mSubscriptionPlans.isEmpty()) {
4470             // safe return false if unable to get subscription plans or plans don't exist
4471             return false;
4472         }
4473 
4474         boolean isGeneralUnmetered = true;
4475         Set<Integer> allNetworkTypes = Arrays.stream(TelephonyManager.getAllNetworkTypes())
4476                 .boxed().collect(Collectors.toSet());
4477         for (SubscriptionPlan plan : mSubscriptionPlans) {
4478             // check plan is general (applies to all network types) or specific
4479             if (Arrays.stream(plan.getNetworkTypes()).boxed().collect(Collectors.toSet())
4480                     .containsAll(allNetworkTypes)) {
4481                 if (!isPlanUnmetered(plan)) {
4482                     // metered takes precedence over unmetered for safety
4483                     isGeneralUnmetered = false;
4484                 }
4485             } else {
4486                 // check plan applies to given network type
4487                 if (networkType != TelephonyManager.NETWORK_TYPE_UNKNOWN) {
4488                     for (int planNetworkType : plan.getNetworkTypes()) {
4489                         if (planNetworkType == networkType) {
4490                             return isPlanUnmetered(plan);
4491                         }
4492                     }
4493                 }
4494             }
4495         }
4496         return isGeneralUnmetered;
4497     }
4498 
isPlanUnmetered(SubscriptionPlan plan)4499     private boolean isPlanUnmetered(SubscriptionPlan plan) {
4500         return plan.getDataLimitBytes() == SubscriptionPlan.BYTES_UNLIMITED;
4501     }
4502 
isNrUnmetered()4503     private boolean isNrUnmetered() {
4504         int rat = mPhone.getDisplayInfoController().getTelephonyDisplayInfo().getNetworkType();
4505         int override = mPhone.getDisplayInfoController().getTelephonyDisplayInfo()
4506                 .getOverrideNetworkType();
4507 
4508         if (isNetworkTypeUnmetered(NETWORK_TYPE_NR)) {
4509             if (mNrNsaMmwaveUnmetered) {
4510                 if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) {
4511                     if (DBG) log("NR unmetered for mmwave only");
4512                     return true;
4513                 }
4514                 return false;
4515             } else if (mNrNsaSub6Unmetered) {
4516                 if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) {
4517                     if (DBG) log("NR unmetered for sub6 only");
4518                     return true;
4519                 }
4520                 return false;
4521             }
4522             if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
4523                     || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA
4524                     || rat == NETWORK_TYPE_NR) {
4525                 if (DBG) log("NR unmetered for all frequencies");
4526                 return true;
4527             }
4528             return false;
4529         }
4530 
4531         if (mNrNsaAllUnmetered) {
4532             if (mNrNsaMmwaveUnmetered) {
4533                 if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED) {
4534                     if (DBG) log("NR NSA unmetered for mmwave only via carrier configs");
4535                     return true;
4536                 }
4537                 return false;
4538             } else if (mNrNsaSub6Unmetered) {
4539                 if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) {
4540                     if (DBG) log("NR NSA unmetered for sub6 only via carrier configs");
4541                     return true;
4542                 }
4543                 return false;
4544             }
4545             if (override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_ADVANCED
4546                     || override == TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NR_NSA) {
4547                 if (DBG) log("NR NSA unmetered for all frequencies via carrier configs");
4548                 return true;
4549             }
4550             return false;
4551         }
4552 
4553         if (mNrSaAllUnmetered) {
4554             // TODO: add logic for mNrSaMmwaveUnmetered and mNrSaSub6Unmetered once it's defined
4555             // in TelephonyDisplayInfo
4556             if (rat == NETWORK_TYPE_NR) {
4557                 if (DBG) log("NR SA unmetered for all frequencies via carrier configs");
4558                 return true;
4559             }
4560             return false;
4561         }
4562 
4563         return false;
4564     }
4565 
isTempNotMeteredSupportedByCarrier()4566     private boolean isTempNotMeteredSupportedByCarrier() {
4567         CarrierConfigManager configManager =
4568                 mPhone.getContext().getSystemService(CarrierConfigManager.class);
4569         if (configManager != null) {
4570             PersistableBundle bundle = configManager.getConfigForSubId(mPhone.getSubId());
4571             if (bundle != null) {
4572                 return bundle.getBoolean(
4573                         CarrierConfigManager.KEY_NETWORK_TEMP_NOT_METERED_SUPPORTED_BOOL);
4574             }
4575         }
4576 
4577         return false;
4578     }
4579 
log(String s)4580     protected void log(String s) {
4581         Rlog.d(mLogTag, s);
4582     }
4583 
loge(String s)4584     private void loge(String s) {
4585         Rlog.e(mLogTag, s);
4586     }
4587 
logSortedApnContexts()4588     private void logSortedApnContexts() {
4589         if (VDBG) {
4590             log("initApnContexts: X mApnContexts=" + mApnContexts);
4591 
4592             StringBuilder sb = new StringBuilder();
4593             sb.append("sorted apncontexts -> [");
4594             for (ApnContext apnContext : mPrioritySortedApnContexts) {
4595                 sb.append(apnContext);
4596                 sb.append(", ");
4597 
4598                 log("sorted list");
4599             }
4600             sb.append("]");
4601             log(sb.toString());
4602         }
4603     }
4604 
dump(FileDescriptor fd, PrintWriter pw, String[] args)4605     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4606         pw.println("DcTracker:");
4607         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
4608         pw.println(" mDataEnabledSettings=" + mDataEnabledSettings);
4609         pw.println(" isDataAllowed=" + isDataAllowed(null));
4610         pw.flush();
4611         pw.println(" mRequestedApnType=" + mRequestedApnType);
4612         pw.println(" mPhone=" + mPhone.getPhoneName());
4613         pw.println(" mConfigReady=" + mConfigReady);
4614         pw.println(" mSimState=" + SubscriptionInfoUpdater.simStateString(mSimState));
4615         pw.println(" mActivity=" + mActivity);
4616         pw.println(" mState=" + mState);
4617         pw.println(" mTxPkts=" + mTxPkts);
4618         pw.println(" mRxPkts=" + mRxPkts);
4619         pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
4620         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
4621         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
4622         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
4623         pw.println(" mDataStallNoRxEnabled=" + mDataStallNoRxEnabled);
4624         pw.println(" mEmergencyApn=" + mEmergencyApn);
4625         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
4626         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
4627         pw.println(" mResolver=" + mResolver);
4628         pw.println(" mReconnectIntent=" + mReconnectIntent);
4629         pw.println(" mAutoAttachEnabled=" + mAutoAttachEnabled.get());
4630         pw.println(" mIsScreenOn=" + mIsScreenOn);
4631         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
4632         pw.println(" mDataServiceBound=" + mDataServiceBound);
4633         pw.println(" mDataRoamingLeakageLog= ");
4634         mDataRoamingLeakageLog.dump(fd, pw, args);
4635         pw.println(" mApnSettingsInitializationLog= ");
4636         mApnSettingsInitializationLog.dump(fd, pw, args);
4637         pw.flush();
4638         pw.println(" ***************************************");
4639         DcController dcc = mDcc;
4640         if (dcc != null) {
4641             if (mDataServiceBound) {
4642                 dcc.dump(fd, pw, args);
4643             } else {
4644                 pw.println(" Can't dump mDcc because data service is not bound.");
4645             }
4646         } else {
4647             pw.println(" mDcc=null");
4648         }
4649         pw.println(" ***************************************");
4650         HashMap<Integer, DataConnection> dcs = mDataConnections;
4651         if (dcs != null) {
4652             Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
4653             pw.println(" mDataConnections: count=" + mDcSet.size());
4654             for (Entry<Integer, DataConnection> entry : mDcSet) {
4655                 pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
4656                 entry.getValue().dump(fd, pw, args);
4657             }
4658         } else {
4659             pw.println("mDataConnections=null");
4660         }
4661         pw.println(" ***************************************");
4662         pw.flush();
4663         HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
4664         if (apnToDcId != null) {
4665             Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
4666             pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
4667             for (Entry<String, Integer> entry : apnToDcIdSet) {
4668                 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
4669             }
4670         } else {
4671             pw.println("mApnToDataConnectionId=null");
4672         }
4673         pw.println(" ***************************************");
4674         pw.flush();
4675         ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
4676         if (apnCtxs != null) {
4677             Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
4678             pw.println(" mApnContexts size=" + apnCtxsSet.size());
4679             for (Entry<String, ApnContext> entry : apnCtxsSet) {
4680                 entry.getValue().dump(fd, pw, args);
4681             }
4682             ApnContext.dumpLocalLog(fd, pw, args);
4683             pw.println(" ***************************************");
4684         } else {
4685             pw.println(" mApnContexts=null");
4686         }
4687         pw.flush();
4688 
4689         pw.println(" mAllApnSettings size=" + mAllApnSettings.size());
4690         for (int i = 0; i < mAllApnSettings.size(); i++) {
4691             pw.printf(" mAllApnSettings[%d]: %s\n", i, mAllApnSettings.get(i));
4692         }
4693         pw.flush();
4694 
4695         pw.println(" mPreferredApn=" + mPreferredApn);
4696         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
4697         pw.println(" mIsDisposed=" + mIsDisposed);
4698         pw.println(" mIntentReceiver=" + mIntentReceiver);
4699         pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure);
4700         pw.println(" canSetPreferApn=" + mCanSetPreferApn);
4701         pw.println(" mApnObserver=" + mApnObserver);
4702         pw.println(" isAnyDataConnected=" + isAnyDataConnected());
4703         pw.println(" mAttached=" + mAttached.get());
4704         mDataEnabledSettings.dump(fd, pw, args);
4705         pw.flush();
4706     }
4707 
getPcscfAddress(String apnType)4708     public String[] getPcscfAddress(String apnType) {
4709         log("getPcscfAddress()");
4710         ApnContext apnContext = null;
4711 
4712         if(apnType == null){
4713             log("apnType is null, return null");
4714             return null;
4715         }
4716 
4717         if (TextUtils.equals(apnType, ApnSetting.TYPE_EMERGENCY_STRING)) {
4718             apnContext = mApnContextsByType.get(ApnSetting.TYPE_EMERGENCY);
4719         } else if (TextUtils.equals(apnType, ApnSetting.TYPE_IMS_STRING)) {
4720             apnContext = mApnContextsByType.get(ApnSetting.TYPE_IMS);
4721         } else {
4722             log("apnType is invalid, return null");
4723             return null;
4724         }
4725 
4726         if (apnContext == null) {
4727             log("apnContext is null, return null");
4728             return null;
4729         }
4730 
4731         DataConnection dataConnection = apnContext.getDataConnection();
4732         String[] result = null;
4733 
4734         if (dataConnection != null) {
4735             result = dataConnection.getPcscfAddresses();
4736 
4737             if (result != null) {
4738                 for (int i = 0; i < result.length; i++) {
4739                     log("Pcscf[" + i + "]: " + result[i]);
4740                 }
4741             }
4742             return result;
4743         }
4744         return null;
4745     }
4746 
4747     /**
4748      * Create default apn settings for the apn type like emergency, and ims
4749      */
buildDefaultApnSetting(@onNull String entry, @NonNull String apn, @ApnType int apnTypeBitmask)4750     private ApnSetting buildDefaultApnSetting(@NonNull String entry,
4751             @NonNull String apn, @ApnType int apnTypeBitmask) {
4752         return new ApnSetting.Builder()
4753                 .setEntryName(entry)
4754                 .setProtocol(ApnSetting.PROTOCOL_IPV4V6)
4755                 .setRoamingProtocol(ApnSetting.PROTOCOL_IPV4V6)
4756                 .setApnName(apn)
4757                 .setApnTypeBitmask(apnTypeBitmask)
4758                 .setCarrierEnabled(true)
4759                 .setApnSetId(Telephony.Carriers.MATCH_ALL_APN_SET_ID)
4760                 .build();
4761     }
4762 
4763     /**
4764      * Add default APN settings to APN settings list as needed
4765      */
addDefaultApnSettingsAsNeeded()4766     private void addDefaultApnSettingsAsNeeded() {
4767         boolean isEmergencyApnConfigured = false;
4768         boolean isImsApnConfigured = false;
4769 
4770         for (ApnSetting apn : mAllApnSettings) {
4771             if (apn.canHandleType(ApnSetting.TYPE_EMERGENCY)) {
4772                 isEmergencyApnConfigured = true;
4773             }
4774             if (apn.canHandleType(ApnSetting.TYPE_IMS)) {
4775                 isImsApnConfigured = true;
4776             }
4777             if (isEmergencyApnConfigured && isImsApnConfigured) {
4778                 log("Both emergency and ims apn setting are already present");
4779                 return;
4780             }
4781         }
4782 
4783         // Add default apn setting for emergency service if it is not present
4784         if (!isEmergencyApnConfigured) {
4785             mAllApnSettings.add(buildDefaultApnSetting(
4786                     "DEFAULT EIMS", "sos", ApnSetting.TYPE_EMERGENCY));
4787             log("default emergency apn is created");
4788         }
4789 
4790         // Only add default apn setting for ims when it is not present and sim is loaded
4791         if (!isImsApnConfigured && mSimState == TelephonyManager.SIM_STATE_LOADED) {
4792             mAllApnSettings.add(buildDefaultApnSetting(
4793                     "DEFAULT IMS", "ims", ApnSetting.TYPE_IMS));
4794             log("default ims apn is created");
4795         }
4796     }
4797 
cleanUpConnectionsOnUpdatedApns(boolean detach, String reason)4798     private void cleanUpConnectionsOnUpdatedApns(boolean detach, String reason) {
4799         if (DBG) log("cleanUpConnectionsOnUpdatedApns: detach=" + detach);
4800         if (mAllApnSettings.isEmpty()) {
4801             cleanUpAllConnectionsInternal(detach, Phone.REASON_APN_CHANGED);
4802         } else {
4803             if (getDataRat() == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
4804                 // unknown rat is an exception for data rat change. Its only received when out of
4805                 // service and is not applicable for apn bearer bitmask. We should bypass the check
4806                 // of waiting apn list and keep the data connection on.
4807                 return;
4808             }
4809             for (ApnContext apnContext : mApnContexts.values()) {
4810                 boolean cleanupRequired = true;
4811                 if (!apnContext.isDisconnected()) {
4812                     ArrayList<ApnSetting> waitingApns = buildWaitingApns(
4813                             apnContext.getApnType(), getDataRat());
4814                     if (apnContext.getWaitingApns().size() != waitingApns.size()
4815                             || !apnContext.getWaitingApns().containsAll(waitingApns)) {
4816                         apnContext.setWaitingApns(waitingApns);
4817                     }
4818                     for (ApnSetting apnSetting : waitingApns) {
4819                         if (areCompatible(apnSetting, apnContext.getApnSetting())) {
4820                             cleanupRequired = false;
4821                             break;
4822                         }
4823                     }
4824 
4825                     if (cleanupRequired) {
4826                         if (DBG) {
4827                             log("cleanUpConnectionsOnUpdatedApns: APN type "
4828                                     + apnContext.getApnType() + " clean up is required. The new "
4829                                     + "waiting APN list " + waitingApns + " does not cover "
4830                                     + apnContext.getApnSetting());
4831                         }
4832                         apnContext.setReason(reason);
4833                         cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext);
4834                     }
4835                 }
4836             }
4837         }
4838 
4839         if (!isAnyDataConnected()) {
4840             stopNetStatPoll();
4841             stopDataStallAlarm();
4842         }
4843 
4844         mRequestedApnType = ApnSetting.TYPE_DEFAULT;
4845 
4846         if (areAllDataDisconnected()) {
4847             notifyAllDataDisconnected();
4848         }
4849     }
4850 
4851     /**
4852      * Polling stuff
4853      */
resetPollStats()4854     protected void resetPollStats() {
4855         mTxPkts = -1;
4856         mRxPkts = -1;
4857         mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
4858     }
4859 
startNetStatPoll()4860     protected void startNetStatPoll() {
4861         if (isAnyDataConnected() && !mNetStatPollEnabled) {
4862             if (DBG) {
4863                 log("startNetStatPoll");
4864             }
4865             resetPollStats();
4866             mNetStatPollEnabled = true;
4867             mPollNetStat.run();
4868         }
4869         if (mPhone != null) {
4870             mPhone.notifyDataActivity();
4871         }
4872     }
4873 
stopNetStatPoll()4874     protected void stopNetStatPoll() {
4875         mNetStatPollEnabled = false;
4876         removeCallbacks(mPollNetStat);
4877         if (DBG) {
4878             log("stopNetStatPoll");
4879         }
4880 
4881         // To sync data activity icon in the case of switching data connection to send MMS.
4882         if (mPhone != null) {
4883             mPhone.notifyDataActivity();
4884         }
4885     }
4886 
sendStartNetStatPoll(DctConstants.Activity activity)4887     public void sendStartNetStatPoll(DctConstants.Activity activity) {
4888         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
4889         msg.arg1 = DctConstants.ENABLED;
4890         msg.obj = activity;
4891         sendMessage(msg);
4892     }
4893 
handleStartNetStatPoll(DctConstants.Activity activity)4894     private void handleStartNetStatPoll(DctConstants.Activity activity) {
4895         startNetStatPoll();
4896         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
4897         setActivity(activity);
4898     }
4899 
sendStopNetStatPoll(DctConstants.Activity activity)4900     public void sendStopNetStatPoll(DctConstants.Activity activity) {
4901         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
4902         msg.arg1 = DctConstants.DISABLED;
4903         msg.obj = activity;
4904         sendMessage(msg);
4905     }
4906 
handleStopNetStatPoll(DctConstants.Activity activity)4907     private void handleStopNetStatPoll(DctConstants.Activity activity) {
4908         stopNetStatPoll();
4909         stopDataStallAlarm();
4910         setActivity(activity);
4911     }
4912 
onDataEnabledOverrideRulesChanged()4913     private void onDataEnabledOverrideRulesChanged() {
4914         if (DBG) {
4915             log("onDataEnabledOverrideRulesChanged");
4916         }
4917 
4918         for (ApnContext apnContext : mPrioritySortedApnContexts) {
4919             if (isDataAllowed(apnContext, REQUEST_TYPE_NORMAL, null)) {
4920                 if (apnContext.getDataConnection() != null) {
4921                     apnContext.getDataConnection().reevaluateRestrictedState();
4922                 }
4923                 setupDataOnConnectableApn(apnContext, Phone.REASON_DATA_ENABLED_OVERRIDE,
4924                         RetryFailures.ALWAYS);
4925             } else if (shouldCleanUpConnection(apnContext, true, false)) {
4926                 apnContext.setReason(Phone.REASON_DATA_ENABLED_OVERRIDE);
4927                 cleanUpConnectionInternal(true, RELEASE_TYPE_DETACH, apnContext);
4928             }
4929         }
4930     }
4931 
updateDataActivity()4932     private void updateDataActivity() {
4933         long sent, received;
4934 
4935         DctConstants.Activity newActivity;
4936 
4937         TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts);
4938         TxRxSum curTxRxSum = new TxRxSum();
4939         curTxRxSum.updateTotalTxRxSum();
4940         mTxPkts = curTxRxSum.txPkts;
4941         mRxPkts = curTxRxSum.rxPkts;
4942 
4943         if (VDBG) {
4944             log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum);
4945         }
4946 
4947         if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) {
4948             sent = mTxPkts - preTxRxSum.txPkts;
4949             received = mRxPkts - preTxRxSum.rxPkts;
4950 
4951             if (VDBG)
4952                 log("updateDataActivity: sent=" + sent + " received=" + received);
4953             if (sent > 0 && received > 0) {
4954                 newActivity = DctConstants.Activity.DATAINANDOUT;
4955             } else if (sent > 0 && received == 0) {
4956                 newActivity = DctConstants.Activity.DATAOUT;
4957             } else if (sent == 0 && received > 0) {
4958                 newActivity = DctConstants.Activity.DATAIN;
4959             } else {
4960                 newActivity = (mActivity == DctConstants.Activity.DORMANT) ?
4961                         mActivity : DctConstants.Activity.NONE;
4962             }
4963 
4964             if (mActivity != newActivity && mIsScreenOn) {
4965                 if (VDBG)
4966                     log("updateDataActivity: newActivity=" + newActivity);
4967                 mActivity = newActivity;
4968                 mPhone.notifyDataActivity();
4969             }
4970         }
4971     }
4972 
handlePcoData(AsyncResult ar)4973     private void handlePcoData(AsyncResult ar) {
4974         if (ar.exception != null) {
4975             loge("PCO_DATA exception: " + ar.exception);
4976             return;
4977         }
4978         PcoData pcoData = (PcoData)(ar.result);
4979         ArrayList<DataConnection> dcList = new ArrayList<>();
4980         DataConnection temp = mDcc.getActiveDcByCid(pcoData.cid);
4981         if (temp != null) {
4982             dcList.add(temp);
4983         }
4984         if (dcList.size() == 0) {
4985             loge("PCO_DATA for unknown cid: " + pcoData.cid + ", inferring");
4986             for (DataConnection dc : mDataConnections.values()) {
4987                 final int cid = dc.getCid();
4988                 if (cid == pcoData.cid) {
4989                     if (VDBG) log("  found " + dc);
4990                     dcList.clear();
4991                     dcList.add(dc);
4992                     break;
4993                 }
4994                 // check if this dc is still connecting
4995                 if (cid == -1) {
4996                     for (ApnContext apnContext : dc.getApnContexts()) {
4997                         if (apnContext.getState() == DctConstants.State.CONNECTING) {
4998                             if (VDBG) log("  found potential " + dc);
4999                             dcList.add(dc);
5000                             break;
5001                         }
5002                     }
5003                 }
5004             }
5005         }
5006         if (dcList.size() == 0) {
5007             loge("PCO_DATA - couldn't infer cid");
5008             return;
5009         }
5010         for (DataConnection dc : dcList) {
5011             List<ApnContext> apnContextList = dc.getApnContexts();
5012             if (apnContextList.size() == 0) {
5013                 break;
5014             }
5015             // send one out for each apn type in play
5016             for (ApnContext apnContext : apnContextList) {
5017                 String apnType = apnContext.getApnType();
5018 
5019                 final Intent intent = new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_PCO_VALUE);
5020                 intent.putExtra(TelephonyManager.EXTRA_APN_TYPE,
5021                         ApnSetting.getApnTypesBitmaskFromString(apnType));
5022                 intent.putExtra(TelephonyManager.EXTRA_APN_PROTOCOL,
5023                         ApnSetting.getProtocolIntFromString(pcoData.bearerProto));
5024                 intent.putExtra(TelephonyManager.EXTRA_PCO_ID, pcoData.pcoId);
5025                 intent.putExtra(TelephonyManager.EXTRA_PCO_VALUE, pcoData.contents);
5026                 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
5027             }
5028         }
5029     }
5030 
5031     /**
5032      * Data-Stall
5033      */
5034 
5035     // Recovery action taken in case of data stall
5036     @IntDef(
5037         value = {
5038             RECOVERY_ACTION_GET_DATA_CALL_LIST,
5039             RECOVERY_ACTION_CLEANUP,
5040             RECOVERY_ACTION_REREGISTER,
5041             RECOVERY_ACTION_RADIO_RESTART
5042         })
5043     @Retention(RetentionPolicy.SOURCE)
5044     public @interface RecoveryAction {};
5045     private static final int RECOVERY_ACTION_GET_DATA_CALL_LIST      = 0;
5046     private static final int RECOVERY_ACTION_CLEANUP                 = 1;
5047     private static final int RECOVERY_ACTION_REREGISTER              = 2;
5048     private static final int RECOVERY_ACTION_RADIO_RESTART           = 3;
5049 
5050     // Recovery handler class for cellular data stall
5051     private class DataStallRecoveryHandler {
5052         // Default minimum duration between each recovery steps
5053         private static final int
5054                 DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS = (3 * 60 * 1000); // 3 mins
5055 
5056         // The elapsed real time of last recovery attempted
5057         private long mTimeLastRecoveryStartMs;
5058         // Whether current network good or not
5059         private boolean mIsValidNetwork;
5060         // Whether data stall happened or not.
5061         private boolean mWasDataStall;
5062         // Whether the result of last action(RADIO_RESTART) reported.
5063         private boolean mLastActionReported;
5064         // The real time for data stall start.
5065         private long mDataStallStartMs;
5066         // Last data stall action.
5067         private @RecoveryAction int mLastAction;
5068 
DataStallRecoveryHandler()5069         public DataStallRecoveryHandler() {
5070             reset();
5071         }
5072 
reset()5073         public void reset() {
5074             mTimeLastRecoveryStartMs = 0;
5075             putRecoveryAction(RECOVERY_ACTION_GET_DATA_CALL_LIST);
5076         }
5077 
setNetworkValidationState(boolean isValid)5078         private void setNetworkValidationState(boolean isValid) {
5079             // Validation status is true and was not data stall.
5080             if (isValid && !mWasDataStall) {
5081                 return;
5082             }
5083 
5084             if (!mWasDataStall) {
5085                 mWasDataStall = true;
5086                 mDataStallStartMs = SystemClock.elapsedRealtime();
5087                 if (DBG) log("data stall: start time = " + mDataStallStartMs);
5088                 return;
5089             }
5090 
5091             if (!mLastActionReported) {
5092                 int timeDuration = (int) (SystemClock.elapsedRealtime() - mDataStallStartMs);
5093                 if (DBG) {
5094                     log("data stall: lastaction = " + mLastAction + ", isRecovered = "
5095                             + isValid + ", mTimeDuration = " + timeDuration);
5096                 }
5097                 DataStallRecoveryStats.onDataStallEvent(mLastAction, mPhone, isValid,
5098                                                         timeDuration);
5099                 mLastActionReported = true;
5100             }
5101 
5102             if (isValid) {
5103                 mLastActionReported = false;
5104                 mWasDataStall = false;
5105             }
5106         }
5107 
isAggressiveRecovery()5108         public boolean isAggressiveRecovery() {
5109             @RecoveryAction int action = getRecoveryAction();
5110 
5111             return ((action == RECOVERY_ACTION_CLEANUP)
5112                     || (action == RECOVERY_ACTION_REREGISTER)
5113                     || (action == RECOVERY_ACTION_RADIO_RESTART));
5114         }
5115 
getMinDurationBetweenRecovery()5116         private long getMinDurationBetweenRecovery() {
5117             return Settings.Global.getLong(mResolver,
5118                 Settings.Global.MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS,
5119                 DEFAULT_MIN_DURATION_BETWEEN_RECOVERY_STEPS_IN_MS);
5120         }
5121 
getElapsedTimeSinceRecoveryMs()5122         private long getElapsedTimeSinceRecoveryMs() {
5123             return (SystemClock.elapsedRealtime() - mTimeLastRecoveryStartMs);
5124         }
5125 
5126         @RecoveryAction
getRecoveryAction()5127         private int getRecoveryAction() {
5128             @RecoveryAction int action = Settings.System.getInt(mResolver,
5129                     "radio.data.stall.recovery.action", RECOVERY_ACTION_GET_DATA_CALL_LIST);
5130             if (VDBG_STALL) log("getRecoveryAction: " + action);
5131             return action;
5132         }
5133 
putRecoveryAction(@ecoveryAction int action)5134         private void putRecoveryAction(@RecoveryAction int action) {
5135             Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action);
5136             if (VDBG_STALL) log("putRecoveryAction: " + action);
5137         }
5138 
broadcastDataStallDetected(@ecoveryAction int recoveryAction)5139         private void broadcastDataStallDetected(@RecoveryAction int recoveryAction) {
5140             Intent intent = new Intent(TelephonyManager.ACTION_DATA_STALL_DETECTED);
5141             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
5142             intent.putExtra(TelephonyManager.EXTRA_RECOVERY_ACTION, recoveryAction);
5143             mPhone.getContext().sendBroadcast(intent, READ_PRIVILEGED_PHONE_STATE);
5144         }
5145 
isRecoveryAlreadyStarted()5146         private boolean isRecoveryAlreadyStarted() {
5147             return getRecoveryAction() != RECOVERY_ACTION_GET_DATA_CALL_LIST;
5148         }
5149 
checkRecovery()5150         private boolean checkRecovery() {
5151             // To avoid back to back recovery wait for a grace period
5152             if (getElapsedTimeSinceRecoveryMs() < getMinDurationBetweenRecovery()) {
5153                 if (VDBG_STALL) log("skip back to back data stall recovery");
5154                 return false;
5155             }
5156 
5157             // Skip recovery if it can cause a call to drop
5158             if (mPhone.getState() != PhoneConstants.State.IDLE
5159                     && getRecoveryAction() > RECOVERY_ACTION_CLEANUP) {
5160                 if (VDBG_STALL) log("skip data stall recovery as there is an active call");
5161                 return false;
5162             }
5163 
5164             // Allow recovery if data is expected to work
5165             return mAttached.get() && isDataAllowed(null);
5166         }
5167 
triggerRecovery()5168         private void triggerRecovery() {
5169             // Updating the recovery start time early to avoid race when
5170             // the message is being processed in the Queue
5171             mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime();
5172             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
5173         }
5174 
doRecovery()5175         public void doRecovery() {
5176             if (isAnyDataConnected()) {
5177                 // Go through a series of recovery steps, each action transitions to the next action
5178                 @RecoveryAction final int recoveryAction = getRecoveryAction();
5179                 final int signalStrength = mPhone.getSignalStrength().getLevel();
5180                 TelephonyMetrics.getInstance().writeSignalStrengthEvent(
5181                         mPhone.getPhoneId(), signalStrength);
5182                 TelephonyMetrics.getInstance().writeDataStallEvent(
5183                         mPhone.getPhoneId(), recoveryAction);
5184                 mLastAction = recoveryAction;
5185                 mLastActionReported = false;
5186                 broadcastDataStallDetected(recoveryAction);
5187 
5188                 switch (recoveryAction) {
5189                     case RECOVERY_ACTION_GET_DATA_CALL_LIST:
5190                         EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
5191                             mSentSinceLastRecv);
5192                         if (DBG) log("doRecovery() get data call list");
5193                         mDataServiceManager.requestDataCallList(obtainMessage());
5194                         putRecoveryAction(RECOVERY_ACTION_CLEANUP);
5195                         break;
5196                     case RECOVERY_ACTION_CLEANUP:
5197                         EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP,
5198                             mSentSinceLastRecv);
5199                         if (DBG) log("doRecovery() cleanup all connections");
5200                         cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString(
5201                                 ApnSetting.TYPE_DEFAULT)));
5202                         cleanUpConnection(mApnContexts.get(ApnSetting.getApnTypeString(
5203                                 ApnSetting.TYPE_ENTERPRISE)));
5204                         putRecoveryAction(RECOVERY_ACTION_REREGISTER);
5205                         break;
5206                     case RECOVERY_ACTION_REREGISTER:
5207                         EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
5208                             mSentSinceLastRecv);
5209                         if (DBG) log("doRecovery() re-register");
5210                         mPhone.getServiceStateTracker().reRegisterNetwork(null);
5211                         putRecoveryAction(RECOVERY_ACTION_RADIO_RESTART);
5212                         break;
5213                     case RECOVERY_ACTION_RADIO_RESTART:
5214                         EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
5215                             mSentSinceLastRecv);
5216                         if (DBG) log("restarting radio");
5217                         restartRadio();
5218                         reset();
5219                         break;
5220                     default:
5221                         throw new RuntimeException("doRecovery: Invalid recoveryAction="
5222                             + recoveryAction);
5223                 }
5224                 mSentSinceLastRecv = 0;
5225             }
5226         }
5227 
processNetworkStatusChanged(boolean isValid)5228         public void processNetworkStatusChanged(boolean isValid) {
5229             setNetworkValidationState(isValid);
5230             if (isValid) {
5231                 mIsValidNetwork = true;
5232                 reset();
5233             } else {
5234                 if (mIsValidNetwork || isRecoveryAlreadyStarted()) {
5235                     mIsValidNetwork = false;
5236                     // Check and trigger a recovery if network switched from good
5237                     // to bad or recovery is already started before.
5238                     if (checkRecovery()) {
5239                         if (DBG) log("trigger data stall recovery");
5240                         triggerRecovery();
5241                     }
5242                 }
5243             }
5244         }
5245 
isRecoveryOnBadNetworkEnabled()5246         public boolean isRecoveryOnBadNetworkEnabled() {
5247             return Settings.Global.getInt(mResolver,
5248                     Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK, 1) == 1;
5249         }
5250 
isNoRxDataStallDetectionEnabled()5251         public boolean isNoRxDataStallDetectionEnabled() {
5252             return mDataStallNoRxEnabled && !isRecoveryOnBadNetworkEnabled();
5253         }
5254     }
5255 
updateDataStallInfo()5256     private void updateDataStallInfo() {
5257         long sent, received;
5258 
5259         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
5260         mDataStallTxRxSum.updateTotalTxRxSum();
5261 
5262         if (VDBG_STALL) {
5263             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
5264                     " preTxRxSum=" + preTxRxSum);
5265         }
5266 
5267         sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts;
5268         received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts;
5269 
5270         if (RADIO_TESTS) {
5271             if (SystemProperties.getBoolean("radio.test.data.stall", false)) {
5272                 log("updateDataStallInfo: radio.test.data.stall true received = 0;");
5273                 received = 0;
5274             }
5275         }
5276         if ( sent > 0 && received > 0 ) {
5277             if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
5278             mSentSinceLastRecv = 0;
5279             mDsRecoveryHandler.reset();
5280         } else if (sent > 0 && received == 0) {
5281             if (isPhoneStateIdle()) {
5282                 mSentSinceLastRecv += sent;
5283             } else {
5284                 mSentSinceLastRecv = 0;
5285             }
5286             if (DBG) {
5287                 log("updateDataStallInfo: OUT sent=" + sent +
5288                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
5289             }
5290         } else if (sent == 0 && received > 0) {
5291             if (VDBG_STALL) log("updateDataStallInfo: IN");
5292             mSentSinceLastRecv = 0;
5293             mDsRecoveryHandler.reset();
5294         } else {
5295             if (VDBG_STALL) log("updateDataStallInfo: NONE");
5296         }
5297     }
5298 
isPhoneStateIdle()5299     private boolean isPhoneStateIdle() {
5300         for (int i = 0; i < mTelephonyManager.getPhoneCount(); i++) {
5301             Phone phone = PhoneFactory.getPhone(i);
5302             if (phone != null && phone.getState() != PhoneConstants.State.IDLE) {
5303                 log("isPhoneStateIdle false: Voice call active on phone " + i);
5304                 return false;
5305             }
5306         }
5307         return true;
5308     }
5309 
onDataStallAlarm(int tag)5310     private void onDataStallAlarm(int tag) {
5311         if (mDataStallAlarmTag != tag) {
5312             if (DBG) {
5313                 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag);
5314             }
5315             return;
5316         }
5317 
5318         if (DBG) log("Data stall alarm");
5319         updateDataStallInfo();
5320 
5321         int hangWatchdogTrigger = Settings.Global.getInt(mResolver,
5322                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
5323                 NUMBER_SENT_PACKETS_OF_HANG);
5324 
5325         boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
5326         if (mSentSinceLastRecv >= hangWatchdogTrigger) {
5327             if (DBG) {
5328                 log("onDataStallAlarm: tag=" + tag + " do recovery action="
5329                         + mDsRecoveryHandler.getRecoveryAction());
5330             }
5331             suspectedStall = DATA_STALL_SUSPECTED;
5332             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
5333         } else {
5334             if (VDBG_STALL) {
5335                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
5336                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
5337             }
5338         }
5339         startDataStallAlarm(suspectedStall);
5340     }
5341 
startDataStallAlarm(boolean suspectedStall)5342     protected void startDataStallAlarm(boolean suspectedStall) {
5343         int delayInMs;
5344 
5345         if (mDsRecoveryHandler.isNoRxDataStallDetectionEnabled() && isAnyDataConnected()) {
5346             // If screen is on or data stall is currently suspected, set the alarm
5347             // with an aggressive timeout.
5348             if (mIsScreenOn || suspectedStall || mDsRecoveryHandler.isAggressiveRecovery()) {
5349                 delayInMs = Settings.Global.getInt(mResolver,
5350                         Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
5351                         DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
5352             } else {
5353                 delayInMs = Settings.Global.getInt(mResolver,
5354                         Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
5355                         DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
5356             }
5357 
5358             mDataStallAlarmTag += 1;
5359             if (VDBG_STALL) {
5360                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
5361                         " delay=" + (delayInMs / 1000) + "s");
5362             }
5363             Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
5364             intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TAG, mDataStallAlarmTag);
5365             intent.putExtra(INTENT_DATA_STALL_ALARM_EXTRA_TRANSPORT_TYPE, mTransportType);
5366             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId());
5367             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
5368                     PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
5369             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME,
5370                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
5371         } else {
5372             if (VDBG_STALL) {
5373                 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
5374             }
5375         }
5376     }
5377 
stopDataStallAlarm()5378     private void stopDataStallAlarm() {
5379         if (VDBG_STALL) {
5380             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
5381                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
5382         }
5383         mDataStallAlarmTag += 1;
5384         if (mDataStallAlarmIntent != null) {
5385             mAlarmManager.cancel(mDataStallAlarmIntent);
5386             mDataStallAlarmIntent = null;
5387         }
5388     }
5389 
restartDataStallAlarm()5390     private void restartDataStallAlarm() {
5391         if (!isAnyDataConnected()) return;
5392         // To be called on screen status change.
5393         // Do not cancel the alarm if it is set with aggressive timeout.
5394         if (mDsRecoveryHandler.isAggressiveRecovery()) {
5395             if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
5396             return;
5397         }
5398         if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
5399         stopDataStallAlarm();
5400         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
5401     }
5402 
5403     /**
5404      * Provisioning APN
5405      */
onActionIntentProvisioningApnAlarm(Intent intent)5406     private void onActionIntentProvisioningApnAlarm(Intent intent) {
5407         if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction());
5408         Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM,
5409                 intent.getAction());
5410         msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0);
5411         sendMessage(msg);
5412     }
5413 
startProvisioningApnAlarm()5414     private void startProvisioningApnAlarm() {
5415         int delayInMs = Settings.Global.getInt(mResolver,
5416                                 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
5417                                 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT);
5418         if (TelephonyUtils.IS_DEBUGGABLE) {
5419             // Allow debug code to use a system property to provide another value
5420             String delayInMsStrg = Integer.toString(delayInMs);
5421             delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg);
5422             try {
5423                 delayInMs = Integer.parseInt(delayInMsStrg);
5424             } catch (NumberFormatException e) {
5425                 loge("startProvisioningApnAlarm: e=" + e);
5426             }
5427         }
5428         mProvisioningApnAlarmTag += 1;
5429         if (DBG) {
5430             log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag +
5431                     " delay=" + (delayInMs / 1000) + "s");
5432         }
5433         Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM);
5434         intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag);
5435         mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
5436                 PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
5437         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
5438                 SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent);
5439     }
5440 
stopProvisioningApnAlarm()5441     private void stopProvisioningApnAlarm() {
5442         if (DBG) {
5443             log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag +
5444                     " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent);
5445         }
5446         mProvisioningApnAlarmTag += 1;
5447         if (mProvisioningApnAlarmIntent != null) {
5448             mAlarmManager.cancel(mProvisioningApnAlarmIntent);
5449             mProvisioningApnAlarmIntent = null;
5450         }
5451     }
5452 
5453     /**
5454      * 5G connection reevaluation alarm
5455      */
startWatchdogAlarm()5456     private void startWatchdogAlarm() {
5457         sendMessageDelayed(obtainMessage(DctConstants.EVENT_NR_TIMER_WATCHDOG), mWatchdogTimeMs);
5458         mWatchdog = true;
5459     }
5460 
stopWatchdogAlarm()5461     private void stopWatchdogAlarm() {
5462         removeMessages(DctConstants.EVENT_NR_TIMER_WATCHDOG);
5463         mWatchdog = false;
5464     }
5465 
onDataServiceBindingChanged(boolean bound)5466     private void onDataServiceBindingChanged(boolean bound) {
5467         if (!bound) {
5468             if (mTransportType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN) {
5469                 boolean connPersistenceOnRestart = mPhone.getContext().getResources()
5470                    .getBoolean(com.android
5471                        .internal.R.bool.config_wlan_data_service_conn_persistence_on_restart);
5472                 if (!connPersistenceOnRestart) {
5473                     cleanUpAllConnectionsInternal(false, Phone.REASON_IWLAN_DATA_SERVICE_DIED);
5474                 }
5475             }
5476         } else {
5477             //reset throttling after binding to data service
5478             mDataThrottler.reset();
5479         }
5480         mDataServiceBound = bound;
5481     }
5482 
requestTypeToString(@equestNetworkType int type)5483     public static String requestTypeToString(@RequestNetworkType int type) {
5484         switch (type) {
5485             case REQUEST_TYPE_NORMAL: return "NORMAL";
5486             case REQUEST_TYPE_HANDOVER: return "HANDOVER";
5487         }
5488         return "UNKNOWN";
5489     }
5490 
releaseTypeToString(@eleaseNetworkType int type)5491     public static String releaseTypeToString(@ReleaseNetworkType int type) {
5492         switch (type) {
5493             case RELEASE_TYPE_NORMAL: return "NORMAL";
5494             case RELEASE_TYPE_DETACH: return "DETACH";
5495             case RELEASE_TYPE_HANDOVER: return "HANDOVER";
5496         }
5497         return "UNKNOWN";
5498     }
5499 
5500     @RilRadioTechnology
getDataRat()5501     protected int getDataRat() {
5502         ServiceState ss = mPhone.getServiceState();
5503         NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo(
5504                 NetworkRegistrationInfo.DOMAIN_PS, mTransportType);
5505         if (nrs != null) {
5506             return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology());
5507         }
5508         return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
5509     }
5510 
5511     @RilRadioTechnology
getVoiceRat()5512     private int getVoiceRat() {
5513         ServiceState ss = mPhone.getServiceState();
5514         NetworkRegistrationInfo nrs = ss.getNetworkRegistrationInfo(
5515                 NetworkRegistrationInfo.DOMAIN_CS, mTransportType);
5516         if (nrs != null) {
5517             return ServiceState.networkTypeToRilRadioTechnology(nrs.getAccessNetworkTechnology());
5518         }
5519         return ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN;
5520     }
5521 
read5GConfiguration()5522     private void read5GConfiguration() {
5523         if (DBG) log("read5GConfiguration");
5524         String[] bandwidths = CarrierConfigManager.getDefaultConfig().getStringArray(
5525                 CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY);
5526         boolean useLte = false;
5527         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
5528                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
5529         if (configManager != null) {
5530             PersistableBundle b = configManager.getConfigForSubId(mPhone.getSubId());
5531             if (b != null) {
5532                 if (b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY) != null) {
5533                     bandwidths = b.getStringArray(CarrierConfigManager.KEY_BANDWIDTH_STRING_ARRAY);
5534                 }
5535                 useLte = b.getBoolean(CarrierConfigManager
5536                         .KEY_BANDWIDTH_NR_NSA_USE_LTE_VALUE_FOR_UPLINK_BOOL);
5537                 mWatchdogTimeMs = b.getLong(CarrierConfigManager.KEY_5G_WATCHDOG_TIME_MS_LONG);
5538                 mNrNsaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_NSA_BOOL);
5539                 mNrNsaMmwaveUnmetered = b.getBoolean(
5540                         CarrierConfigManager.KEY_UNMETERED_NR_NSA_MMWAVE_BOOL);
5541                 mNrNsaSub6Unmetered = b.getBoolean(
5542                         CarrierConfigManager.KEY_UNMETERED_NR_NSA_SUB6_BOOL);
5543                 mNrSaAllUnmetered = b.getBoolean(CarrierConfigManager.KEY_UNMETERED_NR_SA_BOOL);
5544                 mNrSaMmwaveUnmetered = b.getBoolean(
5545                         CarrierConfigManager.KEY_UNMETERED_NR_SA_MMWAVE_BOOL);
5546                 mNrSaSub6Unmetered = b.getBoolean(
5547                         CarrierConfigManager.KEY_UNMETERED_NR_SA_SUB6_BOOL);
5548                 mNrNsaRoamingUnmetered = b.getBoolean(
5549                         CarrierConfigManager.KEY_UNMETERED_NR_NSA_WHEN_ROAMING_BOOL);
5550                 mLteEndcUsingUserDataForRrcDetection = b.getBoolean(
5551                         CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL);
5552             }
5553         }
5554         updateLinkBandwidths(bandwidths, useLte);
5555     }
5556 
getLteEndcUsingUserDataForIdleDetection()5557     public boolean getLteEndcUsingUserDataForIdleDetection() {
5558         return mLteEndcUsingUserDataForRrcDetection;
5559     }
5560 
5561     /**
5562      * Register for physical link status (i.e. RRC state) changed event.
5563      * if {@link CarrierConfigManager.KEY_LTE_ENDC_USING_USER_DATA_FOR_RRC_DETECTION_BOOL} is true,
5564      * then physical link state is focusing on "internet data connection" instead of RRC state.
5565      *
5566      * @param h The handler
5567      * @param what The event
5568      */
registerForPhysicalLinkStatusChanged(Handler h, int what)5569     public void registerForPhysicalLinkStatusChanged(Handler h, int what) {
5570         mDcc.registerForPhysicalLinkStatusChanged(h, what);
5571     }
5572 
5573     /**
5574      * Unregister from physical link status (i.e. RRC state) changed event.
5575      *
5576      * @param h The previously registered handler
5577      */
unregisterForPhysicalLinkStatusChanged(Handler h)5578     public void unregisterForPhysicalLinkStatusChanged(Handler h) {
5579         mDcc.unregisterForPhysicalLinkStatusChanged(h);
5580     }
5581 
5582     // We use a specialized equals function in Apn setting when checking if an active
5583     // data connection is still legitimate to use against a different apn setting.
5584     // This method is extracted to a function to ensure that any future changes to this check will
5585     // be applied to both cleanUpConnectionsOnUpdatedApns and checkForCompatibleDataConnection.
5586     // Fix for b/158908392.
areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2)5587     private boolean areCompatible(ApnSetting apnSetting1, ApnSetting apnSetting2) {
5588         return apnSetting1.equals(apnSetting2,
5589                 mPhone.getServiceState().getDataRoamingFromRegistration());
5590     }
5591 
5592     @NonNull
getCarrierConfig()5593     private PersistableBundle getCarrierConfig() {
5594         CarrierConfigManager configManager = (CarrierConfigManager) mPhone.getContext()
5595                 .getSystemService(Context.CARRIER_CONFIG_SERVICE);
5596         if (configManager != null) {
5597             // If an invalid subId is used, this bundle will contain default values.
5598             PersistableBundle config = configManager.getConfigForSubId(mPhone.getSubId());
5599             if (config != null) {
5600                 return config;
5601             }
5602         }
5603         // Return static default defined in CarrierConfigManager.
5604         return CarrierConfigManager.getDefaultConfig();
5605     }
5606 
5607     /**
5608      * @return The data service manager.
5609      */
getDataServiceManager()5610     public @NonNull DataServiceManager getDataServiceManager() {
5611         return mDataServiceManager;
5612     }
5613 
5614     /**
5615      * @return The data throttler
5616      */
getDataThrottler()5617     public @NonNull DataThrottler getDataThrottler() {
5618         return mDataThrottler;
5619     }
5620 
showProvisioningNotification()5621     private void showProvisioningNotification() {
5622         final Intent intent = new Intent(DcTracker.INTENT_PROVISION);
5623         intent.putExtra(DcTracker.EXTRA_PROVISION_PHONE_ID, mPhone.getPhoneId());
5624         final PendingIntent pendingIntent = PendingIntent.getBroadcast(
5625                 mPhone.getContext(), 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
5626 
5627         final Resources r = mPhone.getContext().getResources();
5628         final String title = r.getString(R.string.network_available_sign_in, 0);
5629         final String details = mTelephonyManager.getNetworkOperator(mPhone.getSubId());
5630         final Notification.Builder builder = new Notification.Builder(mPhone.getContext())
5631                 .setWhen(System.currentTimeMillis())
5632                 .setSmallIcon(R.drawable.stat_notify_rssi_in_range)
5633                 .setChannelId(NotificationChannelController.CHANNEL_ID_MOBILE_DATA_STATUS)
5634                 .setAutoCancel(true)
5635                 .setTicker(title)
5636                 .setColor(mPhone.getContext().getColor(
5637                         com.android.internal.R.color.system_notification_accent_color))
5638                 .setContentTitle(title)
5639                 .setContentText(details)
5640                 .setContentIntent(pendingIntent)
5641                 .setLocalOnly(true)
5642                 .setOnlyAlertOnce(true);
5643 
5644         final Notification notification = builder.build();
5645         try {
5646             getNotificationManager().notify(NOTIFICATION_TAG, mPhone.getPhoneId(), notification);
5647         } catch (final NullPointerException npe) {
5648             Log.e(mLogTag, "showProvisioningNotification: error showing notification", npe);
5649         }
5650     }
5651 
hideProvisioningNotification()5652     private void hideProvisioningNotification() {
5653         try {
5654             getNotificationManager().cancel(NOTIFICATION_TAG, mPhone.getPhoneId());
5655         } catch (final NullPointerException npe) {
5656             Log.e(mLogTag, "hideProvisioningNotification: error hiding notification", npe);
5657         }
5658     }
5659 
getNotificationManager()5660     private NotificationManager getNotificationManager() {
5661         return (NotificationManager) mPhone.getContext()
5662                 .createContextAsUser(UserHandle.ALL, 0 /* flags */)
5663                 .getSystemService(Context.NOTIFICATION_SERVICE);
5664     }
5665 }
5666