Home | History | Annotate | Download | only in telephony
      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;
     18 
     19 import android.app.PendingIntent;
     20 import android.content.BroadcastReceiver;
     21 import android.content.ContentResolver;
     22 import android.content.Context;
     23 import android.content.Intent;
     24 import android.content.IntentFilter;
     25 import android.content.SharedPreferences;
     26 import android.database.ContentObserver;
     27 import android.net.LinkCapabilities;
     28 import android.net.LinkProperties;
     29 import android.net.NetworkInfo;
     30 import android.net.wifi.WifiManager;
     31 import android.os.AsyncResult;
     32 import android.os.Bundle;
     33 import android.os.Handler;
     34 import android.os.Message;
     35 import android.os.Messenger;
     36 import android.os.SystemProperties;
     37 import android.preference.PreferenceManager;
     38 import android.provider.Settings;
     39 import android.provider.Settings.SettingNotFoundException;
     40 import android.telephony.ServiceState;
     41 import android.text.TextUtils;
     42 import android.util.Log;
     43 
     44 import com.android.internal.R;
     45 import com.android.internal.telephony.DataConnection.FailCause;
     46 import com.android.internal.util.AsyncChannel;
     47 import com.android.internal.util.Protocol;
     48 
     49 import java.util.ArrayList;
     50 import java.util.HashMap;
     51 import java.util.concurrent.ConcurrentHashMap;
     52 import java.util.concurrent.atomic.AtomicInteger;
     53 
     54 /**
     55  * {@hide}
     56  */
     57 public abstract class DataConnectionTracker extends Handler {
     58     protected static final boolean DBG = true;
     59 
     60     /**
     61      * IDLE: ready to start data connection setup, default state
     62      * INITING: state of issued setupDefaultPDP() but not finish yet
     63      * CONNECTING: state of issued startPppd() but not finish yet
     64      * SCANNING: data connection fails with one apn but other apns are available
     65      *           ready to start data connection on other apns (before INITING)
     66      * CONNECTED: IP connection is setup
     67      * DISCONNECTING: Connection.disconnect() has been called, but PDP
     68      *                context is not yet deactivated
     69      * FAILED: data connection fail for all apns settings
     70      *
     71      * getDataConnectionState() maps State to DataState
     72      *      FAILED or IDLE : DISCONNECTED
     73      *      INITING or CONNECTING or SCANNING: CONNECTING
     74      *      CONNECTED : CONNECTED or DISCONNECTING
     75      */
     76     public enum State {
     77         IDLE,
     78         INITING,
     79         CONNECTING,
     80         SCANNING,
     81         CONNECTED,
     82         DISCONNECTING,
     83         FAILED
     84     }
     85 
     86     public enum Activity {
     87         NONE,
     88         DATAIN,
     89         DATAOUT,
     90         DATAINANDOUT,
     91         DORMANT
     92     }
     93 
     94     public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER =
     95         "com.android.internal.telephony";
     96     public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
     97 
     98     /***** Event Codes *****/
     99     protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
    100     protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
    101     protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
    102     protected static final int EVENT_RECORDS_LOADED = BASE + 2;
    103     protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
    104     protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
    105     protected static final int EVENT_POLL_PDP = BASE + 5;
    106     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
    107     protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
    108     protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
    109     protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
    110     protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
    111     protected static final int EVENT_ROAMING_ON = BASE + 11;
    112     protected static final int EVENT_ROAMING_OFF = BASE + 12;
    113     protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
    114     protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
    115     protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
    116     protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
    117     protected static final int EVENT_START_NETSTAT_POLL = BASE + 17;
    118     protected static final int EVENT_START_RECOVERY = BASE + 18;
    119     protected static final int EVENT_APN_CHANGED = BASE + 19;
    120     protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
    121     protected static final int EVENT_NV_READY = BASE + 21;
    122     protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
    123     protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
    124     public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
    125     protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
    126     protected static final int EVENT_RESTART_RADIO = BASE + 26;
    127     protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
    128     protected static final int EVENT_RESET_DONE = BASE + 28;
    129     public static final int CMD_SET_USER_DATA_ENABLE = BASE + 29;
    130     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
    131     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
    132     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
    133 
    134     /***** Constants *****/
    135 
    136     protected static final int APN_INVALID_ID = -1;
    137     protected static final int APN_DEFAULT_ID = 0;
    138     protected static final int APN_MMS_ID = 1;
    139     protected static final int APN_SUPL_ID = 2;
    140     protected static final int APN_DUN_ID = 3;
    141     protected static final int APN_HIPRI_ID = 4;
    142     protected static final int APN_IMS_ID = 5;
    143     protected static final int APN_FOTA_ID = 6;
    144     protected static final int APN_CBS_ID = 7;
    145     protected static final int APN_NUM_TYPES = 8;
    146 
    147     public static final int DISABLED = 0;
    148     public static final int ENABLED = 1;
    149 
    150     public static final String APN_TYPE_KEY = "apnType";
    151 
    152     /** Delay between APN attempts.
    153         Note the property override mechanism is there just for testing purpose only. */
    154     protected static final int APN_DELAY_MILLIS =
    155                                 SystemProperties.getInt("persist.radio.apn_delay", 5000);
    156 
    157     protected Object mDataEnabledLock = new Object();
    158 
    159     // responds to the setInternalDataEnabled call - used internally to turn off data
    160     // for example during emergency calls
    161     protected boolean mInternalDataEnabled = true;
    162 
    163     // responds to public (user) API to enable/disable data use
    164     // independent of mInternalDataEnabled and requests for APN access
    165     // persisted
    166     protected boolean mUserDataEnabled = true;
    167     protected boolean mPolicyDataEnabled = true;
    168 
    169     private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
    170 
    171     private int enabledCount = 0;
    172 
    173     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
    174     protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
    175 
    176     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
    177     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
    178         + "5000,10000,20000,40000,80000:5000,160000:5000,"
    179         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
    180 
    181     /** Retry configuration for secondary networks: 4 tries in 20 sec */
    182     protected static final String SECONDARY_DATA_RETRY_CONFIG =
    183             "max_retries=3, 5000, 5000, 5000";
    184 
    185     /** Slow poll when attempting connection recovery. */
    186     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
    187     /** Default max failure count before attempting to network re-registration. */
    188     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
    189 
    190     /**
    191      * After detecting a potential connection problem, this is the max number
    192      * of subsequent polls before attempting a radio reset.  At this point,
    193      * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
    194      * poll for about 2 more minutes.
    195      */
    196     protected static final int NO_RECV_POLL_LIMIT = 24;
    197 
    198     // 1 sec. default polling interval when screen is on.
    199     protected static final int POLL_NETSTAT_MILLIS = 1000;
    200     // 10 min. default polling interval when screen is off.
    201     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
    202     // 2 min for round trip time
    203     protected static final int POLL_LONGEST_RTT = 120 * 1000;
    204     // 10 for packets without ack
    205     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
    206     // how long to wait before switching back to default APN
    207     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
    208     // system property that can override the above value
    209     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
    210     // represents an invalid IP address
    211     protected static final String NULL_IP = "0.0.0.0";
    212 
    213     // TODO: See if we can remove INTENT_RECONNECT_ALARM
    214     //       having to have different values for GSM and
    215     //       CDMA. If so we can then remove the need for
    216     //       getActionIntentReconnectAlarm.
    217     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
    218 
    219     // Used for debugging. Send the INTENT with an optional counter value with the number
    220     // of times the setup is to fail before succeeding. If the counter isn't passed the
    221     // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
    222     // adb shell am broadcast \
    223     //  -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
    224     //  --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
    225     protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
    226         "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
    227     protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
    228     protected int mFailDataSetupCounter = 0;
    229     protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
    230     protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
    231 
    232     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
    233 
    234     // member variables
    235     protected PhoneBase mPhone;
    236     protected Activity mActivity = Activity.NONE;
    237     protected State mState = State.IDLE;
    238     protected Handler mDataConnectionTracker = null;
    239 
    240 
    241     protected long mTxPkts;
    242     protected long mRxPkts;
    243     protected long mSentSinceLastRecv;
    244     protected int mNetStatPollPeriod;
    245     protected int mNoRecvPollCount = 0;
    246     protected boolean mNetStatPollEnabled = false;
    247 
    248     // wifi connection status will be updated by sticky intent
    249     protected boolean mIsWifiConnected = false;
    250 
    251     /** Intent sent when the reconnect alarm fires. */
    252     protected PendingIntent mReconnectIntent = null;
    253 
    254     /** CID of active data connection */
    255     protected int mCidActive;
    256 
    257     // When false we will not auto attach and manually attaching is required.
    258     protected boolean mAutoAttachOnCreation = false;
    259 
    260     // State of screen
    261     // (TODO: Reconsider tying directly to screen, maybe this is
    262     //        really a lower power mode")
    263     protected boolean mIsScreenOn = true;
    264 
    265     /** Allows the generation of unique Id's for DataConnection objects */
    266     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
    267 
    268     /** The data connections. */
    269     protected HashMap<Integer, DataConnection> mDataConnections =
    270         new HashMap<Integer, DataConnection>();
    271 
    272     /** The data connection async channels */
    273     protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
    274         new HashMap<Integer, DataConnectionAc>();
    275 
    276     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
    277     protected HashMap<String, Integer> mApnToDataConnectionId =
    278                                     new HashMap<String, Integer>();
    279 
    280     /** Phone.APN_TYPE_* ===> ApnContext */
    281     protected ConcurrentHashMap<String, ApnContext> mApnContexts;
    282 
    283     /* Currently active APN */
    284     protected ApnSetting mActiveApn;
    285 
    286     /** allApns holds all apns */
    287     protected ArrayList<ApnSetting> mAllApns = null;
    288 
    289     /** preferred apn */
    290     protected ApnSetting mPreferredApn = null;
    291 
    292     /** Is packet service restricted by network */
    293     protected boolean mIsPsRestricted = false;
    294 
    295     /* Once disposed dont handle any messages */
    296     protected boolean mIsDisposed = false;
    297 
    298     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
    299     {
    300         @Override
    301         public void onReceive(Context context, Intent intent)
    302         {
    303             String action = intent.getAction();
    304             if (DBG) log("onReceive: action=" + action);
    305             if (action.equals(Intent.ACTION_SCREEN_ON)) {
    306                 mIsScreenOn = true;
    307                 stopNetStatPoll();
    308                 startNetStatPoll();
    309             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
    310                 mIsScreenOn = false;
    311                 stopNetStatPoll();
    312                 startNetStatPoll();
    313             } else if (action.startsWith(getActionIntentReconnectAlarm())) {
    314                 log("Reconnect alarm. Previous state was " + mState);
    315                 onActionIntentReconnectAlarm(intent);
    316 
    317             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
    318                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
    319                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
    320                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
    321             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
    322                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
    323                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
    324 
    325                 if (!enabled) {
    326                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
    327                     // quit and won't report disconnected until next enabling.
    328                     mIsWifiConnected = false;
    329                 }
    330             } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
    331                 mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
    332                 mFailDataSetupFailCause = FailCause.fromInt(
    333                         intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
    334                                                     FailCause.ERROR_UNSPECIFIED.getErrorCode()));
    335                 if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
    336                         " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
    337             }
    338         }
    339     };
    340 
    341     private final DataRoamingSettingObserver mDataRoamingSettingObserver;
    342 
    343     private class DataRoamingSettingObserver extends ContentObserver {
    344         public DataRoamingSettingObserver(Handler handler) {
    345             super(handler);
    346         }
    347 
    348         public void register(Context context) {
    349             final ContentResolver resolver = context.getContentResolver();
    350             resolver.registerContentObserver(
    351                     Settings.Secure.getUriFor(Settings.Secure.DATA_ROAMING), false, this);
    352         }
    353 
    354         public void unregister(Context context) {
    355             final ContentResolver resolver = context.getContentResolver();
    356             resolver.unregisterContentObserver(this);
    357         }
    358 
    359         @Override
    360         public void onChange(boolean selfChange) {
    361             // already running on mPhone handler thread
    362             handleDataOnRoamingChange();
    363         }
    364     }
    365 
    366     protected boolean isDataSetupCompleteOk(AsyncResult ar) {
    367         if (ar.exception != null) {
    368             if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
    369             return false;
    370         }
    371         if (mFailDataSetupCounter <= 0) {
    372             if (DBG) log("isDataSetupCompleteOk return true");
    373             return true;
    374         }
    375         ar.result = mFailDataSetupFailCause;
    376         if (DBG) {
    377             log("isDataSetupCompleteOk return false" +
    378                     " mFailDataSetupCounter=" + mFailDataSetupCounter +
    379                     " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
    380         }
    381         mFailDataSetupCounter -= 1;
    382         return false;
    383     }
    384 
    385     protected void onActionIntentReconnectAlarm(Intent intent) {
    386         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
    387         if (mState == State.FAILED) {
    388             Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
    389             msg.arg1 = 0; // tearDown is false
    390             msg.arg2 = 0;
    391             msg.obj = reason;
    392             sendMessage(msg);
    393         }
    394         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
    395     }
    396 
    397     /**
    398      * Default constructor
    399      */
    400     protected DataConnectionTracker(PhoneBase phone) {
    401         super();
    402         mPhone = phone;
    403 
    404         IntentFilter filter = new IntentFilter();
    405         filter.addAction(getActionIntentReconnectAlarm());
    406         filter.addAction(Intent.ACTION_SCREEN_ON);
    407         filter.addAction(Intent.ACTION_SCREEN_OFF);
    408         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
    409         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
    410         filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
    411 
    412         mUserDataEnabled = Settings.Secure.getInt(
    413                 mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, 1) == 1;
    414 
    415         // TODO: Why is this registering the phone as the receiver of the intent
    416         //       and not its own handler?
    417         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
    418 
    419         // This preference tells us 1) initial condition for "dataEnabled",
    420         // and 2) whether the RIL will setup the baseband to auto-PS attach.
    421 
    422         dataEnabled[APN_DEFAULT_ID] = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,
    423                                                                   true);
    424         if (dataEnabled[APN_DEFAULT_ID]) {
    425             enabledCount++;
    426         }
    427 
    428         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
    429         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
    430 
    431         // watch for changes to Settings.Secure.DATA_ROAMING
    432         mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone);
    433         mDataRoamingSettingObserver.register(mPhone.getContext());
    434     }
    435 
    436     public void dispose() {
    437         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
    438             dcac.disconnect();
    439         }
    440         mDataConnectionAsyncChannels.clear();
    441         mIsDisposed = true;
    442         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
    443         mDataRoamingSettingObserver.unregister(mPhone.getContext());
    444     }
    445 
    446     protected void broadcastMessenger() {
    447         Intent intent = new Intent(ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
    448         intent.putExtra(EXTRA_MESSENGER, new Messenger(this));
    449         mPhone.getContext().sendBroadcast(intent);
    450     }
    451 
    452     public Activity getActivity() {
    453         return mActivity;
    454     }
    455 
    456     public boolean isApnTypeActive(String type) {
    457         // TODO: support simultaneous with List instead
    458         if (Phone.APN_TYPE_DUN.equals(type)) {
    459             ApnSetting dunApn = fetchDunApn();
    460             if (dunApn != null) {
    461                 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
    462             }
    463         }
    464         return mActiveApn != null && mActiveApn.canHandleType(type);
    465     }
    466 
    467     protected ApnSetting fetchDunApn() {
    468         Context c = mPhone.getContext();
    469         String apnData = Settings.Secure.getString(c.getContentResolver(),
    470                 Settings.Secure.TETHER_DUN_APN);
    471         ApnSetting dunSetting = ApnSetting.fromString(apnData);
    472         if (dunSetting != null) return dunSetting;
    473 
    474         apnData = c.getResources().getString(R.string.config_tether_apndata);
    475         return ApnSetting.fromString(apnData);
    476     }
    477 
    478     public String[] getActiveApnTypes() {
    479         String[] result;
    480         if (mActiveApn != null) {
    481             result = mActiveApn.types;
    482         } else {
    483             result = new String[1];
    484             result[0] = Phone.APN_TYPE_DEFAULT;
    485         }
    486         return result;
    487     }
    488 
    489     /** TODO: See if we can remove */
    490     public String getActiveApnString(String apnType) {
    491         String result = null;
    492         if (mActiveApn != null) {
    493             result = mActiveApn.apn;
    494         }
    495         return result;
    496     }
    497 
    498     /**
    499      * Modify {@link Settings.Secure#DATA_ROAMING} value.
    500      */
    501     public void setDataOnRoamingEnabled(boolean enabled) {
    502         if (getDataOnRoamingEnabled() != enabled) {
    503             final ContentResolver resolver = mPhone.getContext().getContentResolver();
    504             Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
    505             // will trigger handleDataOnRoamingChange() through observer
    506         }
    507     }
    508 
    509     /**
    510      * Return current {@link Settings.Secure#DATA_ROAMING} value.
    511      */
    512     public boolean getDataOnRoamingEnabled() {
    513         try {
    514             final ContentResolver resolver = mPhone.getContext().getContentResolver();
    515             return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING) != 0;
    516         } catch (SettingNotFoundException snfe) {
    517             return false;
    518         }
    519     }
    520 
    521     private void handleDataOnRoamingChange() {
    522         if (mPhone.getServiceState().getRoaming()) {
    523             if (getDataOnRoamingEnabled()) {
    524                 resetAllRetryCounts();
    525             }
    526             sendMessage(obtainMessage(EVENT_ROAMING_ON));
    527         }
    528     }
    529 
    530     // abstract methods
    531     protected abstract String getActionIntentReconnectAlarm();
    532     protected abstract void startNetStatPoll();
    533     protected abstract void stopNetStatPoll();
    534     protected abstract void restartRadio();
    535     protected abstract void log(String s);
    536     protected abstract void loge(String s);
    537     protected abstract boolean isDataAllowed();
    538     protected abstract boolean isApnTypeAvailable(String type);
    539     public    abstract State getState(String apnType);
    540     protected abstract void setState(State s);
    541     protected abstract void gotoIdleAndNotifyDataConnection(String reason);
    542 
    543     protected abstract boolean onTrySetupData(String reason);
    544     protected abstract void onRoamingOff();
    545     protected abstract void onRoamingOn();
    546     protected abstract void onRadioAvailable();
    547     protected abstract void onRadioOffOrNotAvailable();
    548     protected abstract void onDataSetupComplete(AsyncResult ar);
    549     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
    550     protected abstract void onVoiceCallStarted();
    551     protected abstract void onVoiceCallEnded();
    552     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
    553     protected abstract void onCleanUpAllConnections(String cause);
    554     protected abstract boolean isDataPossible(String apnType);
    555 
    556     @Override
    557     public void handleMessage(Message msg) {
    558         switch (msg.what) {
    559             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
    560                 log("DISCONNECTED_CONNECTED: msg=" + msg);
    561                 DataConnectionAc dcac = (DataConnectionAc) msg.obj;
    562                 mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
    563                 dcac.disconnected();
    564                 break;
    565             }
    566             case EVENT_ENABLE_NEW_APN:
    567                 onEnableApn(msg.arg1, msg.arg2);
    568                 break;
    569 
    570             case EVENT_TRY_SETUP_DATA:
    571                 String reason = null;
    572                 if (msg.obj instanceof String) {
    573                     reason = (String) msg.obj;
    574                 }
    575                 onTrySetupData(reason);
    576                 break;
    577 
    578             case EVENT_ROAMING_OFF:
    579                 if (getDataOnRoamingEnabled() == false) {
    580                     resetAllRetryCounts();
    581                 }
    582                 onRoamingOff();
    583                 break;
    584 
    585             case EVENT_ROAMING_ON:
    586                 onRoamingOn();
    587                 break;
    588 
    589             case EVENT_RADIO_AVAILABLE:
    590                 onRadioAvailable();
    591                 break;
    592 
    593             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
    594                 onRadioOffOrNotAvailable();
    595                 break;
    596 
    597             case EVENT_DATA_SETUP_COMPLETE:
    598                 mCidActive = msg.arg1;
    599                 onDataSetupComplete((AsyncResult) msg.obj);
    600                 break;
    601 
    602             case EVENT_DISCONNECT_DONE:
    603                 log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
    604                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
    605                 break;
    606 
    607             case EVENT_VOICE_CALL_STARTED:
    608                 onVoiceCallStarted();
    609                 break;
    610 
    611             case EVENT_VOICE_CALL_ENDED:
    612                 onVoiceCallEnded();
    613                 break;
    614 
    615             case EVENT_CLEAN_UP_ALL_CONNECTIONS: {
    616                 onCleanUpAllConnections((String) msg.obj);
    617                 break;
    618             }
    619             case EVENT_CLEAN_UP_CONNECTION: {
    620                 boolean tearDown = (msg.arg1 == 0) ? false : true;
    621                 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
    622                 break;
    623             }
    624             case EVENT_SET_INTERNAL_DATA_ENABLE: {
    625                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    626                 onSetInternalDataEnabled(enabled);
    627                 break;
    628             }
    629             case EVENT_RESET_DONE: {
    630                 if (DBG) log("EVENT_RESET_DONE");
    631                 onResetDone((AsyncResult) msg.obj);
    632                 break;
    633             }
    634             case CMD_SET_USER_DATA_ENABLE: {
    635                 final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    636                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
    637                 onSetUserDataEnabled(enabled);
    638                 break;
    639             }
    640             case CMD_SET_DEPENDENCY_MET: {
    641                 boolean met = (msg.arg1 == ENABLED) ? true : false;
    642                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
    643                 Bundle bundle = msg.getData();
    644                 if (bundle != null) {
    645                     String apnType = (String)bundle.get(APN_TYPE_KEY);
    646                     if (apnType != null) {
    647                         onSetDependencyMet(apnType, met);
    648                     }
    649                 }
    650                 break;
    651             }
    652             case CMD_SET_POLICY_DATA_ENABLE: {
    653                 final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    654                 onSetPolicyDataEnabled(enabled);
    655                 break;
    656             }
    657             default:
    658                 Log.e("DATA", "Unidentified event msg=" + msg);
    659                 break;
    660         }
    661     }
    662 
    663     /**
    664      * Report on whether data connectivity is enabled
    665      *
    666      * @return {@code false} if data connectivity has been explicitly disabled,
    667      *         {@code true} otherwise.
    668      */
    669     public boolean getAnyDataEnabled() {
    670         final boolean result;
    671         synchronized (mDataEnabledLock) {
    672             result = (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
    673                     && (enabledCount != 0));
    674         }
    675         if (!result && DBG) log("getAnyDataEnabled " + result);
    676         return result;
    677     }
    678 
    679     protected boolean isEmergency() {
    680         final boolean result;
    681         synchronized (mDataEnabledLock) {
    682             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
    683         }
    684         log("isEmergency: result=" + result);
    685         return result;
    686     }
    687 
    688     protected int apnTypeToId(String type) {
    689         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
    690             return APN_DEFAULT_ID;
    691         } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
    692             return APN_MMS_ID;
    693         } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
    694             return APN_SUPL_ID;
    695         } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
    696             return APN_DUN_ID;
    697         } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
    698             return APN_HIPRI_ID;
    699         } else if (TextUtils.equals(type, Phone.APN_TYPE_IMS)) {
    700             return APN_IMS_ID;
    701         } else if (TextUtils.equals(type, Phone.APN_TYPE_FOTA)) {
    702             return APN_FOTA_ID;
    703         } else if (TextUtils.equals(type, Phone.APN_TYPE_CBS)) {
    704             return APN_CBS_ID;
    705         } else {
    706             return APN_INVALID_ID;
    707         }
    708     }
    709 
    710     protected String apnIdToType(int id) {
    711         switch (id) {
    712         case APN_DEFAULT_ID:
    713             return Phone.APN_TYPE_DEFAULT;
    714         case APN_MMS_ID:
    715             return Phone.APN_TYPE_MMS;
    716         case APN_SUPL_ID:
    717             return Phone.APN_TYPE_SUPL;
    718         case APN_DUN_ID:
    719             return Phone.APN_TYPE_DUN;
    720         case APN_HIPRI_ID:
    721             return Phone.APN_TYPE_HIPRI;
    722         case APN_IMS_ID:
    723             return Phone.APN_TYPE_IMS;
    724         case APN_FOTA_ID:
    725             return Phone.APN_TYPE_FOTA;
    726         case APN_CBS_ID:
    727             return Phone.APN_TYPE_CBS;
    728         default:
    729             log("Unknown id (" + id + ") in apnIdToType");
    730             return Phone.APN_TYPE_DEFAULT;
    731         }
    732     }
    733 
    734     protected LinkProperties getLinkProperties(String apnType) {
    735         int id = apnTypeToId(apnType);
    736 
    737         if (isApnIdEnabled(id)) {
    738             // TODO - remove this cdma-only hack and support multiple DCs.
    739             DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
    740             return dcac.getLinkPropertiesSync();
    741         } else {
    742             return new LinkProperties();
    743         }
    744     }
    745 
    746     protected LinkCapabilities getLinkCapabilities(String apnType) {
    747         int id = apnTypeToId(apnType);
    748         if (isApnIdEnabled(id)) {
    749             // TODO - remove this cdma-only hack and support multiple DCs.
    750             DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
    751             return dcac.getLinkCapabilitiesSync();
    752         } else {
    753             return new LinkCapabilities();
    754         }
    755     }
    756 
    757     // tell all active apns of the current condition
    758     protected void notifyDataConnection(String reason) {
    759         for (int id = 0; id < APN_NUM_TYPES; id++) {
    760             if (dataEnabled[id]) {
    761                 mPhone.notifyDataConnection(reason, apnIdToType(id));
    762             }
    763         }
    764         notifyOffApnsOfAvailability(reason);
    765     }
    766 
    767     // a new APN has gone active and needs to send events to catch up with the
    768     // current condition
    769     private void notifyApnIdUpToCurrent(String reason, int apnId) {
    770         switch (mState) {
    771             case IDLE:
    772             case INITING:
    773                 break;
    774             case CONNECTING:
    775             case SCANNING:
    776                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
    777                 break;
    778             case CONNECTED:
    779             case DISCONNECTING:
    780                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
    781                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED);
    782                 break;
    783         }
    784     }
    785 
    786     // since we normally don't send info to a disconnected APN, we need to do this specially
    787     private void notifyApnIdDisconnected(String reason, int apnId) {
    788         mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED);
    789     }
    790 
    791     // disabled apn's still need avail/unavail notificiations - send them out
    792     protected void notifyOffApnsOfAvailability(String reason) {
    793         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
    794         for (int id = 0; id < APN_NUM_TYPES; id++) {
    795             if (!isApnIdEnabled(id)) {
    796                 notifyApnIdDisconnected(reason, id);
    797             }
    798         }
    799     }
    800 
    801     public boolean isApnTypeEnabled(String apnType) {
    802         if (apnType == null) {
    803             return false;
    804         } else {
    805             return isApnIdEnabled(apnTypeToId(apnType));
    806         }
    807     }
    808 
    809     protected synchronized boolean isApnIdEnabled(int id) {
    810         if (id != APN_INVALID_ID) {
    811             return dataEnabled[id];
    812         }
    813         return false;
    814     }
    815 
    816     /**
    817      * Ensure that we are connected to an APN of the specified type.
    818      *
    819      * @param type the APN type (currently the only valid values are
    820      *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
    821      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
    822      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
    823      *         broadcast will be sent by the ConnectivityManager when a
    824      *         connection to the APN has been established.
    825      */
    826     public synchronized int enableApnType(String type) {
    827         int id = apnTypeToId(type);
    828         if (id == APN_INVALID_ID) {
    829             return Phone.APN_REQUEST_FAILED;
    830         }
    831 
    832         if (DBG) {
    833             log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
    834                     + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
    835         }
    836 
    837         if (!isApnTypeAvailable(type)) {
    838             if (DBG) log("type not available");
    839             return Phone.APN_TYPE_NOT_AVAILABLE;
    840         }
    841 
    842         if (isApnIdEnabled(id)) {
    843             return Phone.APN_ALREADY_ACTIVE;
    844         } else {
    845             setEnabled(id, true);
    846         }
    847         return Phone.APN_REQUEST_STARTED;
    848     }
    849 
    850     /**
    851      * The APN of the specified type is no longer needed. Ensure that if use of
    852      * the default APN has not been explicitly disabled, we are connected to the
    853      * default APN.
    854      *
    855      * @param type the APN type. The only valid values are currently
    856      *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
    857      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
    858      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
    859      *         broadcast will be sent by the ConnectivityManager when a
    860      *         connection to the APN has been disconnected. A {@code
    861      *         Phone.APN_REQUEST_FAILED} is returned if the type parameter is
    862      *         invalid or if the apn wasn't enabled.
    863      */
    864     public synchronized int disableApnType(String type) {
    865         if (DBG) log("disableApnType(" + type + ")");
    866         int id = apnTypeToId(type);
    867         if (id == APN_INVALID_ID) {
    868             return Phone.APN_REQUEST_FAILED;
    869         }
    870         if (isApnIdEnabled(id)) {
    871             setEnabled(id, false);
    872             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
    873                 if (dataEnabled[APN_DEFAULT_ID]) {
    874                     return Phone.APN_ALREADY_ACTIVE;
    875                 } else {
    876                     return Phone.APN_REQUEST_STARTED;
    877                 }
    878             } else {
    879                 return Phone.APN_REQUEST_STARTED;
    880             }
    881         } else {
    882             return Phone.APN_REQUEST_FAILED;
    883         }
    884     }
    885 
    886     protected void setEnabled(int id, boolean enable) {
    887         if (DBG) {
    888             log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id]
    889                     + " and enabledCount = " + enabledCount);
    890         }
    891         Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
    892         msg.arg1 = id;
    893         msg.arg2 = (enable ? ENABLED : DISABLED);
    894         sendMessage(msg);
    895     }
    896 
    897     protected void onEnableApn(int apnId, int enabled) {
    898         if (DBG) {
    899             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
    900                     ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] +
    901                     ", enabledCount = " + enabledCount + ", isApnTypeActive = " +
    902                     isApnTypeActive(apnIdToType(apnId)));
    903         }
    904         if (enabled == ENABLED) {
    905             synchronized (this) {
    906                 if (!dataEnabled[apnId]) {
    907                     dataEnabled[apnId] = true;
    908                     enabledCount++;
    909                 }
    910             }
    911             String type = apnIdToType(apnId);
    912             if (!isApnTypeActive(type)) {
    913                 mRequestedApnType = type;
    914                 onEnableNewApn();
    915             } else {
    916                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
    917             }
    918         } else {
    919             // disable
    920             boolean didDisable = false;
    921             synchronized (this) {
    922                 if (dataEnabled[apnId]) {
    923                     dataEnabled[apnId] = false;
    924                     enabledCount--;
    925                     didDisable = true;
    926                 }
    927             }
    928             if (didDisable && enabledCount == 0) {
    929                 onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
    930 
    931                 // send the disconnect msg manually, since the normal route wont send
    932                 // it (it's not enabled)
    933                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
    934                 if (dataEnabled[APN_DEFAULT_ID] == true
    935                         && !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
    936                     // TODO - this is an ugly way to restore the default conn - should be done
    937                     // by a real contention manager and policy that disconnects the lower pri
    938                     // stuff as enable requests come in and pops them back on as we disable back
    939                     // down to the lower pri stuff
    940                     mRequestedApnType = Phone.APN_TYPE_DEFAULT;
    941                     onEnableNewApn();
    942                 }
    943             }
    944         }
    945     }
    946 
    947     /**
    948      * Called when we switch APNs.
    949      *
    950      * mRequestedApnType is set prior to call
    951      * To be overridden.
    952      */
    953     protected void onEnableNewApn() {
    954     }
    955 
    956     /**
    957      * Called when EVENT_RESET_DONE is received so goto
    958      * IDLE state and send notifications to those interested.
    959      *
    960      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
    961      * TODO - needs to pass some notion of which connection is reset..
    962      */
    963     protected void onResetDone(AsyncResult ar) {
    964         if (DBG) log("EVENT_RESET_DONE");
    965         String reason = null;
    966         if (ar.userObj instanceof String) {
    967             reason = (String) ar.userObj;
    968         }
    969         gotoIdleAndNotifyDataConnection(reason);
    970     }
    971 
    972     /**
    973      * Prevent mobile data connections from being established, or once again
    974      * allow mobile data connections. If the state toggles, then either tear
    975      * down or set up data, as appropriate to match the new state.
    976      *
    977      * @param enable indicates whether to enable ({@code true}) or disable (
    978      *            {@code false}) data
    979      * @return {@code true} if the operation succeeded
    980      */
    981     public boolean setInternalDataEnabled(boolean enable) {
    982         if (DBG)
    983             log("setInternalDataEnabled(" + enable + ")");
    984 
    985         Message msg = obtainMessage(EVENT_SET_INTERNAL_DATA_ENABLE);
    986         msg.arg1 = (enable ? ENABLED : DISABLED);
    987         sendMessage(msg);
    988         return true;
    989     }
    990 
    991     protected void onSetInternalDataEnabled(boolean enabled) {
    992         synchronized (mDataEnabledLock) {
    993             mInternalDataEnabled = enabled;
    994             if (enabled) {
    995                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
    996                 resetAllRetryCounts();
    997                 onTrySetupData(Phone.REASON_DATA_ENABLED);
    998             } else {
    999                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
   1000                 cleanUpAllConnections(null);
   1001             }
   1002         }
   1003     }
   1004 
   1005     public void cleanUpAllConnections(String cause) {
   1006         Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
   1007         msg.obj = cause;
   1008         sendMessage(msg);
   1009     }
   1010 
   1011     public abstract boolean isDisconnected();
   1012 
   1013     protected void onSetUserDataEnabled(boolean enabled) {
   1014         synchronized (mDataEnabledLock) {
   1015             final boolean prevEnabled = getAnyDataEnabled();
   1016             if (mUserDataEnabled != enabled) {
   1017                 mUserDataEnabled = enabled;
   1018                 Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
   1019                         Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
   1020                 if (prevEnabled != getAnyDataEnabled()) {
   1021                     if (!prevEnabled) {
   1022                         resetAllRetryCounts();
   1023                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1024                     } else {
   1025                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1026                     }
   1027                 }
   1028             }
   1029         }
   1030     }
   1031 
   1032     protected void onSetDependencyMet(String apnType, boolean met) {
   1033     }
   1034 
   1035     protected void onSetPolicyDataEnabled(boolean enabled) {
   1036         synchronized (mDataEnabledLock) {
   1037             final boolean prevEnabled = getAnyDataEnabled();
   1038             if (mPolicyDataEnabled != enabled) {
   1039                 mPolicyDataEnabled = enabled;
   1040                 if (prevEnabled != getAnyDataEnabled()) {
   1041                     if (!prevEnabled) {
   1042                         resetAllRetryCounts();
   1043                         onTrySetupData(Phone.REASON_DATA_ENABLED);
   1044                     } else {
   1045                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
   1046                     }
   1047                 }
   1048             }
   1049         }
   1050     }
   1051 
   1052     protected String getReryConfig(boolean forDefault) {
   1053         int rt = mPhone.getServiceState().getRadioTechnology();
   1054 
   1055         if ((rt == ServiceState.RADIO_TECHNOLOGY_IS95A) ||
   1056             (rt == ServiceState.RADIO_TECHNOLOGY_IS95B) ||
   1057             (rt == ServiceState.RADIO_TECHNOLOGY_1xRTT) ||
   1058             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_0) ||
   1059             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_A) ||
   1060             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_B) ||
   1061             (rt == ServiceState.RADIO_TECHNOLOGY_EHRPD)) {
   1062             // CDMA variant
   1063             return SystemProperties.get("ro.cdma.data_retry_config");
   1064         } else {
   1065             // Use GSM varient for all others.
   1066             if (forDefault) {
   1067                 return SystemProperties.get("ro.gsm.data_retry_config");
   1068             } else {
   1069                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
   1070             }
   1071         }
   1072     }
   1073 
   1074     protected void resetAllRetryCounts() {
   1075         for (DataConnection dc : mDataConnections.values()) {
   1076             dc.resetRetryCount();
   1077         }
   1078     }
   1079 }
   1080