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