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