• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.INetStatService;
23 import android.os.Message;
24 import android.os.RemoteException;
25 import android.provider.Settings;
26 import android.provider.Settings.SettingNotFoundException;
27 import android.text.TextUtils;
28 import android.util.Log;
29 
30 import java.util.ArrayList;
31 
32 /**
33  * {@hide}
34  *
35  */
36 public abstract class DataConnectionTracker extends Handler {
37     protected static final boolean DBG = true;
38     protected final String LOG_TAG = "DataConnectionTracker";
39 
40     /**
41      * IDLE: ready to start data connection setup, default state
42      * INITING: state of issued setupDefaultPDP() but not finish yet
43      * CONNECTING: state of issued startPppd() but not finish yet
44      * SCANNING: data connection fails with one apn but other apns are available
45      *           ready to start data connection on other apns (before INITING)
46      * CONNECTED: IP connection is setup
47      * DISCONNECTING: Connection.disconnect() has been called, but PDP
48      *                context is not yet deactivated
49      * FAILED: data connection fail for all apns settings
50      *
51      * getDataConnectionState() maps State to DataState
52      *      FAILED or IDLE : DISCONNECTED
53      *      INITING or CONNECTING or SCANNING: CONNECTING
54      *      CONNECTED : CONNECTED or DISCONNECTING
55      */
56     public enum State {
57         IDLE,
58         INITING,
59         CONNECTING,
60         SCANNING,
61         CONNECTED,
62         DISCONNECTING,
63         FAILED
64     }
65 
66     public enum Activity {
67         NONE,
68         DATAIN,
69         DATAOUT,
70         DATAINANDOUT,
71         DORMANT
72     }
73 
74     /***** Event Codes *****/
75     protected static final int EVENT_DATA_SETUP_COMPLETE = 1;
76     protected static final int EVENT_RADIO_AVAILABLE = 3;
77     protected static final int EVENT_RECORDS_LOADED = 4;
78     protected static final int EVENT_TRY_SETUP_DATA = 5;
79     protected static final int EVENT_DATA_STATE_CHANGED = 6;
80     protected static final int EVENT_POLL_PDP = 7;
81     protected static final int EVENT_GET_PDP_LIST_COMPLETE = 11;
82     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 12;
83     protected static final int EVENT_VOICE_CALL_STARTED = 14;
84     protected static final int EVENT_VOICE_CALL_ENDED = 15;
85     protected static final int EVENT_GPRS_DETACHED = 19;
86     protected static final int EVENT_LINK_STATE_CHANGED = 20;
87     protected static final int EVENT_ROAMING_ON = 21;
88     protected static final int EVENT_ROAMING_OFF = 22;
89     protected static final int EVENT_ENABLE_NEW_APN = 23;
90     protected static final int EVENT_RESTORE_DEFAULT_APN = 24;
91     protected static final int EVENT_DISCONNECT_DONE = 25;
92     protected static final int EVENT_GPRS_ATTACHED = 26;
93     protected static final int EVENT_START_NETSTAT_POLL = 27;
94     protected static final int EVENT_START_RECOVERY = 28;
95     protected static final int EVENT_APN_CHANGED = 29;
96     protected static final int EVENT_CDMA_DATA_DETACHED = 30;
97     protected static final int EVENT_NV_READY = 31;
98     protected static final int EVENT_PS_RESTRICT_ENABLED = 32;
99     protected static final int EVENT_PS_RESTRICT_DISABLED = 33;
100     public static final int EVENT_CLEAN_UP_CONNECTION = 34;
101     protected static final int EVENT_CDMA_OTA_PROVISION = 35;
102     protected static final int EVENT_RESTART_RADIO = 36;
103     protected static final int EVENT_SET_MASTER_DATA_ENABLE = 37;
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 INetStatService netstat;
175     protected long txPkts, rxPkts, sentSinceLastRecv;
176     protected int netStatPollPeriod;
177     protected int mNoRecvPollCount = 0;
178     protected boolean netStatPollEnabled = false;
179 
180     /** Manage the behavior of data retry after failure */
181     protected RetryManager mRetryMgr = new RetryManager();
182 
183     // wifi connection status will be updated by sticky intent
184     protected boolean mIsWifiConnected = false;
185 
186     /** Intent sent when the reconnect alarm fires. */
187     protected PendingIntent mReconnectIntent = null;
188 
189     /** CID of active data connection */
190     protected int cidActive;
191 
192    /**
193      * Default constructor
194      */
DataConnectionTracker(PhoneBase phone)195     protected DataConnectionTracker(PhoneBase phone) {
196         super();
197         this.phone = phone;
198     }
199 
dispose()200     public abstract void dispose();
201 
getActivity()202     public Activity getActivity() {
203         return activity;
204     }
205 
getState()206     public State getState() {
207         return state;
208     }
209 
getStateInString()210     public String getStateInString() {
211         switch (state) {
212             case IDLE:          return "IDLE";
213             case INITING:       return "INIT";
214             case CONNECTING:    return "CING";
215             case SCANNING:      return "SCAN";
216             case CONNECTED:     return "CNTD";
217             case DISCONNECTING: return "DING";
218             case FAILED:        return "FAIL";
219             default:            return "ERRO";
220         }
221     }
222 
223     /**
224      * The data connection is expected to be setup while device
225      *  1. has Icc card
226      *  2. registered for data service
227      *  3. user doesn't explicitly disable data service
228      *  4. wifi is not on
229      *
230      * @return false while no data connection if all above requirements are met.
231      */
isDataConnectionAsDesired()232     public abstract boolean isDataConnectionAsDesired();
233 
234     //The data roaming setting is now located in the shared preferences.
235     //  See if the requested preference value is the same as that stored in
236     //  the shared values.  If it is not, then update it.
setDataOnRoamingEnabled(boolean enabled)237     public void setDataOnRoamingEnabled(boolean enabled) {
238         if (getDataOnRoamingEnabled() != enabled) {
239             Settings.Secure.putInt(phone.getContext().getContentResolver(),
240                 Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
241             if (phone.getServiceState().getRoaming()) {
242                 if (enabled) {
243                     mRetryMgr.resetRetryCount();
244                 }
245                 sendMessage(obtainMessage(EVENT_ROAMING_ON));
246             }
247         }
248     }
249 
250     //Retrieve the data roaming setting from the shared preferences.
getDataOnRoamingEnabled()251     public boolean getDataOnRoamingEnabled() {
252         try {
253             return Settings.Secure.getInt(phone.getContext().getContentResolver(),
254                 Settings.Secure.DATA_ROAMING) > 0;
255         } catch (SettingNotFoundException snfe) {
256             return false;
257         }
258     }
259 
260     // abstract handler methods
onTrySetupData(String reason)261     protected abstract boolean onTrySetupData(String reason);
onRoamingOff()262     protected abstract void onRoamingOff();
onRoamingOn()263     protected abstract void onRoamingOn();
onRadioAvailable()264     protected abstract void onRadioAvailable();
onRadioOffOrNotAvailable()265     protected abstract void onRadioOffOrNotAvailable();
onDataSetupComplete(AsyncResult ar)266     protected abstract void onDataSetupComplete(AsyncResult ar);
onDisconnectDone(AsyncResult ar)267     protected abstract void onDisconnectDone(AsyncResult ar);
onVoiceCallStarted()268     protected abstract void onVoiceCallStarted();
onVoiceCallEnded()269     protected abstract void onVoiceCallEnded();
onCleanUpConnection(boolean tearDown, String reason)270     protected abstract void onCleanUpConnection(boolean tearDown, String reason);
271 
272     @Override
handleMessage(Message msg)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             default:
335                 Log.e("DATA", "Unidentified event = " + msg.what);
336                 break;
337         }
338     }
339 
340     /**
341      * Report the current state of data connectivity (enabled or disabled)
342      * @return {@code false} if data connectivity has been explicitly disabled,
343      * {@code true} otherwise.
344      */
getDataEnabled()345     public synchronized boolean getDataEnabled() {
346         return dataEnabled[APN_DEFAULT_ID];
347     }
348 
349     /**
350      * Report on whether data connectivity is enabled
351      * @return {@code false} if data connectivity has been explicitly disabled,
352      * {@code true} otherwise.
353      */
getAnyDataEnabled()354     public boolean getAnyDataEnabled() {
355         return (enabledCount != 0);
356     }
357 
startNetStatPoll()358     protected abstract void startNetStatPoll();
359 
stopNetStatPoll()360     protected abstract void stopNetStatPoll();
361 
restartRadio()362     protected abstract void restartRadio();
363 
log(String s)364     protected abstract void log(String s);
365 
apnTypeToId(String type)366     protected int apnTypeToId(String type) {
367         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
368             return APN_DEFAULT_ID;
369         } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
370             return APN_MMS_ID;
371         } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
372             return APN_SUPL_ID;
373         } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
374             return APN_DUN_ID;
375         } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
376             return APN_HIPRI_ID;
377         } else {
378             return APN_INVALID_ID;
379         }
380     }
381 
apnIdToType(int id)382     protected String apnIdToType(int id) {
383         switch (id) {
384         case APN_DEFAULT_ID:
385             return Phone.APN_TYPE_DEFAULT;
386         case APN_MMS_ID:
387             return Phone.APN_TYPE_MMS;
388         case APN_SUPL_ID:
389             return Phone.APN_TYPE_SUPL;
390         case APN_DUN_ID:
391             return Phone.APN_TYPE_DUN;
392         case APN_HIPRI_ID:
393             return Phone.APN_TYPE_HIPRI;
394         default:
395             Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType");
396             return Phone.APN_TYPE_DEFAULT;
397         }
398     }
399 
isApnTypeActive(String type)400     protected abstract boolean isApnTypeActive(String type);
401 
isApnTypeAvailable(String type)402     protected abstract boolean isApnTypeAvailable(String type);
403 
getActiveApnTypes()404     protected abstract String[] getActiveApnTypes();
405 
getActiveApnString()406     protected abstract String getActiveApnString();
407 
getAllDataConnections()408     public abstract ArrayList<DataConnection> getAllDataConnections();
409 
getInterfaceName(String apnType)410     protected abstract String getInterfaceName(String apnType);
411 
getIpAddress(String apnType)412     protected abstract String getIpAddress(String apnType);
413 
getGateway(String apnType)414     protected abstract String getGateway(String apnType);
415 
getDnsServers(String apnType)416     protected abstract String[] getDnsServers(String apnType);
417 
setState(State s)418     protected abstract void setState(State s);
419 
isEnabled(int id)420     protected synchronized boolean isEnabled(int id) {
421         if (id != APN_INVALID_ID) {
422             return dataEnabled[id];
423         }
424         return false;
425     }
426 
427     /**
428      * Ensure that we are connected to an APN of the specified type.
429      * @param type the APN type (currently the only valid values
430      * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
431      * @return the result of the operation. Success is indicated by
432      * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
433      * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
434      * will be sent by the ConnectivityManager when a connection to
435      * the APN has been established.
436      */
enableApnType(String type)437     public synchronized int enableApnType(String type) {
438         int id = apnTypeToId(type);
439         if (id == APN_INVALID_ID) {
440             return Phone.APN_REQUEST_FAILED;
441         }
442 
443         if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
444                 + isApnTypeActive(type) + " and state = " + state);
445 
446         if (!isApnTypeAvailable(type)) {
447             return Phone.APN_TYPE_NOT_AVAILABLE;
448         }
449 
450         // just because it's active doesn't mean we had it explicitly requested before
451         // (a broad default may handle many types).  make sure we mark it enabled
452         // so if the default is disabled we keep the connection for others
453         setEnabled(id, true);
454 
455         if (isApnTypeActive(type)) {
456             if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
457             else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
458         }
459         return Phone.APN_REQUEST_STARTED;
460     }
461 
462     /**
463      * The APN of the specified type is no longer needed. Ensure that if
464      * use of the default APN has not been explicitly disabled, we are connected
465      * to the default APN.
466      * @param type the APN type. The only valid values are currently
467      * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
468      * @return
469      */
disableApnType(String type)470     public synchronized int disableApnType(String type) {
471         if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
472         int id = apnTypeToId(type);
473         if (id == APN_INVALID_ID) {
474             return Phone.APN_REQUEST_FAILED;
475         }
476         if (isEnabled(id)) {
477             setEnabled(id, false);
478             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
479                 if (dataEnabled[APN_DEFAULT_ID]) {
480                     return Phone.APN_ALREADY_ACTIVE;
481                 } else {
482                     return Phone.APN_REQUEST_STARTED;
483                 }
484             } else {
485                 return Phone.APN_REQUEST_STARTED;
486             }
487         } else {
488             return Phone.APN_REQUEST_FAILED;
489         }
490     }
491 
setEnabled(int id, boolean enable)492     private void setEnabled(int id, boolean enable) {
493         if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " +
494                 dataEnabled[id] + " and enabledCount = " + enabledCount);
495 
496         Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
497         msg.arg1 = id;
498         msg.arg2 = (enable ? ENABLED : DISABLED);
499         sendMessage(msg);
500     }
501 
onEnableApn(int apnId, int enabled)502     protected synchronized void onEnableApn(int apnId, int enabled) {
503         if (DBG) {
504             Log.d(LOG_TAG, "EVENT_APN_ENABLE_REQUEST " + apnId + ", " + enabled);
505             Log.d(LOG_TAG, " dataEnabled = " + dataEnabled[apnId] +
506                     ", enabledCount = " + enabledCount +
507                     ", isApnTypeActive = " + isApnTypeActive(apnIdToType(apnId)));
508         }
509         if (enabled == ENABLED) {
510             if (!dataEnabled[apnId]) {
511                 dataEnabled[apnId] = true;
512                 enabledCount++;
513             }
514             String type = apnIdToType(apnId);
515             if (!isApnTypeActive(type)) {
516                 mRequestedApnType = type;
517                 onEnableNewApn();
518             }
519         } else {
520             // disable
521             if (dataEnabled[apnId]) {
522                 dataEnabled[apnId] = false;
523                 enabledCount--;
524                 if (enabledCount == 0) {
525                     onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
526                 } else if (dataEnabled[APN_DEFAULT_ID] == true &&
527                         !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
528                     mRequestedApnType = Phone.APN_TYPE_DEFAULT;
529                     onEnableNewApn();
530                 }
531             }
532         }
533     }
534 
535     /**
536      * Called when we switch APNs.
537      *
538      * mRequestedApnType is set prior to call
539      * To be overridden.
540      */
onEnableNewApn()541     protected void onEnableNewApn() {
542     }
543 
544     /**
545      * Prevent mobile data connections from being established,
546      * or once again allow mobile data connections. If the state
547      * toggles, then either tear down or set up data, as
548      * appropriate to match the new state.
549      * <p>This operation only affects the default APN, and if the same APN is
550      * currently being used for MMS traffic, the teardown will not happen
551      * even when {@code enable} is {@code false}.</p>
552      * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
553      * @return {@code true} if the operation succeeded
554      */
setDataEnabled(boolean enable)555     public boolean setDataEnabled(boolean enable) {
556         if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")");
557 
558         Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE);
559         msg.arg1 = (enable ? ENABLED : DISABLED);
560         sendMessage(msg);
561         return true;
562     }
563 
onSetDataEnabled(boolean enable)564     protected void onSetDataEnabled(boolean enable) {
565         if (mMasterDataEnabled != enable) {
566             mMasterDataEnabled = enable;
567             if (enable) {
568                 mRetryMgr.resetRetryCount();
569                 onTrySetupData(Phone.REASON_DATA_ENABLED);
570             } else {
571                 onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);
572            }
573         }
574     }
575 
576 
577 }
578