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