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.os.AsyncResult;
     21 import android.os.Handler;
     22 import android.os.Message;
     23 import android.os.RemoteException;
     24 import android.provider.Settings;
     25 import android.provider.Settings.SettingNotFoundException;
     26 import android.text.TextUtils;
     27 import android.util.Log;
     28 
     29 import java.util.ArrayList;
     30 
     31 /**
     32  * {@hide}
     33  *
     34  */
     35 public abstract class DataConnectionTracker extends Handler {
     36     protected static final boolean DBG = false;
     37     protected final String LOG_TAG = "DataConnectionTracker";
     38 
     39     /**
     40      * IDLE: ready to start data connection setup, default state
     41      * INITING: state of issued setupDefaultPDP() but not finish yet
     42      * CONNECTING: state of issued startPppd() but not finish yet
     43      * SCANNING: data connection fails with one apn but other apns are available
     44      *           ready to start data connection on other apns (before INITING)
     45      * CONNECTED: IP connection is setup
     46      * DISCONNECTING: Connection.disconnect() has been called, but PDP
     47      *                context is not yet deactivated
     48      * FAILED: data connection fail for all apns settings
     49      *
     50      * getDataConnectionState() maps State to DataState
     51      *      FAILED or IDLE : DISCONNECTED
     52      *      INITING or CONNECTING or SCANNING: CONNECTING
     53      *      CONNECTED : CONNECTED or DISCONNECTING
     54      */
     55     public enum State {
     56         IDLE,
     57         INITING,
     58         CONNECTING,
     59         SCANNING,
     60         CONNECTED,
     61         DISCONNECTING,
     62         FAILED
     63     }
     64 
     65     public enum Activity {
     66         NONE,
     67         DATAIN,
     68         DATAOUT,
     69         DATAINANDOUT,
     70         DORMANT
     71     }
     72 
     73     /***** Event Codes *****/
     74     protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
     75     protected static final int EVENT_RADIO_AVAILABLE = 3;
     76     protected static final int EVENT_RECORDS_LOADED = 4;
     77     protected static final int EVENT_TRY_SETUP_DATA = 5;
     78     protected static final int EVENT_DATA_STATE_CHANGED = 6;
     79     protected static final int EVENT_POLL_PDP = 7;
     80     protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11;
     81     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
     82     protected static final int EVENT_VOICE_CALL_STARTED = 14;
     83     protected static final int EVENT_VOICE_CALL_ENDED = 15;
     84     protected static final int EVENT_GPRS_DETACHED = 19;
     85     protected static final int EVENT_LINK_STATE_CHANGED = 20;
     86     protected static final int EVENT_ROAMING_ON = 21;
     87     protected static final int EVENT_ROAMING_OFF = 22;
     88     protected static final int EVENT_ENABLE_NEW_APN = 23;
     89     protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
     90     protected static final int EVENT_DISCONNECT_DONE = 25;
     91     protected static final int EVENT_GPRS_ATTACHED = 26;
     92     protected static final int EVENT_START_NETSTAT_POLL = 27;
     93     protected static final int EVENT_START_RECOVERY = 28;
     94     protected static final int EVENT_APN_CHANGED = 29;
     95     protected static final int EVENT_CDMA_DATA_DETACHED = 30;
     96     protected static final int EVENT_NV_READY = 31;
     97     protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
     98     protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
     99     public static final int EVENT_CLEAN_UP_CONNECTION = 34;
    100     protected static final int EVENT_CDMA_OTA_PROVISION = 35;
    101     protected static final int EVENT_RESTART_RADIO = 36;
    102     protected static final int EVENT_SET_MASTER_DATA_ENABLE = 37;
    103     protected static final int EVENT_RESET_DONE = 38;
    104 
    105     /***** Constants *****/
    106 
    107     protected static final int APN_INVALID_ID = -1;
    108     protected static final int APN_DEFAULT_ID = 0;
    109     protected static final int APN_MMS_ID = 1;
    110     protected static final int APN_SUPL_ID = 2;
    111     protected static final int APN_DUN_ID = 3;
    112     protected static final int APN_HIPRI_ID = 4;
    113     protected static final int APN_NUM_TYPES = 5;
    114 
    115     protected static final int DISABLED = 0;
    116     protected static final int ENABLED = 1;
    117 
    118     // responds to the setDataEnabled call - used independently from the APN requests
    119     protected boolean mMasterDataEnabled = true;
    120 
    121     protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
    122     protected int enabledCount = 0;
    123 
    124     /* Currently requested APN type */
    125     protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
    126 
    127     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
    128     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
    129         + "5000,10000,20000,40000,80000:5000,160000:5000,"
    130         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
    131 
    132     /** Retry configuration for secondary networks: 4 tries in 20 sec */
    133     protected static final String SECONDARY_DATA_RETRY_CONFIG =
    134             "max_retries=3, 5000, 5000, 5000";
    135 
    136     /** Slow poll when attempting connection recovery. */
    137     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
    138     /** Default ping deadline, in seconds. */
    139     protected static final int DEFAULT_PING_DEADLINE = 5;
    140     /** Default max failure count before attempting to network re-registration. */
    141     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
    142 
    143     /**
    144      * After detecting a potential connection problem, this is the max number
    145      * of subsequent polls before attempting a radio reset.  At this point,
    146      * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
    147      * poll for about 2 more minutes.
    148      */
    149     protected static final int NO_RECV_POLL_LIMIT = 24;
    150 
    151     // 1 sec. default polling interval when screen is on.
    152     protected static final int POLL_NETSTAT_MILLIS = 1000;
    153     // 10 min. default polling interval when screen is off.
    154     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
    155     // 2 min for round trip time
    156     protected static final int POLL_LONGEST_RTT = 120 * 1000;
    157     // 10 for packets without ack
    158     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
    159     // how long to wait before switching back to default APN
    160     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
    161     // system property that can override the above value
    162     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
    163     // represents an invalid IP address
    164     protected static final String NULL_IP = "0.0.0.0";
    165 
    166 
    167     // member variables
    168     protected PhoneBase phone;
    169     protected Activity activity = Activity.NONE;
    170     protected State state = State.IDLE;
    171     protected Handler mDataConnectionTracker = null;
    172 
    173 
    174     protected long txPkts, rxPkts, sentSinceLastRecv;
    175     protected int netStatPollPeriod;
    176     protected int mNoRecvPollCount = 0;
    177     protected boolean netStatPollEnabled = false;
    178 
    179     /** Manage the behavior of data retry after failure */
    180     protected RetryManager mRetryMgr = new RetryManager();
    181 
    182     // wifi connection status will be updated by sticky intent
    183     protected boolean mIsWifiConnected = false;
    184 
    185     /** Intent sent when the reconnect alarm fires. */
    186     protected PendingIntent mReconnectIntent = null;
    187 
    188     /** CID of active data connection */
    189     protected int cidActive;
    190 
    191    /**
    192      * Default constructor
    193      */
    194     protected DataConnectionTracker(PhoneBase phone) {
    195         super();
    196         this.phone = phone;
    197     }
    198 
    199     public abstract void dispose();
    200 
    201     public Activity getActivity() {
    202         return activity;
    203     }
    204 
    205     public State getState() {
    206         return state;
    207     }
    208 
    209     public String getStateInString() {
    210         switch (state) {
    211             case IDLE:          return "IDLE";
    212             case INITING:       return "INIT";
    213             case CONNECTING:    return "CING";
    214             case SCANNING:      return "SCAN";
    215             case CONNECTED:     return "CNTD";
    216             case DISCONNECTING: return "DING";
    217             case FAILED:        return "FAIL";
    218             default:            return "ERRO";
    219         }
    220     }
    221 
    222     /**
    223      * The data connection is expected to be setup while device
    224      *  1. has Icc card
    225      *  2. registered for data service
    226      *  3. user doesn't explicitly disable data service
    227      *  4. wifi is not on
    228      *
    229      * @return false while no data connection if all above requirements are met.
    230      */
    231     public abstract boolean isDataConnectionAsDesired();
    232 
    233     //The data roaming setting is now located in the shared preferences.
    234     //  See if the requested preference value is the same as that stored in
    235     //  the shared values.  If it is not, then update it.
    236     public void setDataOnRoamingEnabled(boolean enabled) {
    237         if (getDataOnRoamingEnabled() != enabled) {
    238             Settings.Secure.putInt(phone.getContext().getContentResolver(),
    239                 Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
    240             if (phone.getServiceState().getRoaming()) {
    241                 if (enabled) {
    242                     mRetryMgr.resetRetryCount();
    243                 }
    244                 sendMessage(obtainMessage(EVENT_ROAMING_ON));
    245             }
    246         }
    247     }
    248 
    249     //Retrieve the data roaming setting from the shared preferences.
    250     public boolean getDataOnRoamingEnabled() {
    251         try {
    252             return Settings.Secure.getInt(phone.getContext().getContentResolver(),
    253                 Settings.Secure.DATA_ROAMING) > 0;
    254         } catch (SettingNotFoundException snfe) {
    255             return false;
    256         }
    257     }
    258 
    259     // abstract handler methods
    260     protected abstract boolean onTrySetupData(String reason);
    261     protected abstract void onRoamingOff();
    262     protected abstract void onRoamingOn();
    263     protected abstract void onRadioAvailable();
    264     protected abstract void onRadioOffOrNotAvailable();
    265     protected abstract void onDataSetupComplete(AsyncResult ar);
    266     protected abstract void onDisconnectDone(AsyncResult ar);
    267     protected abstract void onResetDone(AsyncResult ar);
    268     protected abstract void onVoiceCallStarted();
    269     protected abstract void onVoiceCallEnded();
    270     protected abstract void onCleanUpConnection(boolean tearDown, String reason);
    271 
    272     @Override
    273     public void handleMessage (Message msg) {
    274         switch (msg.what) {
    275 
    276             case EVENT_ENABLE_NEW_APN:
    277                 onEnableApn(msg.arg1, msg.arg2);
    278                 break;
    279 
    280             case EVENT_TRY_SETUP_DATA:
    281                 String reason = null;
    282                 if (msg.obj instanceof String) {
    283                     reason = (String)msg.obj;
    284                 }
    285                 onTrySetupData(reason);
    286                 break;
    287 
    288             case EVENT_ROAMING_OFF:
    289                 if (getDataOnRoamingEnabled() == false) {
    290                     mRetryMgr.resetRetryCount();
    291                 }
    292                 onRoamingOff();
    293                 break;
    294 
    295             case EVENT_ROAMING_ON:
    296                 onRoamingOn();
    297                 break;
    298 
    299             case EVENT_RADIO_AVAILABLE:
    300                 onRadioAvailable();
    301                 break;
    302 
    303             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
    304                 onRadioOffOrNotAvailable();
    305                 break;
    306 
    307             case EVENT_DATA_SETUP_COMPLETE:
    308                 cidActive = msg.arg1;
    309                 onDataSetupComplete((AsyncResult) msg.obj);
    310                 break;
    311 
    312             case EVENT_DISCONNECT_DONE:
    313                 onDisconnectDone((AsyncResult) msg.obj);
    314                 break;
    315 
    316             case EVENT_VOICE_CALL_STARTED:
    317                 onVoiceCallStarted();
    318                 break;
    319 
    320             case EVENT_VOICE_CALL_ENDED:
    321                 onVoiceCallEnded();
    322                 break;
    323 
    324             case EVENT_CLEAN_UP_CONNECTION:
    325                 boolean tearDown = (msg.arg1 == 0) ? false : true;
    326                 onCleanUpConnection(tearDown, (String)msg.obj);
    327                 break;
    328 
    329             case EVENT_SET_MASTER_DATA_ENABLE:
    330                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
    331                 onSetDataEnabled(enabled);
    332                 break;
    333 
    334             case EVENT_RESET_DONE:
    335                 onResetDone((AsyncResult) msg.obj);
    336                 break;
    337 
    338             default:
    339                 Log.e("DATA", "Unidentified event = " + msg.what);
    340                 break;
    341         }
    342     }
    343 
    344     /**
    345      * Report the current state of data connectivity (enabled or disabled)
    346      * @return {@code false} if data connectivity has been explicitly disabled,
    347      * {@code true} otherwise.
    348      */
    349     public synchronized boolean getDataEnabled() {
    350         return dataEnabled[APN_DEFAULT_ID];
    351     }
    352 
    353     /**
    354      * Report on whether data connectivity is enabled
    355      * @return {@code false} if data connectivity has been explicitly disabled,
    356      * {@code true} otherwise.
    357      */
    358     public boolean getAnyDataEnabled() {
    359         return (enabledCount != 0);
    360     }
    361 
    362     protected abstract void startNetStatPoll();
    363 
    364     protected abstract void stopNetStatPoll();
    365 
    366     protected abstract void restartRadio();
    367 
    368     protected abstract void log(String s);
    369 
    370     protected int apnTypeToId(String type) {
    371         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
    372             return APN_DEFAULT_ID;
    373         } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
    374             return APN_MMS_ID;
    375         } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
    376             return APN_SUPL_ID;
    377         } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
    378             return APN_DUN_ID;
    379         } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
    380             return APN_HIPRI_ID;
    381         } else {
    382             return APN_INVALID_ID;
    383         }
    384     }
    385 
    386     protected String apnIdToType(int id) {
    387         switch (id) {
    388         case APN_DEFAULT_ID:
    389             return Phone.APN_TYPE_DEFAULT;
    390         case APN_MMS_ID:
    391             return Phone.APN_TYPE_MMS;
    392         case APN_SUPL_ID:
    393             return Phone.APN_TYPE_SUPL;
    394         case APN_DUN_ID:
    395             return Phone.APN_TYPE_DUN;
    396         case APN_HIPRI_ID:
    397             return Phone.APN_TYPE_HIPRI;
    398         default:
    399             Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType");
    400             return Phone.APN_TYPE_DEFAULT;
    401         }
    402     }
    403 
    404     protected abstract boolean isApnTypeActive(String type);
    405 
    406     protected abstract boolean isApnTypeAvailable(String type);
    407 
    408     protected abstract String[] getActiveApnTypes();
    409 
    410     protected abstract String getActiveApnString();
    411 
    412     public abstract ArrayList<DataConnection> getAllDataConnections();
    413 
    414     protected abstract String getInterfaceName(String apnType);
    415 
    416     protected abstract String getIpAddress(String apnType);
    417 
    418     protected abstract String getGateway(String apnType);
    419 
    420     protected abstract String[] getDnsServers(String apnType);
    421 
    422     protected abstract void setState(State s);
    423 
    424     protected synchronized boolean isEnabled(int id) {
    425         if (id != APN_INVALID_ID) {
    426             return dataEnabled[id];
    427         }
    428         return false;
    429     }
    430 
    431     /**
    432      * Ensure that we are connected to an APN of the specified type.
    433      * @param type the APN type (currently the only valid values
    434      * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
    435      * @return the result of the operation. Success is indicated by
    436      * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
    437      * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
    438      * will be sent by the ConnectivityManager when a connection to
    439      * the APN has been established.
    440      */
    441     public synchronized int enableApnType(String type) {
    442         int id = apnTypeToId(type);
    443         if (id == APN_INVALID_ID) {
    444             return Phone.APN_REQUEST_FAILED;
    445         }
    446 
    447         if (DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
    448                 + isApnTypeActive(type) + " and state = " + state);
    449 
    450         if (!isApnTypeAvailable(type)) {
    451             if (DBG) Log.d(LOG_TAG, "type not available");
    452             return Phone.APN_TYPE_NOT_AVAILABLE;
    453         }
    454 
    455         // just because it's active doesn't mean we had it explicitly requested before
    456         // (a broad default may handle many types).  make sure we mark it enabled
    457         // so if the default is disabled we keep the connection for others
    458         setEnabled(id, true);
    459 
    460         if (isApnTypeActive(type)) {
    461             if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
    462             else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
    463         }
    464         return Phone.APN_REQUEST_STARTED;
    465     }
    466 
    467     /**
    468      * The APN of the specified type is no longer needed. Ensure that if
    469      * use of the default APN has not been explicitly disabled, we are connected
    470      * to the default APN.
    471      * @param type the APN type. The only valid values are currently
    472      * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
    473      * @return
    474      */
    475     public synchronized int disableApnType(String type) {
    476         if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
    477         int id = apnTypeToId(type);
    478         if (id == APN_INVALID_ID) {
    479             return Phone.APN_REQUEST_FAILED;
    480         }
    481         if (isEnabled(id)) {
    482             setEnabled(id, false);
    483             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
    484                 if (dataEnabled[APN_DEFAULT_ID]) {
    485                     return Phone.APN_ALREADY_ACTIVE;
    486                 } else {
    487                     return Phone.APN_REQUEST_STARTED;
    488                 }
    489             } else {
    490                 return Phone.APN_REQUEST_STARTED;
    491             }
    492         } else {
    493             return Phone.APN_REQUEST_FAILED;
    494         }
    495     }
    496 
    497     private void setEnabled(int id, boolean enable) {
    498         if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " +
    499                 dataEnabled[id] + " and enabledCount = " + enabledCount);
    500 
    501         Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
    502         msg.arg1 = id;
    503         msg.arg2 = (enable ? ENABLED : DISABLED);
    504         sendMessage(msg);
    505     }
    506 
    507     protected synchronized void onEnableApn(int apnId, int enabled) {
    508         if (DBG) {
    509             Log.d(LOG_TAG, "EVENT_APN_ENABLE_REQUEST " + apnId + ", " + enabled);
    510             Log.d(LOG_TAG, " dataEnabled = " + dataEnabled[apnId] +
    511                     ", enabledCount = " + enabledCount +
    512                     ", isApnTypeActive = " + isApnTypeActive(apnIdToType(apnId)));
    513         }
    514         if (enabled == ENABLED) {
    515             if (!dataEnabled[apnId]) {
    516                 dataEnabled[apnId] = true;
    517                 enabledCount++;
    518             }
    519             String type = apnIdToType(apnId);
    520             if (!isApnTypeActive(type)) {
    521                 mRequestedApnType = type;
    522                 onEnableNewApn();
    523             }
    524         } else {
    525             // disable
    526             if (dataEnabled[apnId]) {
    527                 dataEnabled[apnId] = false;
    528                 enabledCount--;
    529                 if (enabledCount == 0) {
    530                     onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
    531                 } else if (dataEnabled[APN_DEFAULT_ID] == true &&
    532                         !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
    533                     mRequestedApnType = Phone.APN_TYPE_DEFAULT;
    534                     onEnableNewApn();
    535                 }
    536             }
    537         }
    538     }
    539 
    540     /**
    541      * Called when we switch APNs.
    542      *
    543      * mRequestedApnType is set prior to call
    544      * To be overridden.
    545      */
    546     protected void onEnableNewApn() {
    547     }
    548 
    549     /**
    550      * Prevent mobile data connections from being established,
    551      * or once again allow mobile data connections. If the state
    552      * toggles, then either tear down or set up data, as
    553      * appropriate to match the new state.
    554      * <p>This operation only affects the default APN, and if the same APN is
    555      * currently being used for MMS traffic, the teardown will not happen
    556      * even when {@code enable} is {@code false}.</p>
    557      * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
    558      * @return {@code true} if the operation succeeded
    559      */
    560     public boolean setDataEnabled(boolean enable) {
    561         if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")");
    562 
    563         Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE);
    564         msg.arg1 = (enable ? ENABLED : DISABLED);
    565         sendMessage(msg);
    566         return true;
    567     }
    568 
    569     protected void onSetDataEnabled(boolean enable) {
    570         if (mMasterDataEnabled != enable) {
    571             mMasterDataEnabled = enable;
    572             if (enable) {
    573                 mRetryMgr.resetRetryCount();
    574                 onTrySetupData(Phone.REASON_DATA_ENABLED);
    575             } else {
    576                 onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
    577            }
    578         }
    579     }
    580 
    581 
    582 }
    583