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