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
17package com.android.internal.telephony;
18
19import android.app.PendingIntent;
20import android.content.BroadcastReceiver;
21import android.content.ContentResolver;
22import android.content.Context;
23import android.content.Intent;
24import android.content.IntentFilter;
25import android.content.SharedPreferences;
26import android.database.ContentObserver;
27import android.net.LinkCapabilities;
28import android.net.LinkProperties;
29import android.net.NetworkInfo;
30import android.net.TrafficStats;
31import android.net.wifi.WifiManager;
32import android.os.AsyncResult;
33import android.os.Bundle;
34import android.os.Handler;
35import android.os.Message;
36import android.os.Messenger;
37import android.os.SystemClock;
38import android.os.SystemProperties;
39import android.preference.PreferenceManager;
40import android.provider.Settings;
41import android.provider.Settings.SettingNotFoundException;
42import android.telephony.ServiceState;
43import android.telephony.TelephonyManager;
44import android.text.TextUtils;
45import android.util.Log;
46
47import com.android.internal.R;
48import com.android.internal.telephony.DataConnection.FailCause;
49import com.android.internal.util.AsyncChannel;
50import com.android.internal.util.Protocol;
51
52import java.io.FileDescriptor;
53import java.io.PrintWriter;
54import java.util.ArrayList;
55import java.util.HashMap;
56import java.util.Map.Entry;
57import java.util.Set;
58import java.util.concurrent.ConcurrentHashMap;
59import java.util.concurrent.atomic.AtomicInteger;
60
61/**
62 * {@hide}
63 */
64public abstract class DataConnectionTracker extends Handler {
65    protected static final boolean DBG = true;
66    protected static final boolean VDBG = false;
67
68    /**
69     * IDLE: ready to start data connection setup, default state
70     * INITING: state of issued setupDefaultPDP() but not finish yet
71     * CONNECTING: state of issued startPppd() but not finish yet
72     * SCANNING: data connection fails with one apn but other apns are available
73     *           ready to start data connection on other apns (before INITING)
74     * CONNECTED: IP connection is setup
75     * DISCONNECTING: Connection.disconnect() has been called, but PDP
76     *                context is not yet deactivated
77     * FAILED: data connection fail for all apns settings
78     *
79     * getDataConnectionState() maps State to DataState
80     *      FAILED or IDLE : DISCONNECTED
81     *      INITING or CONNECTING or SCANNING: CONNECTING
82     *      CONNECTED : CONNECTED or DISCONNECTING
83     */
84    public enum State {
85        IDLE,
86        INITING,
87        CONNECTING,
88        SCANNING,
89        CONNECTED,
90        DISCONNECTING,
91        FAILED
92    }
93
94    public enum Activity {
95        NONE,
96        DATAIN,
97        DATAOUT,
98        DATAINANDOUT,
99        DORMANT
100    }
101
102    public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER =
103        "com.android.internal.telephony";
104    public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
105
106    /***** Event Codes *****/
107    protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
108    protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
109    protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
110    protected static final int EVENT_RECORDS_LOADED = BASE + 2;
111    protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
112    protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
113    protected static final int EVENT_POLL_PDP = BASE + 5;
114    protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
115    protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
116    protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
117    protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
118    protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
119    protected static final int EVENT_ROAMING_ON = BASE + 11;
120    protected static final int EVENT_ROAMING_OFF = BASE + 12;
121    protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
122    protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
123    protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
124    protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
125    protected static final int EVENT_DATA_STALL_ALARM = BASE + 17;
126    protected static final int EVENT_DO_RECOVERY = BASE + 18;
127    protected static final int EVENT_APN_CHANGED = BASE + 19;
128    protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
129    protected static final int EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED = BASE + 21;
130    protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
131    protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
132    public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
133    protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
134    protected static final int EVENT_RESTART_RADIO = BASE + 26;
135    protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
136    protected static final int EVENT_RESET_DONE = BASE + 28;
137    public static final int CMD_SET_USER_DATA_ENABLE = BASE + 29;
138    public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
139    public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
140    public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
141
142    /***** Constants *****/
143
144    protected static final int APN_INVALID_ID = -1;
145    protected static final int APN_DEFAULT_ID = 0;
146    protected static final int APN_MMS_ID = 1;
147    protected static final int APN_SUPL_ID = 2;
148    protected static final int APN_DUN_ID = 3;
149    protected static final int APN_HIPRI_ID = 4;
150    protected static final int APN_IMS_ID = 5;
151    protected static final int APN_FOTA_ID = 6;
152    protected static final int APN_CBS_ID = 7;
153    protected static final int APN_NUM_TYPES = 8;
154
155    public static final int DISABLED = 0;
156    public static final int ENABLED = 1;
157
158    public static final String APN_TYPE_KEY = "apnType";
159
160    /** Delay between APN attempts.
161        Note the property override mechanism is there just for testing purpose only. */
162    protected static final int APN_DELAY_MILLIS =
163                                SystemProperties.getInt("persist.radio.apn_delay", 5000);
164
165    protected Object mDataEnabledLock = new Object();
166
167    // responds to the setInternalDataEnabled call - used internally to turn off data
168    // for example during emergency calls
169    protected boolean mInternalDataEnabled = true;
170
171    // responds to public (user) API to enable/disable data use
172    // independent of mInternalDataEnabled and requests for APN access
173    // persisted
174    protected boolean mUserDataEnabled = true;
175
176    // TODO: move away from static state once 5587429 is fixed.
177    protected static boolean sPolicyDataEnabled = true;
178
179    private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
180
181    private int enabledCount = 0;
182
183    /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
184    protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
185
186    /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
187    protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
188        + "5000,10000,20000,40000,80000:5000,160000:5000,"
189        + "320000:5000,640000:5000,1280000:5000,1800000:5000";
190
191    /** Retry configuration for secondary networks: 4 tries in 20 sec */
192    protected static final String SECONDARY_DATA_RETRY_CONFIG =
193            "max_retries=3, 5000, 5000, 5000";
194
195    /** Slow poll when attempting connection recovery. */
196    protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
197    /** Default max failure count before attempting to network re-registration. */
198    protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
199
200    /**
201     * After detecting a potential connection problem, this is the max number
202     * of subsequent polls before attempting recovery.
203     */
204    protected static final int NO_RECV_POLL_LIMIT = 24;
205    // 1 sec. default polling interval when screen is on.
206    protected static final int POLL_NETSTAT_MILLIS = 1000;
207    // 10 min. default polling interval when screen is off.
208    protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
209    // 2 min for round trip time
210    protected static final int POLL_LONGEST_RTT = 120 * 1000;
211    // Default sent packets without ack which triggers initial recovery steps
212    protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
213    // how long to wait before switching back to default APN
214    protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
215    // system property that can override the above value
216    protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
217    // represents an invalid IP address
218    protected static final String NULL_IP = "0.0.0.0";
219
220    // Default for the data stall alarm while non-aggressive stall detection
221    protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
222    // Default for the data stall alarm for aggressive stall detection
223    protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
224    // If attempt is less than this value we're doing first level recovery
225    protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1;
226    // Tag for tracking stale alarms
227    protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag";
228
229    // TODO: See if we can remove INTENT_RECONNECT_ALARM
230    //       having to have different values for GSM and
231    //       CDMA. If so we can then remove the need for
232    //       getActionIntentReconnectAlarm.
233    protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
234        "reconnect_alarm_extra_reason";
235
236    // Used for debugging. Send the INTENT with an optional counter value with the number
237    // of times the setup is to fail before succeeding. If the counter isn't passed the
238    // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
239    // adb shell am broadcast \
240    //  -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
241    //  --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
242    protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
243        "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
244    protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
245    protected int mFailDataSetupCounter = 0;
246    protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
247    protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
248
249    protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
250
251    // member variables
252    protected PhoneBase mPhone;
253    protected Activity mActivity = Activity.NONE;
254    protected State mState = State.IDLE;
255    protected Handler mDataConnectionTracker = null;
256
257
258    protected long mTxPkts;
259    protected long mRxPkts;
260    protected int mNetStatPollPeriod;
261    protected boolean mNetStatPollEnabled = false;
262
263    protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
264    // Used to track stale data stall alarms.
265    protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
266    // The current data stall alarm intent
267    protected PendingIntent mDataStallAlarmIntent = null;
268    // Number of packets sent since the last received packet
269    protected long mSentSinceLastRecv;
270    // Controls when a simple recovery attempt it to be tried
271    protected int mNoRecvPollCount = 0;
272
273    // wifi connection status will be updated by sticky intent
274    protected boolean mIsWifiConnected = false;
275
276    /** Intent sent when the reconnect alarm fires. */
277    protected PendingIntent mReconnectIntent = null;
278
279    /** CID of active data connection */
280    protected int mCidActive;
281
282    // When false we will not auto attach and manually attaching is required.
283    protected boolean mAutoAttachOnCreation = false;
284
285    // State of screen
286    // (TODO: Reconsider tying directly to screen, maybe this is
287    //        really a lower power mode")
288    protected boolean mIsScreenOn = true;
289
290    /** Allows the generation of unique Id's for DataConnection objects */
291    protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
292
293    /** The data connections. */
294    protected HashMap<Integer, DataConnection> mDataConnections =
295        new HashMap<Integer, DataConnection>();
296
297    /** The data connection async channels */
298    protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
299        new HashMap<Integer, DataConnectionAc>();
300
301    /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
302    protected HashMap<String, Integer> mApnToDataConnectionId =
303                                    new HashMap<String, Integer>();
304
305    /** Phone.APN_TYPE_* ===> ApnContext */
306    protected ConcurrentHashMap<String, ApnContext> mApnContexts =
307                                    new ConcurrentHashMap<String, ApnContext>();
308
309    /* Currently active APN */
310    protected ApnSetting mActiveApn;
311
312    /** allApns holds all apns */
313    protected ArrayList<ApnSetting> mAllApns = null;
314
315    /** preferred apn */
316    protected ApnSetting mPreferredApn = null;
317
318    /** Is packet service restricted by network */
319    protected boolean mIsPsRestricted = false;
320
321    /* Once disposed dont handle any messages */
322    protected boolean mIsDisposed = false;
323
324    protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
325    {
326        @Override
327        public void onReceive(Context context, Intent intent)
328        {
329            String action = intent.getAction();
330            if (DBG) log("onReceive: action=" + action);
331            if (action.equals(Intent.ACTION_SCREEN_ON)) {
332                mIsScreenOn = true;
333                stopNetStatPoll();
334                startNetStatPoll();
335                restartDataStallAlarm();
336            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
337                mIsScreenOn = false;
338                stopNetStatPoll();
339                startNetStatPoll();
340                restartDataStallAlarm();
341            } else if (action.startsWith(getActionIntentReconnectAlarm())) {
342                log("Reconnect alarm. Previous state was " + mState);
343                onActionIntentReconnectAlarm(intent);
344            } else if (action.equals(getActionIntentDataStallAlarm())) {
345                onActionIntentDataStallAlarm(intent);
346            } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
347                final android.net.NetworkInfo networkInfo = (NetworkInfo)
348                        intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
349                mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
350            } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
351                final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
352                        WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
353
354                if (!enabled) {
355                    // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
356                    // quit and won't report disconnected until next enabling.
357                    mIsWifiConnected = false;
358                }
359            } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
360                mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
361                mFailDataSetupFailCause = FailCause.fromInt(
362                        intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
363                                                    FailCause.ERROR_UNSPECIFIED.getErrorCode()));
364                if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
365                        " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
366            }
367        }
368    };
369
370    private final DataRoamingSettingObserver mDataRoamingSettingObserver;
371
372    private class DataRoamingSettingObserver extends ContentObserver {
373        public DataRoamingSettingObserver(Handler handler) {
374            super(handler);
375        }
376
377        public void register(Context context) {
378            final ContentResolver resolver = context.getContentResolver();
379            resolver.registerContentObserver(
380                    Settings.Secure.getUriFor(Settings.Secure.DATA_ROAMING), false, this);
381        }
382
383        public void unregister(Context context) {
384            final ContentResolver resolver = context.getContentResolver();
385            resolver.unregisterContentObserver(this);
386        }
387
388        @Override
389        public void onChange(boolean selfChange) {
390            // already running on mPhone handler thread
391            handleDataOnRoamingChange();
392        }
393    }
394
395    /**
396     * Maintian the sum of transmit and receive packets.
397     *
398     * The packet counts are initizlied and reset to -1 and
399     * remain -1 until they can be updated.
400     */
401    public class TxRxSum {
402        public long txPkts;
403        public long rxPkts;
404
405        public TxRxSum() {
406            reset();
407        }
408
409        public TxRxSum(long txPkts, long rxPkts) {
410            this.txPkts = txPkts;
411            this.rxPkts = rxPkts;
412        }
413
414        public TxRxSum(TxRxSum sum) {
415            txPkts = sum.txPkts;
416            rxPkts = sum.rxPkts;
417        }
418
419        public void reset() {
420            txPkts = -1;
421            rxPkts = -1;
422        }
423
424        public String toString() {
425            return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
426        }
427
428        public void updateTxRxSum() {
429            boolean txUpdated = false, rxUpdated = false;
430            long txSum = 0, rxSum = 0;
431            for (ApnContext apnContext : mApnContexts.values()) {
432                if (apnContext.getState() == State.CONNECTED) {
433                    DataConnectionAc dcac = apnContext.getDataConnectionAc();
434                    if (dcac == null) continue;
435
436                    LinkProperties linkProp = dcac.getLinkPropertiesSync();
437                    if (linkProp == null) continue;
438
439                    String iface = linkProp.getInterfaceName();
440
441                    if (iface != null) {
442                        long stats = TrafficStats.getTxPackets(iface);
443                        if (stats > 0) {
444                            txUpdated = true;
445                            txSum += stats;
446                        }
447                        stats = TrafficStats.getRxPackets(iface);
448                        if (stats > 0) {
449                            rxUpdated = true;
450                            rxSum += stats;
451                        }
452                    }
453                }
454            }
455            if (txUpdated) this.txPkts = txSum;
456            if (rxUpdated) this.rxPkts = rxSum;
457        }
458    }
459
460    protected boolean isDataSetupCompleteOk(AsyncResult ar) {
461        if (ar.exception != null) {
462            if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
463            return false;
464        }
465        if (mFailDataSetupCounter <= 0) {
466            if (DBG) log("isDataSetupCompleteOk return true");
467            return true;
468        }
469        ar.result = mFailDataSetupFailCause;
470        if (DBG) {
471            log("isDataSetupCompleteOk return false" +
472                    " mFailDataSetupCounter=" + mFailDataSetupCounter +
473                    " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
474        }
475        mFailDataSetupCounter -= 1;
476        return false;
477    }
478
479    protected void onActionIntentReconnectAlarm(Intent intent) {
480        String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
481        if (mState == State.FAILED) {
482            Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
483            msg.arg1 = 0; // tearDown is false
484            msg.arg2 = 0;
485            msg.obj = reason;
486            sendMessage(msg);
487        }
488        sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
489    }
490
491    protected void onActionIntentDataStallAlarm(Intent intent) {
492        if (VDBG) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
493        Message msg = obtainMessage(EVENT_DATA_STALL_ALARM, intent.getAction());
494        msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
495        sendMessage(msg);
496    }
497
498    /**
499     * Default constructor
500     */
501    protected DataConnectionTracker(PhoneBase phone) {
502        super();
503        if (DBG) log("DCT.constructor");
504        mPhone = phone;
505
506        IntentFilter filter = new IntentFilter();
507        filter.addAction(getActionIntentReconnectAlarm());
508        filter.addAction(Intent.ACTION_SCREEN_ON);
509        filter.addAction(Intent.ACTION_SCREEN_OFF);
510        filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
511        filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
512        filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
513
514        mUserDataEnabled = Settings.Secure.getInt(
515                mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, 1) == 1;
516
517        // TODO: Why is this registering the phone as the receiver of the intent
518        //       and not its own handler?
519        mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
520
521        // This preference tells us 1) initial condition for "dataEnabled",
522        // and 2) whether the RIL will setup the baseband to auto-PS attach.
523
524        dataEnabled[APN_DEFAULT_ID] = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,
525                                                                  true);
526        if (dataEnabled[APN_DEFAULT_ID]) {
527            enabledCount++;
528        }
529
530        SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
531        mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
532
533        // watch for changes to Settings.Secure.DATA_ROAMING
534        mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone);
535        mDataRoamingSettingObserver.register(mPhone.getContext());
536    }
537
538    public void dispose() {
539        if (DBG) log("DCT.dispose");
540        for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
541            dcac.disconnect();
542        }
543        mDataConnectionAsyncChannels.clear();
544        mIsDisposed = true;
545        mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
546        mDataRoamingSettingObserver.unregister(mPhone.getContext());
547    }
548
549    protected void broadcastMessenger() {
550        Intent intent = new Intent(ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
551        intent.putExtra(EXTRA_MESSENGER, new Messenger(this));
552        mPhone.getContext().sendBroadcast(intent);
553    }
554
555    public Activity getActivity() {
556        return mActivity;
557    }
558
559    public boolean isApnTypeActive(String type) {
560        // TODO: support simultaneous with List instead
561        if (Phone.APN_TYPE_DUN.equals(type)) {
562            ApnSetting dunApn = fetchDunApn();
563            if (dunApn != null) {
564                return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
565            }
566        }
567        return mActiveApn != null && mActiveApn.canHandleType(type);
568    }
569
570    protected ApnSetting fetchDunApn() {
571        if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
572            log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
573            return null;
574        }
575        Context c = mPhone.getContext();
576        String apnData = Settings.Secure.getString(c.getContentResolver(),
577                Settings.Secure.TETHER_DUN_APN);
578        ApnSetting dunSetting = ApnSetting.fromString(apnData);
579        if (dunSetting != null) {
580            if (VDBG) log("fetchDunApn: secure TETHER_DUN_APN dunSetting=" + dunSetting);
581            return dunSetting;
582        }
583
584        apnData = c.getResources().getString(R.string.config_tether_apndata);
585        dunSetting = ApnSetting.fromString(apnData);
586        if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + dunSetting);
587        return dunSetting;
588    }
589
590    public String[] getActiveApnTypes() {
591        String[] result;
592        if (mActiveApn != null) {
593            result = mActiveApn.types;
594        } else {
595            result = new String[1];
596            result[0] = Phone.APN_TYPE_DEFAULT;
597        }
598        return result;
599    }
600
601    /** TODO: See if we can remove */
602    public String getActiveApnString(String apnType) {
603        String result = null;
604        if (mActiveApn != null) {
605            result = mActiveApn.apn;
606        }
607        return result;
608    }
609
610    /**
611     * Modify {@link Settings.Secure#DATA_ROAMING} value.
612     */
613    public void setDataOnRoamingEnabled(boolean enabled) {
614        if (getDataOnRoamingEnabled() != enabled) {
615            final ContentResolver resolver = mPhone.getContext().getContentResolver();
616            Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
617            // will trigger handleDataOnRoamingChange() through observer
618        }
619    }
620
621    /**
622     * Return current {@link Settings.Secure#DATA_ROAMING} value.
623     */
624    public boolean getDataOnRoamingEnabled() {
625        try {
626            final ContentResolver resolver = mPhone.getContext().getContentResolver();
627            return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING) != 0;
628        } catch (SettingNotFoundException snfe) {
629            return false;
630        }
631    }
632
633    private void handleDataOnRoamingChange() {
634        if (mPhone.getServiceState().getRoaming()) {
635            if (getDataOnRoamingEnabled()) {
636                resetAllRetryCounts();
637            }
638            sendMessage(obtainMessage(EVENT_ROAMING_ON));
639        }
640    }
641
642    // abstract methods
643    protected abstract String getActionIntentReconnectAlarm();
644    protected abstract String getActionIntentDataStallAlarm();
645    protected abstract void startNetStatPoll();
646    protected abstract void stopNetStatPoll();
647    protected abstract void restartDataStallAlarm();
648    protected abstract void restartRadio();
649    protected abstract void log(String s);
650    protected abstract void loge(String s);
651    protected abstract boolean isDataAllowed();
652    protected abstract boolean isApnTypeAvailable(String type);
653    public    abstract State getState(String apnType);
654    protected abstract void setState(State s);
655    protected abstract void gotoIdleAndNotifyDataConnection(String reason);
656
657    protected abstract boolean onTrySetupData(String reason);
658    protected abstract void onRoamingOff();
659    protected abstract void onRoamingOn();
660    protected abstract void onRadioAvailable();
661    protected abstract void onRadioOffOrNotAvailable();
662    protected abstract void onDataSetupComplete(AsyncResult ar);
663    protected abstract void onDisconnectDone(int connId, AsyncResult ar);
664    protected abstract void onVoiceCallStarted();
665    protected abstract void onVoiceCallEnded();
666    protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
667    protected abstract void onCleanUpAllConnections(String cause);
668    protected abstract boolean isDataPossible(String apnType);
669
670    protected void onDataStallAlarm(int tag) {
671        loge("onDataStallAlarm: not impleted tag=" + tag);
672    }
673
674    @Override
675    public void handleMessage(Message msg) {
676        switch (msg.what) {
677            case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
678                log("DISCONNECTED_CONNECTED: msg=" + msg);
679                DataConnectionAc dcac = (DataConnectionAc) msg.obj;
680                mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
681                dcac.disconnected();
682                break;
683            }
684            case EVENT_ENABLE_NEW_APN:
685                onEnableApn(msg.arg1, msg.arg2);
686                break;
687
688            case EVENT_TRY_SETUP_DATA:
689                String reason = null;
690                if (msg.obj instanceof String) {
691                    reason = (String) msg.obj;
692                }
693                onTrySetupData(reason);
694                break;
695
696            case EVENT_DATA_STALL_ALARM:
697                onDataStallAlarm(msg.arg1);
698                break;
699
700            case EVENT_ROAMING_OFF:
701                if (getDataOnRoamingEnabled() == false) {
702                    resetAllRetryCounts();
703                }
704                onRoamingOff();
705                break;
706
707            case EVENT_ROAMING_ON:
708                onRoamingOn();
709                break;
710
711            case EVENT_RADIO_AVAILABLE:
712                onRadioAvailable();
713                break;
714
715            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
716                onRadioOffOrNotAvailable();
717                break;
718
719            case EVENT_DATA_SETUP_COMPLETE:
720                mCidActive = msg.arg1;
721                onDataSetupComplete((AsyncResult) msg.obj);
722                break;
723
724            case EVENT_DISCONNECT_DONE:
725                log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
726                onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
727                break;
728
729            case EVENT_VOICE_CALL_STARTED:
730                onVoiceCallStarted();
731                break;
732
733            case EVENT_VOICE_CALL_ENDED:
734                onVoiceCallEnded();
735                break;
736
737            case EVENT_CLEAN_UP_ALL_CONNECTIONS: {
738                onCleanUpAllConnections((String) msg.obj);
739                break;
740            }
741            case EVENT_CLEAN_UP_CONNECTION: {
742                boolean tearDown = (msg.arg1 == 0) ? false : true;
743                onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
744                break;
745            }
746            case EVENT_SET_INTERNAL_DATA_ENABLE: {
747                boolean enabled = (msg.arg1 == ENABLED) ? true : false;
748                onSetInternalDataEnabled(enabled);
749                break;
750            }
751            case EVENT_RESET_DONE: {
752                if (DBG) log("EVENT_RESET_DONE");
753                onResetDone((AsyncResult) msg.obj);
754                break;
755            }
756            case CMD_SET_USER_DATA_ENABLE: {
757                final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
758                if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
759                onSetUserDataEnabled(enabled);
760                break;
761            }
762            case CMD_SET_DEPENDENCY_MET: {
763                boolean met = (msg.arg1 == ENABLED) ? true : false;
764                if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
765                Bundle bundle = msg.getData();
766                if (bundle != null) {
767                    String apnType = (String)bundle.get(APN_TYPE_KEY);
768                    if (apnType != null) {
769                        onSetDependencyMet(apnType, met);
770                    }
771                }
772                break;
773            }
774            case CMD_SET_POLICY_DATA_ENABLE: {
775                final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
776                onSetPolicyDataEnabled(enabled);
777                break;
778            }
779            default:
780                Log.e("DATA", "Unidentified event msg=" + msg);
781                break;
782        }
783    }
784
785    /**
786     * Report on whether data connectivity is enabled
787     *
788     * @return {@code false} if data connectivity has been explicitly disabled,
789     *         {@code true} otherwise.
790     */
791    public boolean getAnyDataEnabled() {
792        final boolean result;
793        synchronized (mDataEnabledLock) {
794            result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
795                    && (enabledCount != 0));
796        }
797        if (!result && DBG) log("getAnyDataEnabled " + result);
798        return result;
799    }
800
801    protected boolean isEmergency() {
802        final boolean result;
803        synchronized (mDataEnabledLock) {
804            result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
805        }
806        log("isEmergency: result=" + result);
807        return result;
808    }
809
810    protected int apnTypeToId(String type) {
811        if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
812            return APN_DEFAULT_ID;
813        } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
814            return APN_MMS_ID;
815        } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
816            return APN_SUPL_ID;
817        } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
818            return APN_DUN_ID;
819        } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
820            return APN_HIPRI_ID;
821        } else if (TextUtils.equals(type, Phone.APN_TYPE_IMS)) {
822            return APN_IMS_ID;
823        } else if (TextUtils.equals(type, Phone.APN_TYPE_FOTA)) {
824            return APN_FOTA_ID;
825        } else if (TextUtils.equals(type, Phone.APN_TYPE_CBS)) {
826            return APN_CBS_ID;
827        } else {
828            return APN_INVALID_ID;
829        }
830    }
831
832    protected String apnIdToType(int id) {
833        switch (id) {
834        case APN_DEFAULT_ID:
835            return Phone.APN_TYPE_DEFAULT;
836        case APN_MMS_ID:
837            return Phone.APN_TYPE_MMS;
838        case APN_SUPL_ID:
839            return Phone.APN_TYPE_SUPL;
840        case APN_DUN_ID:
841            return Phone.APN_TYPE_DUN;
842        case APN_HIPRI_ID:
843            return Phone.APN_TYPE_HIPRI;
844        case APN_IMS_ID:
845            return Phone.APN_TYPE_IMS;
846        case APN_FOTA_ID:
847            return Phone.APN_TYPE_FOTA;
848        case APN_CBS_ID:
849            return Phone.APN_TYPE_CBS;
850        default:
851            log("Unknown id (" + id + ") in apnIdToType");
852            return Phone.APN_TYPE_DEFAULT;
853        }
854    }
855
856    protected LinkProperties getLinkProperties(String apnType) {
857        int id = apnTypeToId(apnType);
858
859        if (isApnIdEnabled(id)) {
860            // TODO - remove this cdma-only hack and support multiple DCs.
861            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
862            return dcac.getLinkPropertiesSync();
863        } else {
864            return new LinkProperties();
865        }
866    }
867
868    protected LinkCapabilities getLinkCapabilities(String apnType) {
869        int id = apnTypeToId(apnType);
870        if (isApnIdEnabled(id)) {
871            // TODO - remove this cdma-only hack and support multiple DCs.
872            DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
873            return dcac.getLinkCapabilitiesSync();
874        } else {
875            return new LinkCapabilities();
876        }
877    }
878
879    // tell all active apns of the current condition
880    protected void notifyDataConnection(String reason) {
881        for (int id = 0; id < APN_NUM_TYPES; id++) {
882            if (dataEnabled[id]) {
883                mPhone.notifyDataConnection(reason, apnIdToType(id));
884            }
885        }
886        notifyOffApnsOfAvailability(reason);
887    }
888
889    // a new APN has gone active and needs to send events to catch up with the
890    // current condition
891    private void notifyApnIdUpToCurrent(String reason, int apnId) {
892        switch (mState) {
893            case IDLE:
894            case INITING:
895                break;
896            case CONNECTING:
897            case SCANNING:
898                mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
899                break;
900            case CONNECTED:
901            case DISCONNECTING:
902                mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
903                mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED);
904                break;
905        }
906    }
907
908    // since we normally don't send info to a disconnected APN, we need to do this specially
909    private void notifyApnIdDisconnected(String reason, int apnId) {
910        mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED);
911    }
912
913    // disabled apn's still need avail/unavail notificiations - send them out
914    protected void notifyOffApnsOfAvailability(String reason) {
915        if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
916        for (int id = 0; id < APN_NUM_TYPES; id++) {
917            if (!isApnIdEnabled(id)) {
918                notifyApnIdDisconnected(reason, id);
919            }
920        }
921    }
922
923    public boolean isApnTypeEnabled(String apnType) {
924        if (apnType == null) {
925            return false;
926        } else {
927            return isApnIdEnabled(apnTypeToId(apnType));
928        }
929    }
930
931    protected synchronized boolean isApnIdEnabled(int id) {
932        if (id != APN_INVALID_ID) {
933            return dataEnabled[id];
934        }
935        return false;
936    }
937
938    /**
939     * Ensure that we are connected to an APN of the specified type.
940     *
941     * @param type the APN type (currently the only valid values are
942     *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
943     * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
944     *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
945     *         broadcast will be sent by the ConnectivityManager when a
946     *         connection to the APN has been established.
947     */
948    public synchronized int enableApnType(String type) {
949        int id = apnTypeToId(type);
950        if (id == APN_INVALID_ID) {
951            return Phone.APN_REQUEST_FAILED;
952        }
953
954        if (DBG) {
955            log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
956                    + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
957        }
958
959        if (!isApnTypeAvailable(type)) {
960            if (DBG) log("type not available");
961            return Phone.APN_TYPE_NOT_AVAILABLE;
962        }
963
964        if (isApnIdEnabled(id)) {
965            return Phone.APN_ALREADY_ACTIVE;
966        } else {
967            setEnabled(id, true);
968        }
969        return Phone.APN_REQUEST_STARTED;
970    }
971
972    /**
973     * The APN of the specified type is no longer needed. Ensure that if use of
974     * the default APN has not been explicitly disabled, we are connected to the
975     * default APN.
976     *
977     * @param type the APN type. The only valid values are currently
978     *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
979     * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
980     *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
981     *         broadcast will be sent by the ConnectivityManager when a
982     *         connection to the APN has been disconnected. A {@code
983     *         Phone.APN_REQUEST_FAILED} is returned if the type parameter is
984     *         invalid or if the apn wasn't enabled.
985     */
986    public synchronized int disableApnType(String type) {
987        if (DBG) log("disableApnType(" + type + ")");
988        int id = apnTypeToId(type);
989        if (id == APN_INVALID_ID) {
990            return Phone.APN_REQUEST_FAILED;
991        }
992        if (isApnIdEnabled(id)) {
993            setEnabled(id, false);
994            if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
995                if (dataEnabled[APN_DEFAULT_ID]) {
996                    return Phone.APN_ALREADY_ACTIVE;
997                } else {
998                    return Phone.APN_REQUEST_STARTED;
999                }
1000            } else {
1001                return Phone.APN_REQUEST_STARTED;
1002            }
1003        } else {
1004            return Phone.APN_REQUEST_FAILED;
1005        }
1006    }
1007
1008    protected void setEnabled(int id, boolean enable) {
1009        if (DBG) {
1010            log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id]
1011                    + " and enabledCount = " + enabledCount);
1012        }
1013        Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
1014        msg.arg1 = id;
1015        msg.arg2 = (enable ? ENABLED : DISABLED);
1016        sendMessage(msg);
1017    }
1018
1019    protected void onEnableApn(int apnId, int enabled) {
1020        if (DBG) {
1021            log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
1022                    ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] +
1023                    ", enabledCount = " + enabledCount + ", isApnTypeActive = " +
1024                    isApnTypeActive(apnIdToType(apnId)));
1025        }
1026        if (enabled == ENABLED) {
1027            synchronized (this) {
1028                if (!dataEnabled[apnId]) {
1029                    dataEnabled[apnId] = true;
1030                    enabledCount++;
1031                }
1032            }
1033            String type = apnIdToType(apnId);
1034            if (!isApnTypeActive(type)) {
1035                mRequestedApnType = type;
1036                onEnableNewApn();
1037            } else {
1038                notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
1039            }
1040        } else {
1041            // disable
1042            boolean didDisable = false;
1043            synchronized (this) {
1044                if (dataEnabled[apnId]) {
1045                    dataEnabled[apnId] = false;
1046                    enabledCount--;
1047                    didDisable = true;
1048                }
1049            }
1050            if (didDisable) {
1051                if ((enabledCount == 0) || (apnId == APN_DUN_ID)) {
1052                    mRequestedApnType = Phone.APN_TYPE_DEFAULT;
1053                    onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
1054                }
1055
1056                // send the disconnect msg manually, since the normal route wont send
1057                // it (it's not enabled)
1058                notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
1059                if (dataEnabled[APN_DEFAULT_ID] == true
1060                        && !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
1061                    // TODO - this is an ugly way to restore the default conn - should be done
1062                    // by a real contention manager and policy that disconnects the lower pri
1063                    // stuff as enable requests come in and pops them back on as we disable back
1064                    // down to the lower pri stuff
1065                    mRequestedApnType = Phone.APN_TYPE_DEFAULT;
1066                    onEnableNewApn();
1067                }
1068            }
1069        }
1070    }
1071
1072    /**
1073     * Called when we switch APNs.
1074     *
1075     * mRequestedApnType is set prior to call
1076     * To be overridden.
1077     */
1078    protected void onEnableNewApn() {
1079    }
1080
1081    /**
1082     * Called when EVENT_RESET_DONE is received so goto
1083     * IDLE state and send notifications to those interested.
1084     *
1085     * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
1086     * TODO - needs to pass some notion of which connection is reset..
1087     */
1088    protected void onResetDone(AsyncResult ar) {
1089        if (DBG) log("EVENT_RESET_DONE");
1090        String reason = null;
1091        if (ar.userObj instanceof String) {
1092            reason = (String) ar.userObj;
1093        }
1094        gotoIdleAndNotifyDataConnection(reason);
1095    }
1096
1097    /**
1098     * Prevent mobile data connections from being established, or once again
1099     * allow mobile data connections. If the state toggles, then either tear
1100     * down or set up data, as appropriate to match the new state.
1101     *
1102     * @param enable indicates whether to enable ({@code true}) or disable (
1103     *            {@code false}) data
1104     * @return {@code true} if the operation succeeded
1105     */
1106    public boolean setInternalDataEnabled(boolean enable) {
1107        if (DBG)
1108            log("setInternalDataEnabled(" + enable + ")");
1109
1110        Message msg = obtainMessage(EVENT_SET_INTERNAL_DATA_ENABLE);
1111        msg.arg1 = (enable ? ENABLED : DISABLED);
1112        sendMessage(msg);
1113        return true;
1114    }
1115
1116    protected void onSetInternalDataEnabled(boolean enabled) {
1117        synchronized (mDataEnabledLock) {
1118            mInternalDataEnabled = enabled;
1119            if (enabled) {
1120                log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
1121                resetAllRetryCounts();
1122                onTrySetupData(Phone.REASON_DATA_ENABLED);
1123            } else {
1124                log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
1125                cleanUpAllConnections(null);
1126            }
1127        }
1128    }
1129
1130    public void cleanUpAllConnections(String cause) {
1131        Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
1132        msg.obj = cause;
1133        sendMessage(msg);
1134    }
1135
1136    public abstract boolean isDisconnected();
1137
1138    protected void onSetUserDataEnabled(boolean enabled) {
1139        synchronized (mDataEnabledLock) {
1140            final boolean prevEnabled = getAnyDataEnabled();
1141            if (mUserDataEnabled != enabled) {
1142                mUserDataEnabled = enabled;
1143                Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1144                        Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
1145                if (getDataOnRoamingEnabled() == false &&
1146                        mPhone.getServiceState().getRoaming() == true) {
1147                    if (enabled) {
1148                        notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
1149                    } else {
1150                        notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
1151                    }
1152                }
1153                if (prevEnabled != getAnyDataEnabled()) {
1154                    if (!prevEnabled) {
1155                        resetAllRetryCounts();
1156                        onTrySetupData(Phone.REASON_DATA_ENABLED);
1157                    } else {
1158                        onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
1159                    }
1160                }
1161            }
1162        }
1163    }
1164
1165    protected void onSetDependencyMet(String apnType, boolean met) {
1166    }
1167
1168    protected void onSetPolicyDataEnabled(boolean enabled) {
1169        synchronized (mDataEnabledLock) {
1170            final boolean prevEnabled = getAnyDataEnabled();
1171            if (sPolicyDataEnabled != enabled) {
1172                sPolicyDataEnabled = enabled;
1173                if (prevEnabled != getAnyDataEnabled()) {
1174                    if (!prevEnabled) {
1175                        resetAllRetryCounts();
1176                        onTrySetupData(Phone.REASON_DATA_ENABLED);
1177                    } else {
1178                        onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
1179                    }
1180                }
1181            }
1182        }
1183    }
1184
1185    protected String getReryConfig(boolean forDefault) {
1186        int nt = mPhone.getServiceState().getNetworkType();
1187
1188        if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
1189            (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
1190            (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
1191            (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
1192            (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
1193            (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
1194            // CDMA variant
1195            return SystemProperties.get("ro.cdma.data_retry_config");
1196        } else {
1197            // Use GSM varient for all others.
1198            if (forDefault) {
1199                return SystemProperties.get("ro.gsm.data_retry_config");
1200            } else {
1201                return SystemProperties.get("ro.gsm.2nd_data_retry_config");
1202            }
1203        }
1204    }
1205
1206    protected void resetAllRetryCounts() {
1207        for (ApnContext ac : mApnContexts.values()) {
1208            ac.setRetryCount(0);
1209        }
1210        for (DataConnection dc : mDataConnections.values()) {
1211            dc.resetRetryCount();
1212        }
1213    }
1214
1215    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1216        pw.println("DataConnectionTracker:");
1217        pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
1218        pw.println(" mUserDataEnabled=" + mUserDataEnabled);
1219        pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
1220        pw.println(" dataEnabled:");
1221        for(int i=0; i < dataEnabled.length; i++) {
1222            pw.printf("  dataEnabled[%d]=%b\n", i, dataEnabled[i]);
1223        }
1224        pw.flush();
1225        pw.println(" enabledCount=" + enabledCount);
1226        pw.println(" mRequestedApnType=" + mRequestedApnType);
1227        pw.println(" mPhone=" + mPhone.getPhoneName());
1228        pw.println(" mActivity=" + mActivity);
1229        pw.println(" mState=" + mState);
1230        pw.println(" mTxPkts=" + mTxPkts);
1231        pw.println(" mRxPkts=" + mRxPkts);
1232        pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
1233        pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
1234        pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
1235        pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
1236        pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
1237        pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
1238        pw.println(" mIsWifiConnected=" + mIsWifiConnected);
1239        pw.println(" mReconnectIntent=" + mReconnectIntent);
1240        pw.println(" mCidActive=" + mCidActive);
1241        pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation);
1242        pw.println(" mIsScreenOn=" + mIsScreenOn);
1243        pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
1244        pw.flush();
1245        pw.println(" ***************************************");
1246        Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
1247        pw.println(" mDataConnections: count=" + mDcSet.size());
1248        for (Entry<Integer, DataConnection> entry : mDcSet) {
1249            pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
1250            entry.getValue().dump(fd, pw, args);
1251        }
1252        pw.println(" ***************************************");
1253        pw.flush();
1254        Set<Entry<String, Integer>> mApnToDcIdSet = mApnToDataConnectionId.entrySet();
1255        pw.println(" mApnToDataConnectonId size=" + mApnToDcIdSet.size());
1256        for (Entry<String, Integer> entry : mApnToDcIdSet) {
1257            pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
1258        }
1259        pw.println(" ***************************************");
1260        pw.flush();
1261        if (mApnContexts != null) {
1262            Set<Entry<String, ApnContext>> mApnContextsSet = mApnContexts.entrySet();
1263            pw.println(" mApnContexts size=" + mApnContextsSet.size());
1264            for (Entry<String, ApnContext> entry : mApnContextsSet) {
1265                entry.getValue().dump(fd, pw, args);
1266            }
1267            pw.println(" ***************************************");
1268        } else {
1269            pw.println(" mApnContexts=null");
1270        }
1271        pw.flush();
1272        pw.println(" mActiveApn=" + mActiveApn);
1273        if (mAllApns != null) {
1274            pw.println(" mAllApns size=" + mAllApns.size());
1275            for (int i=0; i < mAllApns.size(); i++) {
1276                pw.printf(" mAllApns[%d]: %s\n", i, mAllApns.get(i));
1277            }
1278            pw.flush();
1279        } else {
1280            pw.println(" mAllApns=null");
1281        }
1282        pw.println(" mPreferredApn=" + mPreferredApn);
1283        pw.println(" mIsPsRestricted=" + mIsPsRestricted);
1284        pw.println(" mIsDisposed=" + mIsDisposed);
1285        pw.println(" mIntentReceiver=" + mIntentReceiver);
1286        pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver);
1287        pw.flush();
1288    }
1289}
1290