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