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