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