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