2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony;
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;
29 import java.util.ArrayList;
35 public abstract class DataConnectionTracker extends Handler {
36 protected static final boolean DBG = false;
37 protected final String LOG_TAG = "DataConnectionTracker";
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
50 * getDataConnectionState() maps State to DataState
51 * FAILED or IDLE : DISCONNECTED
52 * INITING or CONNECTING or SCANNING: CONNECTING
53 * CONNECTED : CONNECTED or DISCONNECTING
65 public enum Activity {
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;
105 /***** Constants *****/
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;
115 protected static final int DISABLED = 0;
116 protected static final int ENABLED = 1;
118 // responds to the setDataEnabled call - used independently from the APN requests
119 protected boolean mMasterDataEnabled = true;
121 protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
122 protected int enabledCount = 0;
124 /* Currently requested APN type */
125 protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
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";
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";
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;
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.
149 protected static final int NO_RECV_POLL_LIMIT = 24;
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";
168 protected PhoneBase phone;
169 protected Activity activity = Activity.NONE;
170 protected State state = State.IDLE;
171 protected Handler mDataConnectionTracker = null;
174 protected long txPkts, rxPkts, sentSinceLastRecv;
175 protected int netStatPollPeriod;
176 protected int mNoRecvPollCount = 0;
177 protected boolean netStatPollEnabled = false;
179 /** Manage the behavior of data retry after failure */
180 protected RetryManager mRetryMgr = new RetryManager();
182 // wifi connection status will be updated by sticky intent
183 protected boolean mIsWifiConnected = false;
185 /** Intent sent when the reconnect alarm fires. */
186 protected PendingIntent mReconnectIntent = null;
188 /** CID of active data connection */
189 protected int cidActive;
192 * Default constructor
194 protected DataConnectionTracker(PhoneBase phone) {
199 public abstract void dispose();
201 public Activity getActivity() {
205 public State getState() {
209 public String getStateInString() {
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";
223 * The data connection is expected to be setup while device
225 * 2. registered for data service
226 * 3. user doesn't explicitly disable data service
229 * @return false while no data connection if all above requirements are met.
231 public abstract boolean isDataConnectionAsDesired();
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()) {
242 mRetryMgr.resetRetryCount();
244 sendMessage(obtainMessage(EVENT_ROAMING_ON));
249 //Retrieve the data roaming setting from the shared preferences.
250 public boolean getDataOnRoamingEnabled() {
252 return Settings.Secure.getInt(phone.getContext().getContentResolver(),
253 Settings.Secure.DATA_ROAMING) > 0;
254 } catch (SettingNotFoundException snfe) {
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);
273 public void handleMessage (Message msg) {
276 case EVENT_ENABLE_NEW_APN:
277 onEnableApn(msg.arg1, msg.arg2);
280 case EVENT_TRY_SETUP_DATA:
281 String reason = null;
282 if (msg.obj instanceof String) {
283 reason = (String)msg.obj;
285 onTrySetupData(reason);
288 case EVENT_ROAMING_OFF:
289 if (getDataOnRoamingEnabled() == false) {
290 mRetryMgr.resetRetryCount();
295 case EVENT_ROAMING_ON:
299 case EVENT_RADIO_AVAILABLE:
303 case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
304 onRadioOffOrNotAvailable();
307 case EVENT_DATA_SETUP_COMPLETE:
308 cidActive = msg.arg1;
309 onDataSetupComplete((AsyncResult) msg.obj);
312 case EVENT_DISCONNECT_DONE:
313 onDisconnectDone((AsyncResult) msg.obj);
316 case EVENT_VOICE_CALL_STARTED:
317 onVoiceCallStarted();
320 case EVENT_VOICE_CALL_ENDED:
324 case EVENT_CLEAN_UP_CONNECTION:
325 boolean tearDown = (msg.arg1 == 0) ? false : true;
326 onCleanUpConnection(tearDown, (String)msg.obj);
329 case EVENT_SET_MASTER_DATA_ENABLE:
330 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
331 onSetDataEnabled(enabled);
334 case EVENT_RESET_DONE:
335 onResetDone((AsyncResult) msg.obj);
339 Log.e("DATA", "Unidentified event = " + msg.what);
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.
349 public synchronized boolean getDataEnabled() {
350 return dataEnabled[APN_DEFAULT_ID];
354 * Report on whether data connectivity is enabled
355 * @return {@code false} if data connectivity has been explicitly disabled,
356 * {@code true} otherwise.
358 public boolean getAnyDataEnabled() {
359 return (enabledCount != 0);
362 protected abstract void startNetStatPoll();
364 protected abstract void stopNetStatPoll();
366 protected abstract void restartRadio();
368 protected abstract void log(String s);
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)) {
375 } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
377 } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
379 } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
382 return APN_INVALID_ID;
386 protected String apnIdToType(int id) {
389 return Phone.APN_TYPE_DEFAULT;
391 return Phone.APN_TYPE_MMS;
393 return Phone.APN_TYPE_SUPL;
395 return Phone.APN_TYPE_DUN;
397 return Phone.APN_TYPE_HIPRI;
399 Log.e(LOG_TAG, "Unknown id (" + id + ") in apnIdToType");
400 return Phone.APN_TYPE_DEFAULT;
404 protected abstract boolean isApnTypeActive(String type);
406 protected abstract boolean isApnTypeAvailable(String type);
408 protected abstract String[] getActiveApnTypes();
410 protected abstract String getActiveApnString();
412 public abstract ArrayList<DataConnection> getAllDataConnections();
414 protected abstract String getInterfaceName(String apnType);
416 protected abstract String getIpAddress(String apnType);
418 protected abstract String getGateway(String apnType);
420 protected abstract String[] getDnsServers(String apnType);
422 protected abstract void setState(State s);
424 protected synchronized boolean isEnabled(int id) {
425 if (id != APN_INVALID_ID) {
426 return dataEnabled[id];
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.
441 public synchronized int enableApnType(String type) {
442 int id = apnTypeToId(type);
443 if (id == APN_INVALID_ID) {
444 return Phone.APN_REQUEST_FAILED;
447 if (DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
448 + isApnTypeActive(type) + " and state = " + state);
450 if (!isApnTypeAvailable(type)) {
451 if (DBG) Log.d(LOG_TAG, "type not available");
452 return Phone.APN_TYPE_NOT_AVAILABLE;
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);
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;
464 return Phone.APN_REQUEST_STARTED;
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}.
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;
482 setEnabled(id, false);
483 if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
484 if (dataEnabled[APN_DEFAULT_ID]) {
485 return Phone.APN_ALREADY_ACTIVE;
487 return Phone.APN_REQUEST_STARTED;
490 return Phone.APN_REQUEST_STARTED;
493 return Phone.APN_REQUEST_FAILED;
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);
501 Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
503 msg.arg2 = (enable ? ENABLED : DISABLED);
507 protected synchronized void onEnableApn(int apnId, int enabled) {
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)));
514 if (enabled == ENABLED) {
515 if (!dataEnabled[apnId]) {
516 dataEnabled[apnId] = true;
519 String type = apnIdToType(apnId);
520 if (!isApnTypeActive(type)) {
521 mRequestedApnType = type;
526 if (dataEnabled[apnId]) {
527 dataEnabled[apnId] = false;
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;
541 * Called when we switch APNs.
543 * mRequestedApnType is set prior to call
546 protected void onEnableNewApn() {
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
560 public boolean setDataEnabled(boolean enable) {
561 if (DBG) Log.d(LOG_TAG, "setDataEnabled(" + enable + ")");
563 Message msg = obtainMessage(EVENT_SET_MASTER_DATA_ENABLE);
564 msg.arg1 = (enable ? ENABLED : DISABLED);
569 protected void onSetDataEnabled(boolean enable) {
570 if (mMasterDataEnabled != enable) {
571 mMasterDataEnabled = enable;
573 mRetryMgr.resetRetryCount();
574 onTrySetupData(Phone.REASON_DATA_ENABLED);
576 onCleanUpConnection(true, Phone.REASON_DATA_DISABLED);