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