Home | History | Annotate | Download | only in dataconnection
      1 /*
      2  * Copyright (C) 2006 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.internal.telephony.dataconnection;
     18 
     19 import android.app.AlarmManager;
     20 import android.app.PendingIntent;
     21 import android.content.BroadcastReceiver;
     22 import android.content.ContentResolver;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.IntentFilter;
     26 import android.content.SharedPreferences;
     27 import android.database.ContentObserver;
     28 import android.net.ConnectivityManager;
     29 import android.net.LinkCapabilities;
     30 import android.net.LinkProperties;
     31 import android.net.NetworkInfo;
     32 import android.net.TrafficStats;
     33 import android.net.wifi.WifiManager;
     34 import android.os.AsyncResult;
     35 import android.os.Build;
     36 import android.os.Bundle;
     37 import android.os.Handler;
     38 import android.os.HandlerThread;
     39 import android.os.Message;
     40 import android.os.Messenger;
     41 import android.os.SystemClock;
     42 import android.os.SystemProperties;
     43 import android.preference.PreferenceManager;
     44 import android.provider.Settings;
     45 import android.provider.Settings.SettingNotFoundException;
     46 import android.telephony.TelephonyManager;
     47 import android.text.TextUtils;
     48 import android.util.EventLog;
     49 import android.telephony.Rlog;
     50 
     51 import com.android.internal.R;
     52 import com.android.internal.telephony.DctConstants;
     53 import com.android.internal.telephony.DctConstants.State;
     54 import com.android.internal.telephony.EventLogTags;
     55 import com.android.internal.telephony.Phone;
     56 import com.android.internal.telephony.PhoneBase;
     57 import com.android.internal.telephony.PhoneConstants;
     58 import com.android.internal.telephony.uicc.IccRecords;
     59 import com.android.internal.telephony.uicc.UiccController;
     60 import com.android.internal.util.AsyncChannel;
     61 import com.android.internal.util.ArrayUtils;
     62 
     63 import java.io.FileDescriptor;
     64 import java.io.PrintWriter;
     65 import java.util.ArrayList;
     66 import java.util.HashMap;
     67 import java.util.Map.Entry;
     68 import java.util.Set;
     69 import java.util.concurrent.ConcurrentHashMap;
     70 import java.util.concurrent.atomic.AtomicInteger;
     71 import java.util.concurrent.atomic.AtomicReference;
     72 
     73 /**
     74  * {@hide}
     75  */
     76 public 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