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