DataConnectionTracker.java revision 0badd0b700ed618dac421cb6cde4654b51acb3a4
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
104    //***** Constants
105
106    protected static final int APN_INVALID_ID = -1;
107    protected static final int APN_DEFAULT_ID = 0;
108    protected static final int APN_MMS_ID = 1;
109    protected static final int APN_SUPL_ID = 2;
110    protected static final int APN_DUN_ID = 3;
111    protected static final int APN_HIPRI_ID = 4;
112    protected static final int APN_NUM_TYPES = 5;
113
114    protected boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
115    protected int enabledCount = 0;
116
117    /* Currently requested APN type */
118    protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
119
120    /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
121    protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
122        + "5000,10000,20000,40000,80000:5000,160000:5000,"
123        + "320000:5000,640000:5000,1280000:5000,1800000:5000";
124
125    /** Slow poll when attempting connection recovery. */
126    protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
127    /** Default ping deadline, in seconds. */
128    protected static final int DEFAULT_PING_DEADLINE = 5;
129    /** Default max failure count before attempting to network re-registration. */
130    protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
131
132    /**
133     * After detecting a potential connection problem, this is the max number
134     * of subsequent polls before attempting a radio reset.  At this point,
135     * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
136     * poll for about 2 more minutes.
137     */
138    protected static final int NO_RECV_POLL_LIMIT = 24;
139
140    // 1 sec. default polling interval when screen is on.
141    protected static final int POLL_NETSTAT_MILLIS = 1000;
142    // 10 min. default polling interval when screen is off.
143    protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
144    // 2 min for round trip time
145    protected static final int POLL_LONGEST_RTT = 120 * 1000;
146    // 10 for packets without ack
147    protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
148    // how long to wait before switching back to default APN
149    protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
150    // system property that can override the above value
151    protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
152    // represents an invalid IP address
153    protected static final String NULL_IP = "0.0.0.0";
154
155
156    // member variables
157    protected PhoneBase phone;
158    protected Activity activity = Activity.NONE;
159    protected State state = State.IDLE;
160    protected Handler mDataConnectionTracker = null;
161
162
163    protected INetStatService netstat;
164    protected long txPkts, rxPkts, sentSinceLastRecv;
165    protected int netStatPollPeriod;
166    protected int mNoRecvPollCount = 0;
167    protected boolean netStatPollEnabled = false;
168
169    /** Manage the behavior of data retry after failure */
170    protected final RetryManager mRetryMgr = new RetryManager();
171
172    // wifi connection status will be updated by sticky intent
173    protected boolean mIsWifiConnected = false;
174
175    /** Intent sent when the reconnect alarm fires. */
176    protected PendingIntent mReconnectIntent = null;
177
178    /** CID of active data connection */
179    protected int cidActive;
180
181   /**
182     * Default constructor
183     */
184    protected DataConnectionTracker(PhoneBase phone) {
185        super();
186        this.phone = phone;
187    }
188
189    public abstract void dispose();
190
191    public Activity getActivity() {
192        return activity;
193    }
194
195    public State getState() {
196        return state;
197    }
198
199    public String getStateInString() {
200        switch (state) {
201            case IDLE:          return "IDLE";
202            case INITING:       return "INIT";
203            case CONNECTING:    return "CING";
204            case SCANNING:      return "SCAN";
205            case CONNECTED:     return "CNTD";
206            case DISCONNECTING: return "DING";
207            case FAILED:        return "FAIL";
208            default:            return "ERRO";
209        }
210    }
211
212    /**
213     * The data connection is expected to be setup while device
214     *  1. has Icc card
215     *  2. registered for data service
216     *  3. user doesn't explicitly disable data service
217     *  4. wifi is not on
218     *
219     * @return false while no data connection if all above requirements are met.
220     */
221    public abstract boolean isDataConnectionAsDesired();
222
223    //The data roaming setting is now located in the shared preferences.
224    //  See if the requested preference value is the same as that stored in
225    //  the shared values.  If it is not, then update it.
226    public void setDataOnRoamingEnabled(boolean enabled) {
227        if (getDataOnRoamingEnabled() != enabled) {
228            Settings.Secure.putInt(phone.getContext().getContentResolver(),
229                Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
230            if (phone.getServiceState().getRoaming()) {
231                if (enabled) {
232                    mRetryMgr.resetRetryCount();
233                }
234                sendMessage(obtainMessage(EVENT_ROAMING_ON));
235            }
236        }
237    }
238
239    //Retrieve the data roaming setting from the shared preferences.
240    public boolean getDataOnRoamingEnabled() {
241        try {
242            return Settings.Secure.getInt(phone.getContext().getContentResolver(),
243                Settings.Secure.DATA_ROAMING) > 0;
244        } catch (SettingNotFoundException snfe) {
245            return false;
246        }
247    }
248
249    // abstract handler methods
250    protected abstract void onTrySetupData(String reason);
251    protected abstract void onRoamingOff();
252    protected abstract void onRoamingOn();
253    protected abstract void onRadioAvailable();
254    protected abstract void onRadioOffOrNotAvailable();
255    protected abstract void onDataSetupComplete(AsyncResult ar);
256    protected abstract void onDisconnectDone(AsyncResult ar);
257    protected abstract void onVoiceCallStarted();
258    protected abstract void onVoiceCallEnded();
259    protected abstract void onCleanUpConnection(boolean tearDown, String reason);
260
261  //***** Overridden from Handler
262    public void handleMessage (Message msg) {
263        switch (msg.what) {
264
265            case EVENT_TRY_SETUP_DATA:
266                String reason = null;
267                if (msg.obj instanceof String) {
268                    reason = (String)msg.obj;
269                }
270                onTrySetupData(reason);
271                break;
272
273            case EVENT_ROAMING_OFF:
274                if (getDataOnRoamingEnabled() == false) {
275                    mRetryMgr.resetRetryCount();
276                }
277                onRoamingOff();
278                break;
279
280            case EVENT_ROAMING_ON:
281                onRoamingOn();
282                break;
283
284            case EVENT_RADIO_AVAILABLE:
285                onRadioAvailable();
286                break;
287
288            case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
289                onRadioOffOrNotAvailable();
290                break;
291
292            case EVENT_DATA_SETUP_COMPLETE:
293                cidActive = msg.arg1;
294                onDataSetupComplete((AsyncResult) msg.obj);
295                break;
296
297            case EVENT_DISCONNECT_DONE:
298                onDisconnectDone((AsyncResult) msg.obj);
299                break;
300
301            case EVENT_VOICE_CALL_STARTED:
302                onVoiceCallStarted();
303                break;
304
305            case EVENT_VOICE_CALL_ENDED:
306                onVoiceCallEnded();
307                break;
308
309            case EVENT_CLEAN_UP_CONNECTION:
310                boolean tearDown = (msg.arg1 == 0) ? false : true;
311                onCleanUpConnection(tearDown, (String)msg.obj);
312                break;
313
314            default:
315                Log.e("DATA", "Unidentified event = " + msg.what);
316                break;
317        }
318    }
319
320    /**
321     * Report the current state of data connectivity (enabled or disabled)
322     * @return {@code false} if data connectivity has been explicitly disabled,
323     * {@code true} otherwise.
324     */
325    public boolean getDataEnabled() {
326        return dataEnabled[APN_DEFAULT_ID];
327    }
328
329    /**
330     * Report on whether data connectivity is enabled
331     * @return {@code false} if data connectivity has been explicitly disabled,
332     * {@code true} otherwise.
333     */
334    public boolean getAnyDataEnabled() {
335        return (enabledCount != 0);
336    }
337
338    protected abstract void startNetStatPoll();
339
340    protected abstract void stopNetStatPoll();
341
342    protected abstract void restartRadio();
343
344    protected abstract void log(String s);
345
346    protected int apnTypeToId(String type) {
347        if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
348            return APN_DEFAULT_ID;
349        } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
350            return APN_MMS_ID;
351        } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
352            return APN_SUPL_ID;
353        } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
354            return APN_DUN_ID;
355        } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
356            return APN_HIPRI_ID;
357        } else {
358            return APN_INVALID_ID;
359        }
360    }
361
362    protected abstract boolean isApnTypeActive(String type);
363
364    protected abstract boolean isApnTypeAvailable(String type);
365
366    protected abstract String[] getActiveApnTypes();
367
368    protected abstract String getActiveApnString();
369
370    public abstract ArrayList<DataConnection> getAllDataConnections();
371
372    protected abstract String getInterfaceName(String apnType);
373
374    protected abstract String getIpAddress(String apnType);
375
376    protected abstract String getGateway(String apnType);
377
378    protected abstract String[] getDnsServers(String apnType);
379
380    protected abstract void setState(State s);
381
382    protected boolean isEnabled(int id) {
383        if (id != APN_INVALID_ID) {
384            return dataEnabled[id];
385        }
386        return false;
387    }
388
389    /**
390     * Ensure that we are connected to an APN of the specified type.
391     * @param type the APN type (currently the only valid values
392     * are {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
393     * @return the result of the operation. Success is indicated by
394     * a return value of either {@code Phone.APN_ALREADY_ACTIVE} or
395     * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a broadcast
396     * will be sent by the ConnectivityManager when a connection to
397     * the APN has been established.
398     */
399    public int enableApnType(String type) {
400        int id = apnTypeToId(type);
401        if (id == APN_INVALID_ID) {
402            return Phone.APN_REQUEST_FAILED;
403        }
404
405        // If already active, return
406        if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = "
407                + isApnTypeActive(type) + " and state = " + state);
408
409        if (isApnTypeActive(type)) {
410            if (state == State.INITING) return Phone.APN_REQUEST_STARTED;
411            else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE;
412        }
413
414        if (!isApnTypeAvailable(type)) {
415            return Phone.APN_TYPE_NOT_AVAILABLE;
416        }
417
418        setEnabled(id, true);
419        mRequestedApnType = type;
420        sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN));
421        return Phone.APN_REQUEST_STARTED;
422    }
423
424    /**
425     * The APN of the specified type is no longer needed. Ensure that if
426     * use of the default APN has not been explicitly disabled, we are connected
427     * to the default APN.
428     * @param type the APN type. The only valid values are currently
429     * {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
430     * @return
431     */
432    public int disableApnType(String type) {
433        if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")");
434        int id = apnTypeToId(type);
435        if (id == APN_INVALID_ID) {
436            return Phone.APN_REQUEST_FAILED;
437        }
438        if (isEnabled(id)) {
439            setEnabled(id, false);
440            if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
441                mRequestedApnType = Phone.APN_TYPE_DEFAULT;
442                if (dataEnabled[APN_DEFAULT_ID]) {
443                    return Phone.APN_ALREADY_ACTIVE;
444                } else {
445                    return Phone.APN_REQUEST_STARTED;
446                }
447            } else {
448                return Phone.APN_REQUEST_STARTED;
449            }
450        } else {
451            return Phone.APN_REQUEST_FAILED;
452        }
453    }
454
455    protected synchronized void setEnabled(int id, boolean enable) {
456        if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ") with old state = " +
457                dataEnabled[id] + " and enabledCount = " + enabledCount);
458        if (dataEnabled[id] != enable) {
459            dataEnabled[id] = enable;
460
461            // count the total number of enabled APN's
462            // if we just enabled the first APN, start our Data connection,
463            // if we disabled the last, stop our data connection
464            if (enable) {
465                enabledCount++;
466                if (enabledCount == 1) {
467                    setPrivateDataEnabled(true);
468                }
469            } else {
470                enabledCount--;
471                if (enabledCount == 0) {
472                    setPrivateDataEnabled(false);
473                }
474            }
475        }
476    }
477
478    /**
479     * Prevent mobile data connections from being established,
480     * or once again allow mobile data connections. If the state
481     * toggles, then either tear down or set up data, as
482     * appropriate to match the new state.
483     * <p>This operation only affects the default APN, and if the same APN is
484     * currently being used for MMS traffic, the teardown will not happen
485     * even when {@code enable} is {@code false}.</p>
486     * @param enable indicates whether to enable ({@code true}) or disable ({@code false}) data
487     * @return {@code true} if the operation succeeded
488     */
489    public boolean setDataEnabled(boolean enable) {
490        if (DBG) Log.d(LOG_TAG, "setDataEnabled("+enable+")");
491        setEnabled(APN_DEFAULT_ID, enable);
492        return true;
493    }
494
495    private void setPrivateDataEnabled(boolean enable) {
496        if (DBG) Log.d(LOG_TAG, "setPrivateDataEnabled("+enable+")");
497        if (enable) {
498            sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
499        } else {
500            Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
501            msg.arg1 = 1; // tearDown is true
502            msg.obj = Phone.REASON_DATA_DISABLED;
503            sendMessage(msg);
504        }
505    }
506
507}
508