Change to consider SIGNAL_LOST as permanenet failure only if not attached.
[android/platform/frameworks/opt/telephony.git] / src / java / com / android / internal / telephony / dataconnection / DcTrackerBase.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.content.BroadcastReceiver;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.res.Resources;
27 import android.content.SharedPreferences;
28 import android.database.ContentObserver;
29 import android.net.ConnectivityManager;
30 import android.net.LinkProperties;
31 import android.net.NetworkCapabilities;
32 import android.net.NetworkInfo;
33 import android.net.TrafficStats;
34 import android.net.wifi.WifiManager;
35 import android.os.AsyncResult;
36 import android.os.Build;
37 import android.os.Bundle;
38 import android.os.Handler;
39 import android.os.HandlerThread;
40 import android.os.Message;
41 import android.os.Messenger;
42 import android.os.SystemClock;
43 import android.os.SystemProperties;
44 import android.preference.PreferenceManager;
45 import android.provider.Settings;
46 import android.provider.Settings.SettingNotFoundException;
47 import android.telephony.SubscriptionManager;
48 import android.telephony.TelephonyManager;
49 import android.text.TextUtils;
50 import android.util.EventLog;
51 import android.telephony.Rlog;
52 import android.telephony.ServiceState;
53
54 import com.android.internal.R;
55 import com.android.internal.telephony.DctConstants;
56 import com.android.internal.telephony.DctConstants.State;
57 import com.android.internal.telephony.EventLogTags;
58 import com.android.internal.telephony.Phone;
59 import com.android.internal.telephony.PhoneBase;
60 import com.android.internal.telephony.PhoneConstants;
61 import com.android.internal.telephony.uicc.IccRecords;
62 import com.android.internal.telephony.uicc.UiccController;
63 import com.android.internal.util.AsyncChannel;
64 import com.android.internal.util.ArrayUtils;
65
66 import java.io.FileDescriptor;
67 import java.io.PrintWriter;
68 import java.util.ArrayList;
69 import java.util.Comparator;
70 import java.util.HashMap;
71 import java.util.List;
72 import java.util.Map.Entry;
73 import java.util.Set;
74 import java.util.concurrent.ConcurrentHashMap;
75 import java.util.concurrent.atomic.AtomicInteger;
76 import java.util.concurrent.atomic.AtomicReference;
77 import java.util.PriorityQueue;
78
79 /**
80  * {@hide}
81  */
82 public abstract class DcTrackerBase extends Handler {
83     protected static final boolean DBG = true;
84     protected static final boolean VDBG = false; // STOPSHIP if true
85     protected static final boolean VDBG_STALL = true; // STOPSHIP if true
86     protected static final boolean RADIO_TESTS = false;
87
88     static boolean mIsCleanupRequired = false;
89     /**
90      * Constants for the data connection activity:
91      * physical link down/up
92      */
93     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0;
94     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1;
95     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
96
97     /** Delay between APN attempts.
98         Note the property override mechanism is there just for testing purpose only. */
99     protected static final int APN_DELAY_DEFAULT_MILLIS = 20000;
100
101     /** Delay between APN attempts when in fail fast mode */
102     protected static final int APN_FAIL_FAST_DELAY_DEFAULT_MILLIS = 3000;
103
104     AlarmManager mAlarmManager;
105
106     protected Object mDataEnabledLock = new Object();
107
108     // responds to the setInternalDataEnabled call - used internally to turn off data
109     // for example during emergency calls
110     protected boolean mInternalDataEnabled = true;
111
112     // responds to public (user) API to enable/disable data use
113     // independent of mInternalDataEnabled and requests for APN access
114     // persisted
115     protected boolean mUserDataEnabled = true;
116
117     // TODO: move away from static state once 5587429 is fixed.
118     protected static boolean sPolicyDataEnabled = true;
119
120     private boolean[] mDataEnabled = new boolean[DctConstants.APN_NUM_TYPES];
121
122     private int mEnabledCount = 0;
123
124     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
125     protected String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
126
127     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
128     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
129         + "5000,10000,20000,40000,80000:5000,160000:5000,"
130         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
131
132     /** Retry configuration for secondary networks: 4 tries in 20 sec */
133     protected static final String SECONDARY_DATA_RETRY_CONFIG =
134             "max_retries=3, 5000, 5000, 5000";
135
136     /** Slow poll when attempting connection recovery. */
137     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
138     /** Default max failure count before attempting to network re-registration. */
139     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
140
141     /**
142      * After detecting a potential connection problem, this is the max number
143      * of subsequent polls before attempting recovery.
144      */
145     protected static final int NO_RECV_POLL_LIMIT = 24;
146     // 1 sec. default polling interval when screen is on.
147     protected static final int POLL_NETSTAT_MILLIS = 1000;
148     // 10 min. default polling interval when screen is off.
149     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
150     // 2 min for round trip time
151     protected static final int POLL_LONGEST_RTT = 120 * 1000;
152     // Default sent packets without ack which triggers initial recovery steps
153     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
154     // how long to wait before switching back to default APN
155     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
156     // system property that can override the above value
157     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
158     // represents an invalid IP address
159     protected static final String NULL_IP = "0.0.0.0";
160
161     // Default for the data stall alarm while non-aggressive stall detection
162     protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
163     // Default for the data stall alarm for aggressive stall detection
164     protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
165     // If attempt is less than this value we're doing first level recovery
166     protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1;
167     // Tag for tracking stale alarms
168     protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag";
169
170     protected static final boolean DATA_STALL_SUSPECTED = true;
171     protected static final boolean DATA_STALL_NOT_SUSPECTED = false;
172
173     protected String RADIO_RESET_PROPERTY = "gsm.radioreset";
174
175     protected static final String INTENT_RECONNECT_ALARM =
176             "com.android.internal.telephony.data-reconnect";
177     protected static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
178     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
179             "reconnect_alarm_extra_reason";
180
181     protected static final String INTENT_RESTART_TRYSETUP_ALARM =
182             "com.android.internal.telephony.data-restart-trysetup";
183     protected static final String INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE =
184             "restart_trysetup_alarm_extra_type";
185
186     protected static final String INTENT_DATA_STALL_ALARM =
187             "com.android.internal.telephony.data-stall";
188
189
190
191     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
192
193     protected DcTesterFailBringUpAll mDcTesterFailBringUpAll;
194     protected DcController mDcc;
195
196     // member variables
197     protected PhoneBase mPhone;
198     protected UiccController mUiccController;
199     protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
200     protected DctConstants.Activity mActivity = DctConstants.Activity.NONE;
201     protected DctConstants.State mState = DctConstants.State.IDLE;
202     protected Handler mDataConnectionTracker = null;
203
204     protected long mTxPkts;
205     protected long mRxPkts;
206     protected int mNetStatPollPeriod;
207     protected boolean mNetStatPollEnabled = false;
208
209     protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
210     // Used to track stale data stall alarms.
211     protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
212     // The current data stall alarm intent
213     protected PendingIntent mDataStallAlarmIntent = null;
214     // Number of packets sent since the last received packet
215     protected long mSentSinceLastRecv;
216     // Controls when a simple recovery attempt it to be tried
217     protected int mNoRecvPollCount = 0;
218     // Refrence counter for enabling fail fast
219     protected static int sEnableFailFastRefCounter = 0;
220     // True if data stall detection is enabled
221     protected volatile boolean mDataStallDetectionEnabled = true;
222
223     protected volatile boolean mFailFast = false;
224
225     // True when in voice call
226     protected boolean mInVoiceCall = false;
227
228     // wifi connection status will be updated by sticky intent
229     protected boolean mIsWifiConnected = false;
230
231     /** Intent sent when the reconnect alarm fires. */
232     protected PendingIntent mReconnectIntent = null;
233
234     /** CID of active data connection */
235     protected int mCidActive;
236
237     // When false we will not auto attach and manually attaching is required.
238     protected boolean mAutoAttachOnCreationConfig = false;
239     protected boolean mAutoAttachOnCreation = false;
240
241     // State of screen
242     // (TODO: Reconsider tying directly to screen, maybe this is
243     //        really a lower power mode")
244     protected boolean mIsScreenOn = true;
245
246     /** Allows the generation of unique Id's for DataConnection objects */
247     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
248
249     /** The data connections. */
250     protected HashMap<Integer, DataConnection> mDataConnections =
251         new HashMap<Integer, DataConnection>();
252
253     /** The data connection async channels */
254     protected HashMap<Integer, DcAsyncChannel> mDataConnectionAcHashMap =
255         new HashMap<Integer, DcAsyncChannel>();
256
257     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
258     protected HashMap<String, Integer> mApnToDataConnectionId =
259                                     new HashMap<String, Integer>();
260
261     /** Phone.APN_TYPE_* ===> ApnContext */
262     protected final ConcurrentHashMap<String, ApnContext> mApnContexts =
263                                     new ConcurrentHashMap<String, ApnContext>();
264
265     /** kept in sync with mApnContexts
266      * Higher numbers are higher priority and sorted so highest priority is first */
267     protected final PriorityQueue<ApnContext>mPrioritySortedApnContexts =
268             new PriorityQueue<ApnContext>(5,
269             new Comparator<ApnContext>() {
270                 public int compare(ApnContext c1, ApnContext c2) {
271                     return c2.priority - c1.priority;
272                 }
273             } );
274
275     /* Currently active APN */
276     protected ApnSetting mActiveApn;
277
278     /** allApns holds all apns */
279     protected ArrayList<ApnSetting> mAllApnSettings = null;
280
281     /** preferred apn */
282     protected ApnSetting mPreferredApn = null;
283
284     /** Is packet service restricted by network */
285     protected boolean mIsPsRestricted = false;
286
287     /** emergency apn Setting*/
288     protected ApnSetting mEmergencyApn = null;
289
290     /* Once disposed dont handle any messages */
291     protected boolean mIsDisposed = false;
292
293     protected ContentResolver mResolver;
294
295     /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */
296     protected boolean mIsProvisioning = false;
297
298     /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */
299     protected String mProvisioningUrl = null;
300
301     /* Intent for the provisioning apn alarm */
302     protected static final String INTENT_PROVISIONING_APN_ALARM =
303             "com.android.internal.telephony.provisioning_apn_alarm";
304
305     /* Tag for tracking stale alarms */
306     protected static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag";
307
308     /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */
309     protected static final String DEBUG_PROV_APN_ALARM =
310             "persist.debug.prov_apn_alarm";
311
312     /* Default for the provisioning apn alarm timeout */
313     protected static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15;
314
315     /* The provision apn alarm intent used to disable the provisioning apn */
316     protected PendingIntent mProvisioningApnAlarmIntent = null;
317
318     /* Used to track stale provisioning apn alarms */
319     protected int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime();
320
321     protected AsyncChannel mReplyAc = new AsyncChannel();
322
323     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
324     {
325         @Override
326         public void onReceive(Context context, Intent intent)
327         {
328             String action = intent.getAction();
329             if (DBG) log("onReceive: action=" + action);
330             if (action.equals(Intent.ACTION_SCREEN_ON)) {
331                 mIsScreenOn = true;
332                 stopNetStatPoll();
333                 startNetStatPoll();
334                 restartDataStallAlarm();
335             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
336                 mIsScreenOn = false;
337                 stopNetStatPoll();
338                 startNetStatPoll();
339                 restartDataStallAlarm();
340             } else if (action.startsWith(INTENT_RECONNECT_ALARM)) {
341                 if (DBG) log("Reconnect alarm. Previous state was " + mState);
342                 onActionIntentReconnectAlarm(intent);
343             } else if (action.startsWith(INTENT_RESTART_TRYSETUP_ALARM)) {
344                 if (DBG) log("Restart trySetup alarm");
345                 onActionIntentRestartTrySetupAlarm(intent);
346             } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
347                 onActionIntentDataStallAlarm(intent);
348             } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) {
349                 onActionIntentProvisioningApnAlarm(intent);
350             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
351                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
352                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
353                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
354                 if (DBG) log("NETWORK_STATE_CHANGED_ACTION: mIsWifiConnected=" + mIsWifiConnected);
355             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
356                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
357                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
358
359                 if (!enabled) {
360                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
361                     // quit and won't report disconnected until next enabling.
362                     mIsWifiConnected = false;
363                 }
364                 if (DBG) log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled
365                         + " mIsWifiConnected=" + mIsWifiConnected);
366             }
367         }
368     };
369
370     private Runnable mPollNetStat = new Runnable()
371     {
372         @Override
373         public void run() {
374             updateDataActivity();
375
376             if (mIsScreenOn) {
377                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
378                         Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
379             } else {
380                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
381                         Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
382                         POLL_NETSTAT_SCREEN_OFF_MILLIS);
383             }
384
385             if (mNetStatPollEnabled) {
386                 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
387             }
388         }
389     };
390
391     private class DataRoamingSettingObserver extends ContentObserver {
392
393         public DataRoamingSettingObserver(Handler handler, Context context) {
394             super(handler);
395             mResolver = context.getContentResolver();
396         }
397
398         public void register() {
399             mResolver.registerContentObserver(
400                     Settings.Global.getUriFor(Settings.Global.DATA_ROAMING), false, this);
401         }
402
403         public void unregister() {
404             mResolver.unregisterContentObserver(this);
405         }
406
407         @Override
408         public void onChange(boolean selfChange) {
409             // already running on mPhone handler thread
410             if (mPhone.getServiceState().getRoaming()) {
411                 sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON));
412             }
413         }
414     }
415     private final DataRoamingSettingObserver mDataRoamingSettingObserver;
416
417     /**
418      * The Initial MaxRetry sent to a DataConnection as a parameter
419      * to DataConnectionAc.bringUp. This value can be defined at compile
420      * time using the SystemProperty Settings.Global.DCT_INITIAL_MAX_RETRY
421      * and at runtime using gservices to change Settings.Global.DCT_INITIAL_MAX_RETRY.
422      */
423     private static final int DEFAULT_MDC_INITIAL_RETRY = 1;
424     protected int getInitialMaxRetry() {
425         if (mFailFast) {
426             return 0;
427         }
428         // Get default value from system property or use DEFAULT_MDC_INITIAL_RETRY
429         int value = SystemProperties.getInt(
430                 Settings.Global.MDC_INITIAL_MAX_RETRY, DEFAULT_MDC_INITIAL_RETRY);
431
432         // Check if its been overridden
433         return Settings.Global.getInt(mResolver,
434                 Settings.Global.MDC_INITIAL_MAX_RETRY, value);
435     }
436
437     /**
438      * Maintain the sum of transmit and receive packets.
439      *
440      * The packet counts are initialized and reset to -1 and
441      * remain -1 until they can be updated.
442      */
443     public class TxRxSum {
444         public long txPkts;
445         public long rxPkts;
446
447         public TxRxSum() {
448             reset();
449         }
450
451         public TxRxSum(long txPkts, long rxPkts) {
452             this.txPkts = txPkts;
453             this.rxPkts = rxPkts;
454         }
455
456         public TxRxSum(TxRxSum sum) {
457             txPkts = sum.txPkts;
458             rxPkts = sum.rxPkts;
459         }
460
461         public void reset() {
462             txPkts = -1;
463             rxPkts = -1;
464         }
465
466         @Override
467         public String toString() {
468             return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
469         }
470
471         public void updateTxRxSum() {
472             this.txPkts = TrafficStats.getMobileTcpTxPackets();
473             this.rxPkts = TrafficStats.getMobileTcpRxPackets();
474         }
475     }
476
477     protected void onActionIntentReconnectAlarm(Intent intent) {
478         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
479         String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
480
481         long phoneSubId = mPhone.getSubId();
482         long currSubId = intent.getLongExtra(PhoneConstants.SUBSCRIPTION_KEY,
483                 SubscriptionManager.INVALID_SUB_ID);
484         log("onActionIntentReconnectAlarm: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
485
486         // Stop reconnect if not current subId is not correct.
487         // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this.
488 //        if ((currSubId == SubscriptionManager.INVALID_SUB_ID) || (currSubId != phoneSubId)) {
489 //            log("receive ReconnectAlarm but subId incorrect, ignore");
490 //            return;
491 //        }
492
493         ApnContext apnContext = mApnContexts.get(apnType);
494
495         if (DBG) {
496             log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
497                     " apnType=" + apnType + " apnContext=" + apnContext +
498                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
499         }
500
501         if ((apnContext != null) && (apnContext.isEnabled())) {
502             apnContext.setReason(reason);
503             DctConstants.State apnContextState = apnContext.getState();
504             if (DBG) {
505                 log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
506             }
507             if ((apnContextState == DctConstants.State.FAILED)
508                     || (apnContextState == DctConstants.State.IDLE)) {
509                 if (DBG) {
510                     log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
511                 }
512                 DcAsyncChannel dcac = apnContext.getDcAc();
513                 if (dcac != null) {
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     protected void onActionIntentRestartTrySetupAlarm(Intent intent) {
529         String apnType = intent.getStringExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE);
530         ApnContext apnContext = mApnContexts.get(apnType);
531         if (DBG) {
532             log("onActionIntentRestartTrySetupAlarm: mState=" + mState +
533                     " apnType=" + apnType + " apnContext=" + apnContext +
534                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
535         }
536         sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
537     }
538
539     protected void onActionIntentDataStallAlarm(Intent intent) {
540         if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
541         Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM,
542                 intent.getAction());
543         msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
544         sendMessage(msg);
545     }
546
547     ConnectivityManager mCm;
548
549     /**
550      * Default constructor
551      */
552     protected DcTrackerBase(PhoneBase phone) {
553         super();
554         mPhone = phone;
555         if (DBG) log("DCT.constructor");
556         mResolver = mPhone.getContext().getContentResolver();
557         mUiccController = UiccController.getInstance();
558         mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
559         mAlarmManager =
560                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
561         mCm = (ConnectivityManager) mPhone.getContext().getSystemService(
562                 Context.CONNECTIVITY_SERVICE);
563
564
565         IntentFilter filter = new IntentFilter();
566         filter.addAction(Intent.ACTION_SCREEN_ON);
567         filter.addAction(Intent.ACTION_SCREEN_OFF);
568         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
569         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
570         filter.addAction(INTENT_DATA_STALL_ALARM);
571         filter.addAction(INTENT_PROVISIONING_APN_ALARM);
572
573         mUserDataEnabled = Settings.Global.getInt(
574                 mPhone.getContext().getContentResolver(), Settings.Global.MOBILE_DATA, 1) == 1;
575
576         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
577
578         // This preference tells us 1) initial condition for "dataEnabled",
579         // and 2) whether the RIL will setup the baseband to auto-PS attach.
580
581         mDataEnabled[DctConstants.APN_DEFAULT_ID] =
582                 SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,true);
583         if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) {
584             mEnabledCount++;
585         }
586
587         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
588         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
589
590         // Watch for changes to Settings.Global.DATA_ROAMING
591         mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone, mPhone.getContext());
592         mDataRoamingSettingObserver.register();
593
594         HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
595         dcHandlerThread.start();
596         Handler dcHandler = new Handler(dcHandlerThread.getLooper());
597         mDcc = DcController.makeDcc(mPhone, this, dcHandler);
598         mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler);
599     }
600
601     public void dispose() {
602         if (DBG) log("DCT.dispose");
603         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
604             dcac.disconnect();
605         }
606         mDataConnectionAcHashMap.clear();
607         mIsDisposed = true;
608         mPhone.getContext().unregisterReceiver(mIntentReceiver);
609         mUiccController.unregisterForIccChanged(this);
610         mDataRoamingSettingObserver.unregister();
611         mDcc.dispose();
612         mDcTesterFailBringUpAll.dispose();
613     }
614
615     public DctConstants.Activity getActivity() {
616         return mActivity;
617     }
618
619     void setActivity(DctConstants.Activity activity) {
620         log("setActivity = " + activity);
621         mActivity = activity;
622         mPhone.notifyDataActivity();
623     }
624
625     public boolean isApnTypeActive(String type) {
626         // TODO: support simultaneous with List instead
627         if (PhoneConstants.APN_TYPE_DUN.equals(type)) {
628             ApnSetting dunApn = fetchDunApn();
629             if (dunApn != null) {
630                 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
631             }
632         }
633         return mActiveApn != null && mActiveApn.canHandleType(type);
634     }
635
636     protected ApnSetting fetchDunApn() {
637         if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
638             log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
639             return null;
640         }
641         int bearer = -1;
642         Context c = mPhone.getContext();
643         String apnData = Settings.Global.getString(c.getContentResolver(),
644                 Settings.Global.TETHER_DUN_APN);
645         List<ApnSetting> dunSettings = ApnSetting.arrayFromString(apnData);
646         for (ApnSetting dunSetting : dunSettings) {
647             IccRecords r = mIccRecords.get();
648             String operator = (r != null) ? r.getOperatorNumeric() : "";
649             if (dunSetting.bearer != 0) {
650                 if (bearer == -1) bearer = mPhone.getServiceState().getRilDataRadioTechnology();
651                 if (dunSetting.bearer != bearer) continue;
652             }
653             if (dunSetting.numeric.equals(operator)) {
654                 if (dunSetting.hasMvnoParams()) {
655                     if (r != null &&
656                             mvnoMatches(r, dunSetting.mvnoType, dunSetting.mvnoMatchData)) {
657                         if (VDBG) {
658                             log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
659                         }
660                         return dunSetting;
661                     }
662                 } else {
663                     if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
664                     return dunSetting;
665                 }
666             }
667         }
668
669         apnData = c.getResources().getString(R.string.config_tether_apndata);
670         ApnSetting dunSetting = ApnSetting.fromString(apnData);
671         if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + dunSettings);
672         return dunSetting;
673     }
674
675     public String[] getActiveApnTypes() {
676         String[] result;
677         if (mActiveApn != null) {
678             result = mActiveApn.types;
679         } else {
680             result = new String[1];
681             result[0] = PhoneConstants.APN_TYPE_DEFAULT;
682         }
683         return result;
684     }
685
686     /** TODO: See if we can remove */
687     public String getActiveApnString(String apnType) {
688         String result = null;
689         if (mActiveApn != null) {
690             result = mActiveApn.apn;
691         }
692         return result;
693     }
694
695     /**
696      * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value.
697      */
698     public void setDataOnRoamingEnabled(boolean enabled) {
699         if (getDataOnRoamingEnabled() != enabled) {
700             final ContentResolver resolver = mPhone.getContext().getContentResolver();
701             Settings.Global.putInt(resolver, Settings.Global.DATA_ROAMING, enabled ? 1 : 0);
702             // will trigger handleDataOnRoamingChange() through observer
703         }
704     }
705
706     /**
707      * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
708      */
709     public boolean getDataOnRoamingEnabled() {
710         try {
711             final ContentResolver resolver = mPhone.getContext().getContentResolver();
712             return Settings.Global.getInt(resolver, Settings.Global.DATA_ROAMING) != 0;
713         } catch (SettingNotFoundException snfe) {
714             return false;
715         }
716     }
717
718     /**
719      * Modify {@link android.provider.Settings.Global#MOBILE_DATA} value.
720      */
721     public void setDataEnabled(boolean enable) {
722         Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE);
723         msg.arg1 = enable ? 1 : 0;
724         sendMessage(msg);
725     }
726
727     /**
728      * Return current {@link android.provider.Settings.Global#MOBILE_DATA} value.
729      */
730     public boolean getDataEnabled() {
731         try {
732             final ContentResolver resolver = mPhone.getContext().getContentResolver();
733             return Settings.Global.getInt(resolver, Settings.Global.MOBILE_DATA) != 0;
734         } catch (SettingNotFoundException snfe) {
735             return false;
736         }
737     }
738
739     // abstract methods
740     protected abstract void restartRadio();
741     protected abstract void log(String s);
742     protected abstract void loge(String s);
743     protected abstract boolean isDataAllowed();
744     protected abstract boolean isApnTypeAvailable(String type);
745     public    abstract DctConstants.State getState(String apnType);
746     protected abstract boolean isProvisioningApn(String apnType);
747     protected abstract void setState(DctConstants.State s);
748     protected abstract void gotoIdleAndNotifyDataConnection(String reason);
749
750     protected abstract boolean onTrySetupData(String reason);
751     protected abstract void onRoamingOff();
752     protected abstract void onRoamingOn();
753     protected abstract void onRadioAvailable();
754     protected abstract void onRadioOffOrNotAvailable();
755     protected abstract void onDataSetupComplete(AsyncResult ar);
756     protected abstract void onDataSetupCompleteError(AsyncResult ar);
757     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
758     protected abstract void onDisconnectDcRetrying(int connId, AsyncResult ar);
759     protected abstract void onVoiceCallStarted();
760     protected abstract void onVoiceCallEnded();
761     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
762     protected abstract void onCleanUpAllConnections(String cause);
763     public abstract boolean isDataPossible(String apnType);
764     protected abstract void onUpdateIcc();
765     protected abstract void completeConnection(ApnContext apnContext);
766     public abstract void setDataAllowed(boolean enable, Message response);
767     public abstract String[] getPcscfAddress(String apnType);
768     public abstract void setImsRegistrationState(boolean registered);
769     protected abstract boolean mvnoMatches(IccRecords r, String mvno_type, String mvno_match_data);
770     protected abstract boolean isPermanentFail(DcFailCause dcFailCause);
771
772     @Override
773     public void handleMessage(Message msg) {
774         switch (msg.what) {
775             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
776                 log("DISCONNECTED_CONNECTED: msg=" + msg);
777                 DcAsyncChannel dcac = (DcAsyncChannel) msg.obj;
778                 mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync());
779                 dcac.disconnected();
780                 break;
781             }
782             case DctConstants.EVENT_ENABLE_NEW_APN:
783                 onEnableApn(msg.arg1, msg.arg2);
784                 break;
785
786             case DctConstants.EVENT_TRY_SETUP_DATA:
787                 String reason = null;
788                 if (msg.obj instanceof String) {
789                     reason = (String) msg.obj;
790                 }
791                 onTrySetupData(reason);
792                 break;
793
794             case DctConstants.EVENT_DATA_STALL_ALARM:
795                 onDataStallAlarm(msg.arg1);
796                 break;
797
798             case DctConstants.EVENT_ROAMING_OFF:
799                 onRoamingOff();
800                 break;
801
802             case DctConstants.EVENT_ROAMING_ON:
803                 onRoamingOn();
804                 break;
805
806             case DctConstants.EVENT_RADIO_AVAILABLE:
807                 onRadioAvailable();
808                 break;
809
810             case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
811                 onRadioOffOrNotAvailable();
812                 break;
813
814             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
815                 mCidActive = msg.arg1;
816                 onDataSetupComplete((AsyncResult) msg.obj);
817                 break;
818
819             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
820                 onDataSetupCompleteError((AsyncResult) msg.obj);
821                 break;
822
823             case DctConstants.EVENT_DISCONNECT_DONE:
824                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
825                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
826                 break;
827
828             case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
829                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
830                 onDisconnectDcRetrying(msg.arg1, (AsyncResult) msg.obj);
831                 break;
832
833             case DctConstants.EVENT_VOICE_CALL_STARTED:
834                 onVoiceCallStarted();
835                 break;
836
837             case DctConstants.EVENT_VOICE_CALL_ENDED:
838                 onVoiceCallEnded();
839                 break;
840
841             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: {
842                 onCleanUpAllConnections((String) msg.obj);
843                 break;
844             }
845             case DctConstants.EVENT_CLEAN_UP_CONNECTION: {
846                 boolean tearDown = (msg.arg1 == 0) ? false : true;
847                 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
848                 break;
849             }
850             case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: {
851                 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
852                 onSetInternalDataEnabled(enabled);
853                 break;
854             }
855             case DctConstants.EVENT_RESET_DONE: {
856                 if (DBG) log("EVENT_RESET_DONE");
857                 onResetDone((AsyncResult) msg.obj);
858                 break;
859             }
860             case DctConstants.CMD_SET_USER_DATA_ENABLE: {
861                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
862                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
863                 onSetUserDataEnabled(enabled);
864                 break;
865             }
866             case DctConstants.CMD_SET_DEPENDENCY_MET: {
867                 boolean met = (msg.arg1 == DctConstants.ENABLED) ? true : false;
868                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
869                 Bundle bundle = msg.getData();
870                 if (bundle != null) {
871                     String apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
872                     if (apnType != null) {
873                         onSetDependencyMet(apnType, met);
874                     }
875                 }
876                 break;
877             }
878             case DctConstants.CMD_SET_POLICY_DATA_ENABLE: {
879                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
880                 onSetPolicyDataEnabled(enabled);
881                 break;
882             }
883             case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
884                 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1;
885                 if (DBG) {
886                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
887                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
888                 }
889                 if (sEnableFailFastRefCounter < 0) {
890                     final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
891                             + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0";
892                     loge(s);
893                     sEnableFailFastRefCounter = 0;
894                 }
895                 final boolean enabled = sEnableFailFastRefCounter > 0;
896                 if (DBG) {
897                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled
898                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
899                 }
900                 if (mFailFast != enabled) {
901                     mFailFast = enabled;
902                     mDataStallDetectionEnabled = !enabled;
903                     if (mDataStallDetectionEnabled
904                             && (getOverallState() == DctConstants.State.CONNECTED)
905                             && (!mInVoiceCall ||
906                                     mPhone.getServiceStateTracker()
907                                         .isConcurrentVoiceAndDataAllowed())) {
908                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall");
909                         stopDataStallAlarm();
910                         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
911                     } else {
912                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall");
913                         stopDataStallAlarm();
914                     }
915                 }
916
917                 break;
918             }
919             case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: {
920                 Bundle bundle = msg.getData();
921                 if (bundle != null) {
922                     try {
923                         mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY);
924                     } catch(ClassCastException e) {
925                         loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e);
926                         mProvisioningUrl = null;
927                     }
928                 }
929                 if (TextUtils.isEmpty(mProvisioningUrl)) {
930                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring");
931                     mIsProvisioning = false;
932                     mProvisioningUrl = null;
933                 } else {
934                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl);
935                     mIsProvisioning = true;
936                     startProvisioningApnAlarm();
937                 }
938                 break;
939             }
940             case DctConstants.EVENT_PROVISIONING_APN_ALARM: {
941                 if (DBG) log("EVENT_PROVISIONING_APN_ALARM");
942                 ApnContext apnCtx = mApnContexts.get("default");
943                 if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) {
944                     if (mProvisioningApnAlarmTag == msg.arg1) {
945                         if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting");
946                         mIsProvisioning = false;
947                         mProvisioningUrl = null;
948                         stopProvisioningApnAlarm();
949                         sendCleanUpConnection(true, apnCtx);
950                     } else {
951                         if (DBG) {
952                             log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
953                                     + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag
954                                     + " != arg1:" + msg.arg1);
955                         }
956                     }
957                 } else {
958                     if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore");
959                 }
960                 break;
961             }
962             case DctConstants.CMD_IS_PROVISIONING_APN: {
963                 if (DBG) log("CMD_IS_PROVISIONING_APN");
964                 boolean isProvApn;
965                 try {
966                     String apnType = null;
967                     Bundle bundle = msg.getData();
968                     if (bundle != null) {
969                         apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
970                     }
971                     if (TextUtils.isEmpty(apnType)) {
972                         loge("CMD_IS_PROVISIONING_APN: apnType is empty");
973                         isProvApn = false;
974                     } else {
975                         isProvApn = isProvisioningApn(apnType);
976                     }
977                 } catch (ClassCastException e) {
978                     loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring");
979                     isProvApn = false;
980                 }
981                 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn);
982                 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN,
983                         isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED);
984                 break;
985             }
986             case DctConstants.EVENT_ICC_CHANGED: {
987                 onUpdateIcc();
988                 break;
989             }
990             case DctConstants.EVENT_RESTART_RADIO: {
991                 restartRadio();
992                 break;
993             }
994             case DctConstants.CMD_NET_STAT_POLL: {
995                 if (msg.arg1 == DctConstants.ENABLED) {
996                     handleStartNetStatPoll((DctConstants.Activity)msg.obj);
997                 } else if (msg.arg1 == DctConstants.DISABLED) {
998                     handleStopNetStatPoll((DctConstants.Activity)msg.obj);
999                 }
1000                 break;
1001             }
1002             default:
1003                 Rlog.e("DATA", "Unidentified event msg=" + msg);
1004                 break;
1005         }
1006     }
1007
1008     /**
1009      * Report on whether data connectivity is enabled
1010      *
1011      * @return {@code false} if data connectivity has been explicitly disabled,
1012      *         {@code true} otherwise.
1013      */
1014     public boolean getAnyDataEnabled() {
1015         final boolean result;
1016         synchronized (mDataEnabledLock) {
1017             result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
1018                     && (mEnabledCount != 0));
1019         }
1020         if (!result && DBG) log("getAnyDataEnabled " + result);
1021         return result;
1022     }
1023
1024     protected boolean isEmergency() {
1025         final boolean result;
1026         synchronized (mDataEnabledLock) {
1027             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
1028         }
1029         log("isEmergency: result=" + result);
1030         return result;
1031     }
1032
1033     protected int apnTypeToId(String type) {
1034         if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DEFAULT)) {
1035             return DctConstants.APN_DEFAULT_ID;
1036         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_MMS)) {
1037             return DctConstants.APN_MMS_ID;
1038         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_SUPL)) {
1039             return DctConstants.APN_SUPL_ID;
1040         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DUN)) {
1041             return DctConstants.APN_DUN_ID;
1042         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_HIPRI)) {
1043             return DctConstants.APN_HIPRI_ID;
1044         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IMS)) {
1045             return DctConstants.APN_IMS_ID;
1046         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_FOTA)) {
1047             return DctConstants.APN_FOTA_ID;
1048         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_CBS)) {
1049             return DctConstants.APN_CBS_ID;
1050         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IA)) {
1051             return DctConstants.APN_IA_ID;
1052         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_EMERGENCY)) {
1053             return DctConstants.APN_EMERGENCY_ID;
1054         } else {
1055             return DctConstants.APN_INVALID_ID;
1056         }
1057     }
1058
1059     protected String apnIdToType(int id) {
1060         switch (id) {
1061         case DctConstants.APN_DEFAULT_ID:
1062             return PhoneConstants.APN_TYPE_DEFAULT;
1063         case DctConstants.APN_MMS_ID:
1064             return PhoneConstants.APN_TYPE_MMS;
1065         case DctConstants.APN_SUPL_ID:
1066             return PhoneConstants.APN_TYPE_SUPL;
1067         case DctConstants.APN_DUN_ID:
1068             return PhoneConstants.APN_TYPE_DUN;
1069         case DctConstants.APN_HIPRI_ID:
1070             return PhoneConstants.APN_TYPE_HIPRI;
1071         case DctConstants.APN_IMS_ID:
1072             return PhoneConstants.APN_TYPE_IMS;
1073         case DctConstants.APN_FOTA_ID:
1074             return PhoneConstants.APN_TYPE_FOTA;
1075         case DctConstants.APN_CBS_ID:
1076             return PhoneConstants.APN_TYPE_CBS;
1077         case DctConstants.APN_IA_ID:
1078             return PhoneConstants.APN_TYPE_IA;
1079         case DctConstants.APN_EMERGENCY_ID:
1080             return PhoneConstants.APN_TYPE_EMERGENCY;
1081         default:
1082             log("Unknown id (" + id + ") in apnIdToType");
1083             return PhoneConstants.APN_TYPE_DEFAULT;
1084         }
1085     }
1086
1087     public LinkProperties getLinkProperties(String apnType) {
1088         int id = apnTypeToId(apnType);
1089
1090         if (isApnIdEnabled(id)) {
1091             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
1092             return dcac.getLinkPropertiesSync();
1093         } else {
1094             return new LinkProperties();
1095         }
1096     }
1097
1098     public NetworkCapabilities getNetworkCapabilities(String apnType) {
1099         int id = apnTypeToId(apnType);
1100         if (isApnIdEnabled(id)) {
1101             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
1102             return dcac.getNetworkCapabilitiesSync();
1103         } else {
1104             return new NetworkCapabilities();
1105         }
1106     }
1107
1108     // tell all active apns of the current condition
1109     protected void notifyDataConnection(String reason) {
1110         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
1111             if (mDataEnabled[id]) {
1112                 mPhone.notifyDataConnection(reason, apnIdToType(id));
1113             }
1114         }
1115         notifyOffApnsOfAvailability(reason);
1116     }
1117
1118     // a new APN has gone active and needs to send events to catch up with the
1119     // current condition
1120     private void notifyApnIdUpToCurrent(String reason, int apnId) {
1121         switch (mState) {
1122             case IDLE:
1123                 break;
1124             case RETRYING:
1125             case CONNECTING:
1126             case SCANNING:
1127                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1128                         PhoneConstants.DataState.CONNECTING);
1129                 break;
1130             case CONNECTED:
1131             case DISCONNECTING:
1132                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1133                         PhoneConstants.DataState.CONNECTING);
1134                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1135                         PhoneConstants.DataState.CONNECTED);
1136                 break;
1137             default:
1138                 // Ignore
1139                 break;
1140         }
1141     }
1142
1143     // since we normally don't send info to a disconnected APN, we need to do this specially
1144     private void notifyApnIdDisconnected(String reason, int apnId) {
1145         mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1146                 PhoneConstants.DataState.DISCONNECTED);
1147     }
1148
1149     // disabled apn's still need avail/unavail notificiations - send them out
1150     protected void notifyOffApnsOfAvailability(String reason) {
1151         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
1152         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
1153             if (!isApnIdEnabled(id)) {
1154                 notifyApnIdDisconnected(reason, id);
1155             }
1156         }
1157     }
1158
1159     public boolean isApnTypeEnabled(String apnType) {
1160         if (apnType == null) {
1161             return false;
1162         } else {
1163             return isApnIdEnabled(apnTypeToId(apnType));
1164         }
1165     }
1166
1167     protected synchronized boolean isApnIdEnabled(int id) {
1168         if (id != DctConstants.APN_INVALID_ID) {
1169             return mDataEnabled[id];
1170         }
1171         return false;
1172     }
1173
1174     protected void setEnabled(int id, boolean enable) {
1175         if (DBG) {
1176             log("setEnabled(" + id + ", " + enable + ") with old state = " + mDataEnabled[id]
1177                     + " and enabledCount = " + mEnabledCount);
1178         }
1179         Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
1180         msg.arg1 = id;
1181         msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
1182         sendMessage(msg);
1183     }
1184
1185     protected void onEnableApn(int apnId, int enabled) {
1186         if (DBG) {
1187             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
1188                     ", enabled=" + enabled + ", dataEnabled = " + mDataEnabled[apnId] +
1189                     ", enabledCount = " + mEnabledCount + ", isApnTypeActive = " +
1190                     isApnTypeActive(apnIdToType(apnId)));
1191         }
1192         if (enabled == DctConstants.ENABLED) {
1193             synchronized (this) {
1194                 if (!mDataEnabled[apnId]) {
1195                     mDataEnabled[apnId] = true;
1196                     mEnabledCount++;
1197                 }
1198             }
1199             String type = apnIdToType(apnId);
1200             if (!isApnTypeActive(type)) {
1201                 mRequestedApnType = type;
1202                 onEnableNewApn();
1203             } else {
1204                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
1205             }
1206         } else {
1207             // disable
1208             boolean didDisable = false;
1209             synchronized (this) {
1210                 if (mDataEnabled[apnId]) {
1211                     mDataEnabled[apnId] = false;
1212                     mEnabledCount--;
1213                     didDisable = true;
1214                 }
1215             }
1216             if (didDisable) {
1217                 if ((mEnabledCount == 0) || (apnId == DctConstants.APN_DUN_ID)) {
1218                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
1219                     onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
1220                 }
1221
1222                 // send the disconnect msg manually, since the normal route wont send
1223                 // it (it's not enabled)
1224                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
1225                 if (mDataEnabled[DctConstants.APN_DEFAULT_ID] == true
1226                         && !isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) {
1227                     // TODO - this is an ugly way to restore the default conn - should be done
1228                     // by a real contention manager and policy that disconnects the lower pri
1229                     // stuff as enable requests come in and pops them back on as we disable back
1230                     // down to the lower pri stuff
1231                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
1232                     onEnableNewApn();
1233                 }
1234             }
1235         }
1236     }
1237
1238     /**
1239      * Called when we switch APNs.
1240      *
1241      * mRequestedApnType is set prior to call
1242      * To be overridden.
1243      */
1244     protected void onEnableNewApn() {
1245     }
1246
1247     /**
1248      * Called when EVENT_RESET_DONE is received so goto
1249      * IDLE state and send notifications to those interested.
1250      *
1251      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
1252      * TODO - needs to pass some notion of which connection is reset..
1253      */
1254     protected void onResetDone(AsyncResult ar) {
1255         if (DBG) log("EVENT_RESET_DONE");
1256         String reason = null;
1257         if (ar.userObj instanceof String) {
1258             reason = (String) ar.userObj;
1259         }
1260         gotoIdleAndNotifyDataConnection(reason);
1261     }
1262
1263     /**
1264      * Prevent mobile data connections from being established, or once again
1265      * allow mobile data connections. If the state toggles, then either tear
1266      * down or set up data, as appropriate to match the new state.
1267      *
1268      * @param enable indicates whether to enable ({@code true}) or disable (
1269      *            {@code false}) data
1270      * @return {@code true} if the operation succeeded
1271      */
1272     public boolean setInternalDataEnabled(boolean enable) {
1273         if (DBG)
1274             log("setInternalDataEnabled(" + enable + ")");
1275
1276         Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE);
1277         msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
1278         sendMessage(msg);
1279         return true;
1280     }
1281
1282     protected void onSetInternalDataEnabled(boolean enabled) {
1283         synchronized (mDataEnabledLock) {
1284             mInternalDataEnabled = enabled;
1285             if (enabled) {
1286                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
1287                 onTrySetupData(Phone.REASON_DATA_ENABLED);
1288             } else {
1289                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
1290                 cleanUpAllConnections(null);
1291             }
1292         }
1293     }
1294
1295     public void cleanUpAllConnections(String cause) {
1296         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
1297         msg.obj = cause;
1298         sendMessage(msg);
1299     }
1300
1301     public abstract boolean isDisconnected();
1302
1303     protected void onSetUserDataEnabled(boolean enabled) {
1304         synchronized (mDataEnabledLock) {
1305             final boolean prevEnabled = getAnyDataEnabled();
1306             if (mUserDataEnabled != enabled) {
1307                 mUserDataEnabled = enabled;
1308                 Settings.Global.putInt(mPhone.getContext().getContentResolver(),
1309                         Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
1310                 if (getDataOnRoamingEnabled() == false &&
1311                         mPhone.getServiceState().getRoaming() == true) {
1312                     if (enabled) {
1313                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
1314                     } else {
1315                         notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
1316                     }
1317                 }
1318                 if (prevEnabled != getAnyDataEnabled()) {
1319                     if (!prevEnabled) {
1320                         onTrySetupData(Phone.REASON_DATA_ENABLED);
1321                     } else {
1322                         onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
1323                     }
1324                 }
1325             }
1326         }
1327     }
1328
1329     protected void onSetDependencyMet(String apnType, boolean met) {
1330     }
1331
1332     protected void onSetPolicyDataEnabled(boolean enabled) {
1333         synchronized (mDataEnabledLock) {
1334             final boolean prevEnabled = getAnyDataEnabled();
1335             if (sPolicyDataEnabled != enabled) {
1336                 sPolicyDataEnabled = enabled;
1337                 if (prevEnabled != getAnyDataEnabled()) {
1338                     if (!prevEnabled) {
1339                         onTrySetupData(Phone.REASON_DATA_ENABLED);
1340                     } else {
1341                         onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
1342                     }
1343                 }
1344             }
1345         }
1346     }
1347
1348     protected String getReryConfig(boolean forDefault) {
1349         int nt = mPhone.getServiceState().getNetworkType();
1350
1351         if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
1352             (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
1353             (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
1354             (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
1355             (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
1356             (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
1357             // CDMA variant
1358             return SystemProperties.get("ro.cdma.data_retry_config");
1359         } else {
1360             // Use GSM varient for all others.
1361             if (forDefault) {
1362                 return SystemProperties.get("ro.gsm.data_retry_config");
1363             } else {
1364                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
1365             }
1366         }
1367     }
1368
1369     protected void resetPollStats() {
1370         mTxPkts = -1;
1371         mRxPkts = -1;
1372         mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
1373     }
1374
1375     protected abstract DctConstants.State getOverallState();
1376
1377     void startNetStatPoll() {
1378         if (getOverallState() == DctConstants.State.CONNECTED
1379                 && mNetStatPollEnabled == false) {
1380             if (DBG) {
1381                 log("startNetStatPoll");
1382             }
1383             resetPollStats();
1384             mNetStatPollEnabled = true;
1385             mPollNetStat.run();
1386         }
1387     }
1388
1389     void stopNetStatPoll() {
1390         mNetStatPollEnabled = false;
1391         removeCallbacks(mPollNetStat);
1392         if (DBG) {
1393             log("stopNetStatPoll");
1394         }
1395     }
1396
1397     public void sendStartNetStatPoll(DctConstants.Activity activity) {
1398         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
1399         msg.arg1 = DctConstants.ENABLED;
1400         msg.obj = activity;
1401         sendMessage(msg);
1402     }
1403
1404     protected void handleStartNetStatPoll(DctConstants.Activity activity) {
1405         startNetStatPoll();
1406         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1407         setActivity(activity);
1408     }
1409
1410     public void sendStopNetStatPoll(DctConstants.Activity activity) {
1411         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
1412         msg.arg1 = DctConstants.DISABLED;
1413         msg.obj = activity;
1414         sendMessage(msg);
1415     }
1416
1417     protected void handleStopNetStatPoll(DctConstants.Activity activity) {
1418         stopNetStatPoll();
1419         stopDataStallAlarm();
1420         setActivity(activity);
1421     }
1422
1423     public void updateDataActivity() {
1424         long sent, received;
1425
1426         DctConstants.Activity newActivity;
1427
1428         TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts);
1429         TxRxSum curTxRxSum = new TxRxSum();
1430         curTxRxSum.updateTxRxSum();
1431         mTxPkts = curTxRxSum.txPkts;
1432         mRxPkts = curTxRxSum.rxPkts;
1433
1434         if (VDBG) {
1435             log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum);
1436         }
1437
1438         if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) {
1439             sent = mTxPkts - preTxRxSum.txPkts;
1440             received = mRxPkts - preTxRxSum.rxPkts;
1441
1442             if (VDBG)
1443                 log("updateDataActivity: sent=" + sent + " received=" + received);
1444             if (sent > 0 && received > 0) {
1445                 newActivity = DctConstants.Activity.DATAINANDOUT;
1446             } else if (sent > 0 && received == 0) {
1447                 newActivity = DctConstants.Activity.DATAOUT;
1448             } else if (sent == 0 && received > 0) {
1449                 newActivity = DctConstants.Activity.DATAIN;
1450             } else {
1451                 newActivity = (mActivity == DctConstants.Activity.DORMANT) ?
1452                         mActivity : DctConstants.Activity.NONE;
1453             }
1454
1455             if (mActivity != newActivity && mIsScreenOn) {
1456                 if (VDBG)
1457                     log("updateDataActivity: newActivity=" + newActivity);
1458                 mActivity = newActivity;
1459                 mPhone.notifyDataActivity();
1460             }
1461         }
1462     }
1463
1464     // Recovery action taken in case of data stall
1465     protected static class RecoveryAction {
1466         public static final int GET_DATA_CALL_LIST      = 0;
1467         public static final int CLEANUP                 = 1;
1468         public static final int REREGISTER              = 2;
1469         public static final int RADIO_RESTART           = 3;
1470         public static final int RADIO_RESTART_WITH_PROP = 4;
1471
1472         private static boolean isAggressiveRecovery(int value) {
1473             return ((value == RecoveryAction.CLEANUP) ||
1474                     (value == RecoveryAction.REREGISTER) ||
1475                     (value == RecoveryAction.RADIO_RESTART) ||
1476                     (value == RecoveryAction.RADIO_RESTART_WITH_PROP));
1477         }
1478     }
1479
1480     public int getRecoveryAction() {
1481         int action = Settings.System.getInt(mPhone.getContext().getContentResolver(),
1482                 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
1483         if (VDBG_STALL) log("getRecoveryAction: " + action);
1484         return action;
1485     }
1486     public void putRecoveryAction(int action) {
1487         Settings.System.putInt(mPhone.getContext().getContentResolver(),
1488                 "radio.data.stall.recovery.action", action);
1489         if (VDBG_STALL) log("putRecoveryAction: " + action);
1490     }
1491
1492     protected boolean isConnected() {
1493         return false;
1494     }
1495
1496     protected void doRecovery() {
1497         if (getOverallState() == DctConstants.State.CONNECTED) {
1498             // Go through a series of recovery steps, each action transitions to the next action
1499             int recoveryAction = getRecoveryAction();
1500             switch (recoveryAction) {
1501             case RecoveryAction.GET_DATA_CALL_LIST:
1502                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
1503                         mSentSinceLastRecv);
1504                 if (DBG) log("doRecovery() get data call list");
1505                 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED));
1506                 putRecoveryAction(RecoveryAction.CLEANUP);
1507                 break;
1508             case RecoveryAction.CLEANUP:
1509                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv);
1510                 if (DBG) log("doRecovery() cleanup all connections");
1511                 cleanUpAllConnections(Phone.REASON_PDP_RESET);
1512                 putRecoveryAction(RecoveryAction.REREGISTER);
1513                 break;
1514             case RecoveryAction.REREGISTER:
1515                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
1516                         mSentSinceLastRecv);
1517                 if (DBG) log("doRecovery() re-register");
1518                 mPhone.getServiceStateTracker().reRegisterNetwork(null);
1519                 putRecoveryAction(RecoveryAction.RADIO_RESTART);
1520                 break;
1521             case RecoveryAction.RADIO_RESTART:
1522                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
1523                         mSentSinceLastRecv);
1524                 if (DBG) log("restarting radio");
1525                 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP);
1526                 restartRadio();
1527                 break;
1528             case RecoveryAction.RADIO_RESTART_WITH_PROP:
1529                 // This is in case radio restart has not recovered the data.
1530                 // It will set an additional "gsm.radioreset" property to tell
1531                 // RIL or system to take further action.
1532                 // The implementation of hard reset recovery action is up to OEM product.
1533                 // Once RADIO_RESET property is consumed, it is expected to set back
1534                 // to false by RIL.
1535                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1);
1536                 if (DBG) log("restarting radio with gsm.radioreset to true");
1537                 SystemProperties.set(RADIO_RESET_PROPERTY, "true");
1538                 // give 1 sec so property change can be notified.
1539                 try {
1540                     Thread.sleep(1000);
1541                 } catch (InterruptedException e) {}
1542                 restartRadio();
1543                 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
1544                 break;
1545             default:
1546                 throw new RuntimeException("doRecovery: Invalid recoveryAction=" +
1547                     recoveryAction);
1548             }
1549             mSentSinceLastRecv = 0;
1550         }
1551     }
1552
1553     private void updateDataStallInfo() {
1554         long sent, received;
1555
1556         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
1557         mDataStallTxRxSum.updateTxRxSum();
1558
1559         if (VDBG_STALL) {
1560             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
1561                     " preTxRxSum=" + preTxRxSum);
1562         }
1563
1564         sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts;
1565         received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts;
1566
1567         if (RADIO_TESTS) {
1568             if (SystemProperties.getBoolean("radio.test.data.stall", false)) {
1569                 log("updateDataStallInfo: radio.test.data.stall true received = 0;");
1570                 received = 0;
1571             }
1572         }
1573         if ( sent > 0 && received > 0 ) {
1574             if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
1575             mSentSinceLastRecv = 0;
1576             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
1577         } else if (sent > 0 && received == 0) {
1578             if (mPhone.getState() == PhoneConstants.State.IDLE) {
1579                 mSentSinceLastRecv += sent;
1580             } else {
1581                 mSentSinceLastRecv = 0;
1582             }
1583             if (DBG) {
1584                 log("updateDataStallInfo: OUT sent=" + sent +
1585                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
1586             }
1587         } else if (sent == 0 && received > 0) {
1588             if (VDBG_STALL) log("updateDataStallInfo: IN");
1589             mSentSinceLastRecv = 0;
1590             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
1591         } else {
1592             if (VDBG_STALL) log("updateDataStallInfo: NONE");
1593         }
1594     }
1595
1596     protected void onDataStallAlarm(int tag) {
1597         if (mDataStallAlarmTag != tag) {
1598             if (DBG) {
1599                 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag);
1600             }
1601             return;
1602         }
1603         updateDataStallInfo();
1604
1605         int hangWatchdogTrigger = Settings.Global.getInt(mResolver,
1606                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
1607                 NUMBER_SENT_PACKETS_OF_HANG);
1608
1609         boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
1610         if (mSentSinceLastRecv >= hangWatchdogTrigger) {
1611             if (DBG) {
1612                 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
1613             }
1614             suspectedStall = DATA_STALL_SUSPECTED;
1615             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
1616         } else {
1617             if (VDBG_STALL) {
1618                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
1619                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
1620             }
1621         }
1622         startDataStallAlarm(suspectedStall);
1623     }
1624
1625     protected void startDataStallAlarm(boolean suspectedStall) {
1626         int nextAction = getRecoveryAction();
1627         int delayInMs;
1628
1629         if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
1630             // If screen is on or data stall is currently suspected, set the alarm
1631             // with an aggresive timeout.
1632             if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
1633                 delayInMs = Settings.Global.getInt(mResolver,
1634                         Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
1635                         DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
1636             } else {
1637                 delayInMs = Settings.Global.getInt(mResolver,
1638                         Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
1639                         DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
1640             }
1641
1642             mDataStallAlarmTag += 1;
1643             if (VDBG_STALL) {
1644                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
1645                         " delay=" + (delayInMs / 1000) + "s");
1646             }
1647             Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
1648             intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
1649             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
1650                     PendingIntent.FLAG_UPDATE_CURRENT);
1651             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1652                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
1653         } else {
1654             if (VDBG_STALL) {
1655                 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
1656             }
1657         }
1658     }
1659
1660     protected void stopDataStallAlarm() {
1661         if (VDBG_STALL) {
1662             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
1663                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
1664         }
1665         mDataStallAlarmTag += 1;
1666         if (mDataStallAlarmIntent != null) {
1667             mAlarmManager.cancel(mDataStallAlarmIntent);
1668             mDataStallAlarmIntent = null;
1669         }
1670     }
1671
1672     protected void restartDataStallAlarm() {
1673         if (isConnected() == false) return;
1674         // To be called on screen status change.
1675         // Do not cancel the alarm if it is set with aggressive timeout.
1676         int nextAction = getRecoveryAction();
1677
1678         if (RecoveryAction.isAggressiveRecovery(nextAction)) {
1679             if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
1680             return;
1681         }
1682         if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
1683         stopDataStallAlarm();
1684         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1685     }
1686
1687     protected void setInitialAttachApn() {
1688         ApnSetting iaApnSetting = null;
1689         ApnSetting defaultApnSetting = null;
1690         ApnSetting firstApnSetting = null;
1691
1692         log("setInitialApn: E mPreferredApn=" + mPreferredApn);
1693
1694         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
1695             firstApnSetting = mAllApnSettings.get(0);
1696             log("setInitialApn: firstApnSetting=" + firstApnSetting);
1697
1698             // Search for Initial APN setting and the first apn that can handle default
1699             for (ApnSetting apn : mAllApnSettings) {
1700                 // Can't use apn.canHandleType(), as that returns true for APNs that have no type.
1701                 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA) &&
1702                         apn.carrierEnabled) {
1703                     // The Initial Attach APN is highest priority so use it if there is one
1704                     log("setInitialApn: iaApnSetting=" + apn);
1705                     iaApnSetting = apn;
1706                     break;
1707                 } else if ((defaultApnSetting == null)
1708                         && (apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT))) {
1709                     // Use the first default apn if no better choice
1710                     log("setInitialApn: defaultApnSetting=" + apn);
1711                     defaultApnSetting = apn;
1712                 }
1713             }
1714         }
1715
1716         // The priority of apn candidates from highest to lowest is:
1717         //   1) APN_TYPE_IA (Inital Attach)
1718         //   2) mPreferredApn, i.e. the current preferred apn
1719         //   3) The first apn that than handle APN_TYPE_DEFAULT
1720         //   4) The first APN we can find.
1721
1722         ApnSetting initialAttachApnSetting = null;
1723         if (iaApnSetting != null) {
1724             if (DBG) log("setInitialAttachApn: using iaApnSetting");
1725             initialAttachApnSetting = iaApnSetting;
1726         } else if (mPreferredApn != null) {
1727             if (DBG) log("setInitialAttachApn: using mPreferredApn");
1728             initialAttachApnSetting = mPreferredApn;
1729         } else if (defaultApnSetting != null) {
1730             if (DBG) log("setInitialAttachApn: using defaultApnSetting");
1731             initialAttachApnSetting = defaultApnSetting;
1732         } else if (firstApnSetting != null) {
1733             if (DBG) log("setInitialAttachApn: using firstApnSetting");
1734             initialAttachApnSetting = firstApnSetting;
1735         }
1736
1737         if (initialAttachApnSetting == null) {
1738             if (DBG) log("setInitialAttachApn: X There in no available apn");
1739         } else {
1740             if (DBG) log("setInitialAttachApn: X selected Apn=" + initialAttachApnSetting);
1741
1742             mPhone.mCi.setInitialAttachApn(initialAttachApnSetting.apn,
1743                     initialAttachApnSetting.protocol, initialAttachApnSetting.authType,
1744                     initialAttachApnSetting.user, initialAttachApnSetting.password, null);
1745         }
1746     }
1747
1748     protected void setDataProfilesAsNeeded() {
1749         if (DBG) log("setDataProfilesAsNeeded");
1750         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
1751             ArrayList<DataProfile> dps = new ArrayList<DataProfile>();
1752             for (ApnSetting apn : mAllApnSettings) {
1753                 if (apn.modemCognitive) {
1754                     DataProfile dp = new DataProfile(apn,
1755                             mPhone.getServiceState().getRoaming());
1756                     boolean isDup = false;
1757                     for(DataProfile dpIn : dps) {
1758                         if (dp.equals(dpIn)) {
1759                             isDup = true;
1760                             break;
1761                         }
1762                     }
1763                     if (!isDup) {
1764                         dps.add(dp);
1765                     }
1766                 }
1767             }
1768             if(dps.size() > 0) {
1769                 mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]), null);
1770             }
1771         }
1772     }
1773
1774     protected void onActionIntentProvisioningApnAlarm(Intent intent) {
1775         if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction());
1776         Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM,
1777                 intent.getAction());
1778         msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0);
1779         sendMessage(msg);
1780     }
1781
1782     protected void startProvisioningApnAlarm() {
1783         int delayInMs = Settings.Global.getInt(mResolver,
1784                                 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
1785                                 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT);
1786         if (Build.IS_DEBUGGABLE) {
1787             // Allow debug code to use a system property to provide another value
1788             String delayInMsStrg = Integer.toString(delayInMs);
1789             delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg);
1790             try {
1791                 delayInMs = Integer.parseInt(delayInMsStrg);
1792             } catch (NumberFormatException e) {
1793                 loge("startProvisioningApnAlarm: e=" + e);
1794             }
1795         }
1796         mProvisioningApnAlarmTag += 1;
1797         if (DBG) {
1798             log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag +
1799                     " delay=" + (delayInMs / 1000) + "s");
1800         }
1801         Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM);
1802         intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag);
1803         mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
1804                 PendingIntent.FLAG_UPDATE_CURRENT);
1805         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1806                 SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent);
1807     }
1808
1809     protected void stopProvisioningApnAlarm() {
1810         if (DBG) {
1811             log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag +
1812                     " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent);
1813         }
1814         mProvisioningApnAlarmTag += 1;
1815         if (mProvisioningApnAlarmIntent != null) {
1816             mAlarmManager.cancel(mProvisioningApnAlarmIntent);
1817             mProvisioningApnAlarmIntent = null;
1818         }
1819     }
1820
1821     void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
1822         if (DBG)log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
1823         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
1824         msg.arg1 = tearDown ? 1 : 0;
1825         msg.arg2 = 0;
1826         msg.obj = apnContext;
1827         sendMessage(msg);
1828     }
1829
1830     void sendRestartRadio() {
1831         if (DBG)log("sendRestartRadio:");
1832         Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO);
1833         sendMessage(msg);
1834     }
1835
1836     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1837         pw.println("DataConnectionTrackerBase:");
1838         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
1839         pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
1840         pw.println(" mUserDataEnabled=" + mUserDataEnabled);
1841         pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
1842         pw.println(" mDataEnabled:");
1843         for(int i=0; i < mDataEnabled.length; i++) {
1844             pw.printf("  mDataEnabled[%d]=%b\n", i, mDataEnabled[i]);
1845         }
1846         pw.flush();
1847         pw.println(" mEnabledCount=" + mEnabledCount);
1848         pw.println(" mRequestedApnType=" + mRequestedApnType);
1849         pw.println(" mPhone=" + mPhone.getPhoneName());
1850         pw.println(" mActivity=" + mActivity);
1851         pw.println(" mState=" + mState);
1852         pw.println(" mTxPkts=" + mTxPkts);
1853         pw.println(" mRxPkts=" + mRxPkts);
1854         pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
1855         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
1856         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
1857         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
1858         pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled);
1859         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
1860         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
1861         pw.println(" mResolver=" + mResolver);
1862         pw.println(" mIsWifiConnected=" + mIsWifiConnected);
1863         pw.println(" mReconnectIntent=" + mReconnectIntent);
1864         pw.println(" mCidActive=" + mCidActive);
1865         pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation);
1866         pw.println(" mIsScreenOn=" + mIsScreenOn);
1867         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
1868         pw.flush();
1869         pw.println(" ***************************************");
1870         DcController dcc = mDcc;
1871         if (dcc != null) {
1872             dcc.dump(fd, pw, args);
1873         } else {
1874             pw.println(" mDcc=null");
1875         }
1876         pw.println(" ***************************************");
1877         HashMap<Integer, DataConnection> dcs = mDataConnections;
1878         if (dcs != null) {
1879             Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
1880             pw.println(" mDataConnections: count=" + mDcSet.size());
1881             for (Entry<Integer, DataConnection> entry : mDcSet) {
1882                 pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
1883                 entry.getValue().dump(fd, pw, args);
1884             }
1885         } else {
1886             pw.println("mDataConnections=null");
1887         }
1888         pw.println(" ***************************************");
1889         pw.flush();
1890         HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
1891         if (apnToDcId != null) {
1892             Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
1893             pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
1894             for (Entry<String, Integer> entry : apnToDcIdSet) {
1895                 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
1896             }
1897         } else {
1898             pw.println("mApnToDataConnectionId=null");
1899         }
1900         pw.println(" ***************************************");
1901         pw.flush();
1902         ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
1903         if (apnCtxs != null) {
1904             Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
1905             pw.println(" mApnContexts size=" + apnCtxsSet.size());
1906             for (Entry<String, ApnContext> entry : apnCtxsSet) {
1907                 entry.getValue().dump(fd, pw, args);
1908             }
1909             pw.println(" ***************************************");
1910         } else {
1911             pw.println(" mApnContexts=null");
1912         }
1913         pw.flush();
1914         pw.println(" mActiveApn=" + mActiveApn);
1915         ArrayList<ApnSetting> apnSettings = mAllApnSettings;
1916         if (apnSettings != null) {
1917             pw.println(" mAllApnSettings size=" + apnSettings.size());
1918             for (int i=0; i < apnSettings.size(); i++) {
1919                 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i));
1920             }
1921             pw.flush();
1922         } else {
1923             pw.println(" mAllApnSettings=null");
1924         }
1925         pw.println(" mPreferredApn=" + mPreferredApn);
1926         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
1927         pw.println(" mIsDisposed=" + mIsDisposed);
1928         pw.println(" mIntentReceiver=" + mIntentReceiver);
1929         pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver);
1930         pw.flush();
1931     }
1932 }