DataConnectionTracker.java revision 984d22b180e68d6b9f8e2c81c4eb271deccfc94a
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
17package com.android.internal.telephony;
18
19import android.app.PendingIntent;
20import android.os.AsyncResult;
21import android.os.Handler;
22import android.os.INetStatService;
23import android.os.Message;
24import android.os.RemoteException;
25import android.provider.Settings;
26import android.provider.Settings.SettingNotFoundException;
27import android.text.TextUtils;
28import android.util.Log;
29
30import java.util.ArrayList;
31
32/**
33 * {@hide}
34 *
35 */
36public 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     */
195    protected DataConnectionTracker(PhoneBase phone) {
196        super();
197        this.phone = phone;
198    }
199
200    public abstract void dispose();
201
202    public Activity getActivity() {
203        return activity;
204    }
205
206    public State getState() {
207        return state;
208    }
209
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     */
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.
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.
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
261    protected abstract boolean onTrySetupData(String reason);
262    protected abstract void onRoamingOff();
263    protected abstract void onRoamingOn();
264    protected abstract void onRadioAvailable();
265    protected abstract void onRadioOffOrNotAvailable();
266    protected abstract void onDataSetupComplete(AsyncResult ar);
267    protected abstract void onDisconnectDone(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            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     */
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     */
354    public boolean getAnyDataEnabled() {
355        return (enabledCount != 0);
356    }
357
358    protected abstract void startNetStatPoll();
359
360    protected abstract void stopNetStatPoll();
361
362    protected abstract void restartRadio();
363
364    protected abstract void log(String s);
365
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
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
400    protected abstract boolean isApnTypeActive(String type);
401
402    protected abstract boolean isApnTypeAvailable(String type);
403
404    protected abstract String[] getActiveApnTypes();
405
406    protected abstract String getActiveApnString();
407
408    public abstract ArrayList<DataConnection> getAllDataConnections();
409
410    protected abstract String getInterfaceName(String apnType);
411
412    protected abstract String getIpAddress(String apnType);
413
414    protected abstract String getGateway(String apnType);
415
416    protected abstract String[] getDnsServers(String apnType);
417
418    protected abstract void setState(State s);
419
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     */
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     */
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
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
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     */
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     */
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
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