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