• 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.content.BroadcastReceiver;
21 import android.content.ContentResolver;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.IntentFilter;
25 import android.content.SharedPreferences;
26 import android.database.ContentObserver;
27 import android.net.LinkCapabilities;
28 import android.net.LinkProperties;
29 import android.net.NetworkInfo;
30 import android.net.wifi.WifiManager;
31 import android.os.AsyncResult;
32 import android.os.Bundle;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.os.Messenger;
36 import android.os.SystemProperties;
37 import android.preference.PreferenceManager;
38 import android.provider.Settings;
39 import android.provider.Settings.SettingNotFoundException;
40 import android.telephony.ServiceState;
41 import android.text.TextUtils;
42 import android.util.Log;
43 
44 import com.android.internal.R;
45 import com.android.internal.telephony.DataConnection.FailCause;
46 import com.android.internal.util.AsyncChannel;
47 import com.android.internal.util.Protocol;
48 
49 import java.util.ArrayList;
50 import java.util.HashMap;
51 import java.util.concurrent.ConcurrentHashMap;
52 import java.util.concurrent.atomic.AtomicInteger;
53 
54 /**
55  * {@hide}
56  */
57 public abstract class DataConnectionTracker extends Handler {
58     protected static final boolean DBG = true;
59 
60     /**
61      * IDLE: ready to start data connection setup, default state
62      * INITING: state of issued setupDefaultPDP() but not finish yet
63      * CONNECTING: state of issued startPppd() but not finish yet
64      * SCANNING: data connection fails with one apn but other apns are available
65      *           ready to start data connection on other apns (before INITING)
66      * CONNECTED: IP connection is setup
67      * DISCONNECTING: Connection.disconnect() has been called, but PDP
68      *                context is not yet deactivated
69      * FAILED: data connection fail for all apns settings
70      *
71      * getDataConnectionState() maps State to DataState
72      *      FAILED or IDLE : DISCONNECTED
73      *      INITING or CONNECTING or SCANNING: CONNECTING
74      *      CONNECTED : CONNECTED or DISCONNECTING
75      */
76     public enum State {
77         IDLE,
78         INITING,
79         CONNECTING,
80         SCANNING,
81         CONNECTED,
82         DISCONNECTING,
83         FAILED
84     }
85 
86     public enum Activity {
87         NONE,
88         DATAIN,
89         DATAOUT,
90         DATAINANDOUT,
91         DORMANT
92     }
93 
94     public static String ACTION_DATA_CONNECTION_TRACKER_MESSENGER =
95         "com.android.internal.telephony";
96     public static String EXTRA_MESSENGER = "EXTRA_MESSENGER";
97 
98     /***** Event Codes *****/
99     protected static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER;
100     protected static final int EVENT_DATA_SETUP_COMPLETE = BASE + 0;
101     protected static final int EVENT_RADIO_AVAILABLE = BASE + 1;
102     protected static final int EVENT_RECORDS_LOADED = BASE + 2;
103     protected static final int EVENT_TRY_SETUP_DATA = BASE + 3;
104     protected static final int EVENT_DATA_STATE_CHANGED = BASE + 4;
105     protected static final int EVENT_POLL_PDP = BASE + 5;
106     protected static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = BASE + 6;
107     protected static final int EVENT_VOICE_CALL_STARTED = BASE + 7;
108     protected static final int EVENT_VOICE_CALL_ENDED = BASE + 8;
109     protected static final int EVENT_DATA_CONNECTION_DETACHED = BASE + 9;
110     protected static final int EVENT_LINK_STATE_CHANGED = BASE + 10;
111     protected static final int EVENT_ROAMING_ON = BASE + 11;
112     protected static final int EVENT_ROAMING_OFF = BASE + 12;
113     protected static final int EVENT_ENABLE_NEW_APN = BASE + 13;
114     protected static final int EVENT_RESTORE_DEFAULT_APN = BASE + 14;
115     protected static final int EVENT_DISCONNECT_DONE = BASE + 15;
116     protected static final int EVENT_DATA_CONNECTION_ATTACHED = BASE + 16;
117     protected static final int EVENT_START_NETSTAT_POLL = BASE + 17;
118     protected static final int EVENT_START_RECOVERY = BASE + 18;
119     protected static final int EVENT_APN_CHANGED = BASE + 19;
120     protected static final int EVENT_CDMA_DATA_DETACHED = BASE + 20;
121     protected static final int EVENT_NV_READY = BASE + 21;
122     protected static final int EVENT_PS_RESTRICT_ENABLED = BASE + 22;
123     protected static final int EVENT_PS_RESTRICT_DISABLED = BASE + 23;
124     public static final int EVENT_CLEAN_UP_CONNECTION = BASE + 24;
125     protected static final int EVENT_CDMA_OTA_PROVISION = BASE + 25;
126     protected static final int EVENT_RESTART_RADIO = BASE + 26;
127     protected static final int EVENT_SET_INTERNAL_DATA_ENABLE = BASE + 27;
128     protected static final int EVENT_RESET_DONE = BASE + 28;
129     public static final int CMD_SET_USER_DATA_ENABLE = BASE + 29;
130     public static final int EVENT_CLEAN_UP_ALL_CONNECTIONS = BASE + 30;
131     public static final int CMD_SET_DEPENDENCY_MET = BASE + 31;
132     public static final int CMD_SET_POLICY_DATA_ENABLE = BASE + 32;
133 
134     /***** Constants *****/
135 
136     protected static final int APN_INVALID_ID = -1;
137     protected static final int APN_DEFAULT_ID = 0;
138     protected static final int APN_MMS_ID = 1;
139     protected static final int APN_SUPL_ID = 2;
140     protected static final int APN_DUN_ID = 3;
141     protected static final int APN_HIPRI_ID = 4;
142     protected static final int APN_IMS_ID = 5;
143     protected static final int APN_FOTA_ID = 6;
144     protected static final int APN_CBS_ID = 7;
145     protected static final int APN_NUM_TYPES = 8;
146 
147     public static final int DISABLED = 0;
148     public static final int ENABLED = 1;
149 
150     public static final String APN_TYPE_KEY = "apnType";
151 
152     /** Delay between APN attempts.
153         Note the property override mechanism is there just for testing purpose only. */
154     protected static final int APN_DELAY_MILLIS =
155                                 SystemProperties.getInt("persist.radio.apn_delay", 5000);
156 
157     protected Object mDataEnabledLock = new Object();
158 
159     // responds to the setInternalDataEnabled call - used internally to turn off data
160     // for example during emergency calls
161     protected boolean mInternalDataEnabled = true;
162 
163     // responds to public (user) API to enable/disable data use
164     // independent of mInternalDataEnabled and requests for APN access
165     // persisted
166     protected boolean mUserDataEnabled = true;
167     protected boolean mPolicyDataEnabled = true;
168 
169     private boolean[] dataEnabled = new boolean[APN_NUM_TYPES];
170 
171     private int enabledCount = 0;
172 
173     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
174     protected String mRequestedApnType = Phone.APN_TYPE_DEFAULT;
175 
176     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
177     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
178         + "5000,10000,20000,40000,80000:5000,160000:5000,"
179         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
180 
181     /** Retry configuration for secondary networks: 4 tries in 20 sec */
182     protected static final String SECONDARY_DATA_RETRY_CONFIG =
183             "max_retries=3, 5000, 5000, 5000";
184 
185     /** Slow poll when attempting connection recovery. */
186     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
187     /** Default max failure count before attempting to network re-registration. */
188     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
189 
190     /**
191      * After detecting a potential connection problem, this is the max number
192      * of subsequent polls before attempting a radio reset.  At this point,
193      * poll interval is 5 seconds (POLL_NETSTAT_SLOW_MILLIS), so set this to
194      * poll for about 2 more minutes.
195      */
196     protected static final int NO_RECV_POLL_LIMIT = 24;
197 
198     // 1 sec. default polling interval when screen is on.
199     protected static final int POLL_NETSTAT_MILLIS = 1000;
200     // 10 min. default polling interval when screen is off.
201     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
202     // 2 min for round trip time
203     protected static final int POLL_LONGEST_RTT = 120 * 1000;
204     // 10 for packets without ack
205     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
206     // how long to wait before switching back to default APN
207     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
208     // system property that can override the above value
209     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
210     // represents an invalid IP address
211     protected static final String NULL_IP = "0.0.0.0";
212 
213     // TODO: See if we can remove INTENT_RECONNECT_ALARM
214     //       having to have different values for GSM and
215     //       CDMA. If so we can then remove the need for
216     //       getActionIntentReconnectAlarm.
217     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON = "reason";
218 
219     // Used for debugging. Send the INTENT with an optional counter value with the number
220     // of times the setup is to fail before succeeding. If the counter isn't passed the
221     // setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)
222     // adb shell am broadcast \
223     //  -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \
224     //  --ei fail_data_setup_counter 3 --ei fail_data_setup_fail_cause -3
225     protected static final String INTENT_SET_FAIL_DATA_SETUP_COUNTER =
226         "com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter";
227     protected static final String FAIL_DATA_SETUP_COUNTER = "fail_data_setup_counter";
228     protected int mFailDataSetupCounter = 0;
229     protected static final String FAIL_DATA_SETUP_FAIL_CAUSE = "fail_data_setup_fail_cause";
230     protected FailCause mFailDataSetupFailCause = FailCause.ERROR_UNSPECIFIED;
231 
232     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
233 
234     // member variables
235     protected PhoneBase mPhone;
236     protected Activity mActivity = Activity.NONE;
237     protected State mState = State.IDLE;
238     protected Handler mDataConnectionTracker = null;
239 
240 
241     protected long mTxPkts;
242     protected long mRxPkts;
243     protected long mSentSinceLastRecv;
244     protected int mNetStatPollPeriod;
245     protected int mNoRecvPollCount = 0;
246     protected boolean mNetStatPollEnabled = false;
247 
248     // wifi connection status will be updated by sticky intent
249     protected boolean mIsWifiConnected = false;
250 
251     /** Intent sent when the reconnect alarm fires. */
252     protected PendingIntent mReconnectIntent = null;
253 
254     /** CID of active data connection */
255     protected int mCidActive;
256 
257     // When false we will not auto attach and manually attaching is required.
258     protected boolean mAutoAttachOnCreation = false;
259 
260     // State of screen
261     // (TODO: Reconsider tying directly to screen, maybe this is
262     //        really a lower power mode")
263     protected boolean mIsScreenOn = true;
264 
265     /** Allows the generation of unique Id's for DataConnection objects */
266     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
267 
268     /** The data connections. */
269     protected HashMap<Integer, DataConnection> mDataConnections =
270         new HashMap<Integer, DataConnection>();
271 
272     /** The data connection async channels */
273     protected HashMap<Integer, DataConnectionAc> mDataConnectionAsyncChannels =
274         new HashMap<Integer, DataConnectionAc>();
275 
276     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
277     protected HashMap<String, Integer> mApnToDataConnectionId =
278                                     new HashMap<String, Integer>();
279 
280     /** Phone.APN_TYPE_* ===> ApnContext */
281     protected ConcurrentHashMap<String, ApnContext> mApnContexts;
282 
283     /* Currently active APN */
284     protected ApnSetting mActiveApn;
285 
286     /** allApns holds all apns */
287     protected ArrayList<ApnSetting> mAllApns = null;
288 
289     /** preferred apn */
290     protected ApnSetting mPreferredApn = null;
291 
292     /** Is packet service restricted by network */
293     protected boolean mIsPsRestricted = false;
294 
295     /* Once disposed dont handle any messages */
296     protected boolean mIsDisposed = false;
297 
298     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
299     {
300         @Override
301         public void onReceive(Context context, Intent intent)
302         {
303             String action = intent.getAction();
304             if (DBG) log("onReceive: action=" + action);
305             if (action.equals(Intent.ACTION_SCREEN_ON)) {
306                 mIsScreenOn = true;
307                 stopNetStatPoll();
308                 startNetStatPoll();
309             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
310                 mIsScreenOn = false;
311                 stopNetStatPoll();
312                 startNetStatPoll();
313             } else if (action.startsWith(getActionIntentReconnectAlarm())) {
314                 log("Reconnect alarm. Previous state was " + mState);
315                 onActionIntentReconnectAlarm(intent);
316 
317             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
318                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
319                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
320                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
321             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
322                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
323                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
324 
325                 if (!enabled) {
326                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
327                     // quit and won't report disconnected until next enabling.
328                     mIsWifiConnected = false;
329                 }
330             } else if (action.equals(INTENT_SET_FAIL_DATA_SETUP_COUNTER)) {
331                 mFailDataSetupCounter = intent.getIntExtra(FAIL_DATA_SETUP_COUNTER, 1);
332                 mFailDataSetupFailCause = FailCause.fromInt(
333                         intent.getIntExtra(FAIL_DATA_SETUP_FAIL_CAUSE,
334                                                     FailCause.ERROR_UNSPECIFIED.getErrorCode()));
335                 if (DBG) log("set mFailDataSetupCounter=" + mFailDataSetupCounter +
336                         " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
337             }
338         }
339     };
340 
341     private final DataRoamingSettingObserver mDataRoamingSettingObserver;
342 
343     private class DataRoamingSettingObserver extends ContentObserver {
DataRoamingSettingObserver(Handler handler)344         public DataRoamingSettingObserver(Handler handler) {
345             super(handler);
346         }
347 
register(Context context)348         public void register(Context context) {
349             final ContentResolver resolver = context.getContentResolver();
350             resolver.registerContentObserver(
351                     Settings.Secure.getUriFor(Settings.Secure.DATA_ROAMING), false, this);
352         }
353 
unregister(Context context)354         public void unregister(Context context) {
355             final ContentResolver resolver = context.getContentResolver();
356             resolver.unregisterContentObserver(this);
357         }
358 
359         @Override
onChange(boolean selfChange)360         public void onChange(boolean selfChange) {
361             // already running on mPhone handler thread
362             handleDataOnRoamingChange();
363         }
364     }
365 
isDataSetupCompleteOk(AsyncResult ar)366     protected boolean isDataSetupCompleteOk(AsyncResult ar) {
367         if (ar.exception != null) {
368             if (DBG) log("isDataSetupCompleteOk return false, ar.result=" + ar.result);
369             return false;
370         }
371         if (mFailDataSetupCounter <= 0) {
372             if (DBG) log("isDataSetupCompleteOk return true");
373             return true;
374         }
375         ar.result = mFailDataSetupFailCause;
376         if (DBG) {
377             log("isDataSetupCompleteOk return false" +
378                     " mFailDataSetupCounter=" + mFailDataSetupCounter +
379                     " mFailDataSetupFailCause=" + mFailDataSetupFailCause);
380         }
381         mFailDataSetupCounter -= 1;
382         return false;
383     }
384 
onActionIntentReconnectAlarm(Intent intent)385     protected void onActionIntentReconnectAlarm(Intent intent) {
386         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
387         if (mState == State.FAILED) {
388             Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION);
389             msg.arg1 = 0; // tearDown is false
390             msg.arg2 = 0;
391             msg.obj = reason;
392             sendMessage(msg);
393         }
394         sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA));
395     }
396 
397     /**
398      * Default constructor
399      */
DataConnectionTracker(PhoneBase phone)400     protected DataConnectionTracker(PhoneBase phone) {
401         super();
402         mPhone = phone;
403 
404         IntentFilter filter = new IntentFilter();
405         filter.addAction(getActionIntentReconnectAlarm());
406         filter.addAction(Intent.ACTION_SCREEN_ON);
407         filter.addAction(Intent.ACTION_SCREEN_OFF);
408         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
409         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
410         filter.addAction(INTENT_SET_FAIL_DATA_SETUP_COUNTER);
411 
412         mUserDataEnabled = Settings.Secure.getInt(
413                 mPhone.getContext().getContentResolver(), Settings.Secure.MOBILE_DATA, 1) == 1;
414 
415         // TODO: Why is this registering the phone as the receiver of the intent
416         //       and not its own handler?
417         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
418 
419         // This preference tells us 1) initial condition for "dataEnabled",
420         // and 2) whether the RIL will setup the baseband to auto-PS attach.
421 
422         dataEnabled[APN_DEFAULT_ID] = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,
423                                                                   true);
424         if (dataEnabled[APN_DEFAULT_ID]) {
425             enabledCount++;
426         }
427 
428         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
429         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
430 
431         // watch for changes to Settings.Secure.DATA_ROAMING
432         mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone);
433         mDataRoamingSettingObserver.register(mPhone.getContext());
434     }
435 
dispose()436     public void dispose() {
437         for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
438             dcac.disconnect();
439         }
440         mDataConnectionAsyncChannels.clear();
441         mIsDisposed = true;
442         mPhone.getContext().unregisterReceiver(this.mIntentReceiver);
443         mDataRoamingSettingObserver.unregister(mPhone.getContext());
444     }
445 
broadcastMessenger()446     protected void broadcastMessenger() {
447         Intent intent = new Intent(ACTION_DATA_CONNECTION_TRACKER_MESSENGER);
448         intent.putExtra(EXTRA_MESSENGER, new Messenger(this));
449         mPhone.getContext().sendBroadcast(intent);
450     }
451 
getActivity()452     public Activity getActivity() {
453         return mActivity;
454     }
455 
isApnTypeActive(String type)456     public boolean isApnTypeActive(String type) {
457         // TODO: support simultaneous with List instead
458         if (Phone.APN_TYPE_DUN.equals(type)) {
459             ApnSetting dunApn = fetchDunApn();
460             if (dunApn != null) {
461                 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
462             }
463         }
464         return mActiveApn != null && mActiveApn.canHandleType(type);
465     }
466 
fetchDunApn()467     protected ApnSetting fetchDunApn() {
468         Context c = mPhone.getContext();
469         String apnData = Settings.Secure.getString(c.getContentResolver(),
470                 Settings.Secure.TETHER_DUN_APN);
471         ApnSetting dunSetting = ApnSetting.fromString(apnData);
472         if (dunSetting != null) return dunSetting;
473 
474         apnData = c.getResources().getString(R.string.config_tether_apndata);
475         return ApnSetting.fromString(apnData);
476     }
477 
getActiveApnTypes()478     public String[] getActiveApnTypes() {
479         String[] result;
480         if (mActiveApn != null) {
481             result = mActiveApn.types;
482         } else {
483             result = new String[1];
484             result[0] = Phone.APN_TYPE_DEFAULT;
485         }
486         return result;
487     }
488 
489     /** TODO: See if we can remove */
getActiveApnString(String apnType)490     public String getActiveApnString(String apnType) {
491         String result = null;
492         if (mActiveApn != null) {
493             result = mActiveApn.apn;
494         }
495         return result;
496     }
497 
498     /**
499      * Modify {@link Settings.Secure#DATA_ROAMING} value.
500      */
setDataOnRoamingEnabled(boolean enabled)501     public void setDataOnRoamingEnabled(boolean enabled) {
502         if (getDataOnRoamingEnabled() != enabled) {
503             final ContentResolver resolver = mPhone.getContext().getContentResolver();
504             Settings.Secure.putInt(resolver, Settings.Secure.DATA_ROAMING, enabled ? 1 : 0);
505             // will trigger handleDataOnRoamingChange() through observer
506         }
507     }
508 
509     /**
510      * Return current {@link Settings.Secure#DATA_ROAMING} value.
511      */
getDataOnRoamingEnabled()512     public boolean getDataOnRoamingEnabled() {
513         try {
514             final ContentResolver resolver = mPhone.getContext().getContentResolver();
515             return Settings.Secure.getInt(resolver, Settings.Secure.DATA_ROAMING) != 0;
516         } catch (SettingNotFoundException snfe) {
517             return false;
518         }
519     }
520 
handleDataOnRoamingChange()521     private void handleDataOnRoamingChange() {
522         if (mPhone.getServiceState().getRoaming()) {
523             if (getDataOnRoamingEnabled()) {
524                 resetAllRetryCounts();
525             }
526             sendMessage(obtainMessage(EVENT_ROAMING_ON));
527         }
528     }
529 
530     // abstract methods
getActionIntentReconnectAlarm()531     protected abstract String getActionIntentReconnectAlarm();
startNetStatPoll()532     protected abstract void startNetStatPoll();
stopNetStatPoll()533     protected abstract void stopNetStatPoll();
restartRadio()534     protected abstract void restartRadio();
log(String s)535     protected abstract void log(String s);
loge(String s)536     protected abstract void loge(String s);
isDataAllowed()537     protected abstract boolean isDataAllowed();
isApnTypeAvailable(String type)538     protected abstract boolean isApnTypeAvailable(String type);
getState(String apnType)539     public    abstract State getState(String apnType);
setState(State s)540     protected abstract void setState(State s);
gotoIdleAndNotifyDataConnection(String reason)541     protected abstract void gotoIdleAndNotifyDataConnection(String reason);
542 
onTrySetupData(String reason)543     protected abstract boolean onTrySetupData(String reason);
onRoamingOff()544     protected abstract void onRoamingOff();
onRoamingOn()545     protected abstract void onRoamingOn();
onRadioAvailable()546     protected abstract void onRadioAvailable();
onRadioOffOrNotAvailable()547     protected abstract void onRadioOffOrNotAvailable();
onDataSetupComplete(AsyncResult ar)548     protected abstract void onDataSetupComplete(AsyncResult ar);
onDisconnectDone(int connId, AsyncResult ar)549     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
onVoiceCallStarted()550     protected abstract void onVoiceCallStarted();
onVoiceCallEnded()551     protected abstract void onVoiceCallEnded();
onCleanUpConnection(boolean tearDown, int apnId, String reason)552     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
onCleanUpAllConnections(String cause)553     protected abstract void onCleanUpAllConnections(String cause);
isDataPossible(String apnType)554     protected abstract boolean isDataPossible(String apnType);
555 
556     @Override
handleMessage(Message msg)557     public void handleMessage(Message msg) {
558         switch (msg.what) {
559             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
560                 log("DISCONNECTED_CONNECTED: msg=" + msg);
561                 DataConnectionAc dcac = (DataConnectionAc) msg.obj;
562                 mDataConnectionAsyncChannels.remove(dcac.dataConnection.getDataConnectionId());
563                 dcac.disconnected();
564                 break;
565             }
566             case EVENT_ENABLE_NEW_APN:
567                 onEnableApn(msg.arg1, msg.arg2);
568                 break;
569 
570             case EVENT_TRY_SETUP_DATA:
571                 String reason = null;
572                 if (msg.obj instanceof String) {
573                     reason = (String) msg.obj;
574                 }
575                 onTrySetupData(reason);
576                 break;
577 
578             case EVENT_ROAMING_OFF:
579                 if (getDataOnRoamingEnabled() == false) {
580                     resetAllRetryCounts();
581                 }
582                 onRoamingOff();
583                 break;
584 
585             case EVENT_ROAMING_ON:
586                 onRoamingOn();
587                 break;
588 
589             case EVENT_RADIO_AVAILABLE:
590                 onRadioAvailable();
591                 break;
592 
593             case EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
594                 onRadioOffOrNotAvailable();
595                 break;
596 
597             case EVENT_DATA_SETUP_COMPLETE:
598                 mCidActive = msg.arg1;
599                 onDataSetupComplete((AsyncResult) msg.obj);
600                 break;
601 
602             case EVENT_DISCONNECT_DONE:
603                 log("DataConnectoinTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
604                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
605                 break;
606 
607             case EVENT_VOICE_CALL_STARTED:
608                 onVoiceCallStarted();
609                 break;
610 
611             case EVENT_VOICE_CALL_ENDED:
612                 onVoiceCallEnded();
613                 break;
614 
615             case EVENT_CLEAN_UP_ALL_CONNECTIONS: {
616                 onCleanUpAllConnections((String) msg.obj);
617                 break;
618             }
619             case EVENT_CLEAN_UP_CONNECTION: {
620                 boolean tearDown = (msg.arg1 == 0) ? false : true;
621                 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
622                 break;
623             }
624             case EVENT_SET_INTERNAL_DATA_ENABLE: {
625                 boolean enabled = (msg.arg1 == ENABLED) ? true : false;
626                 onSetInternalDataEnabled(enabled);
627                 break;
628             }
629             case EVENT_RESET_DONE: {
630                 if (DBG) log("EVENT_RESET_DONE");
631                 onResetDone((AsyncResult) msg.obj);
632                 break;
633             }
634             case CMD_SET_USER_DATA_ENABLE: {
635                 final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
636                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
637                 onSetUserDataEnabled(enabled);
638                 break;
639             }
640             case CMD_SET_DEPENDENCY_MET: {
641                 boolean met = (msg.arg1 == ENABLED) ? true : false;
642                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
643                 Bundle bundle = msg.getData();
644                 if (bundle != null) {
645                     String apnType = (String)bundle.get(APN_TYPE_KEY);
646                     if (apnType != null) {
647                         onSetDependencyMet(apnType, met);
648                     }
649                 }
650                 break;
651             }
652             case CMD_SET_POLICY_DATA_ENABLE: {
653                 final boolean enabled = (msg.arg1 == ENABLED) ? true : false;
654                 onSetPolicyDataEnabled(enabled);
655                 break;
656             }
657             default:
658                 Log.e("DATA", "Unidentified event msg=" + msg);
659                 break;
660         }
661     }
662 
663     /**
664      * Report on whether data connectivity is enabled
665      *
666      * @return {@code false} if data connectivity has been explicitly disabled,
667      *         {@code true} otherwise.
668      */
getAnyDataEnabled()669     public boolean getAnyDataEnabled() {
670         final boolean result;
671         synchronized (mDataEnabledLock) {
672             result = (mInternalDataEnabled && mUserDataEnabled && mPolicyDataEnabled
673                     && (enabledCount != 0));
674         }
675         if (!result && DBG) log("getAnyDataEnabled " + result);
676         return result;
677     }
678 
isEmergency()679     protected boolean isEmergency() {
680         final boolean result;
681         synchronized (mDataEnabledLock) {
682             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
683         }
684         log("isEmergency: result=" + result);
685         return result;
686     }
687 
apnTypeToId(String type)688     protected int apnTypeToId(String type) {
689         if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) {
690             return APN_DEFAULT_ID;
691         } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) {
692             return APN_MMS_ID;
693         } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) {
694             return APN_SUPL_ID;
695         } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) {
696             return APN_DUN_ID;
697         } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) {
698             return APN_HIPRI_ID;
699         } else if (TextUtils.equals(type, Phone.APN_TYPE_IMS)) {
700             return APN_IMS_ID;
701         } else if (TextUtils.equals(type, Phone.APN_TYPE_FOTA)) {
702             return APN_FOTA_ID;
703         } else if (TextUtils.equals(type, Phone.APN_TYPE_CBS)) {
704             return APN_CBS_ID;
705         } else {
706             return APN_INVALID_ID;
707         }
708     }
709 
apnIdToType(int id)710     protected String apnIdToType(int id) {
711         switch (id) {
712         case APN_DEFAULT_ID:
713             return Phone.APN_TYPE_DEFAULT;
714         case APN_MMS_ID:
715             return Phone.APN_TYPE_MMS;
716         case APN_SUPL_ID:
717             return Phone.APN_TYPE_SUPL;
718         case APN_DUN_ID:
719             return Phone.APN_TYPE_DUN;
720         case APN_HIPRI_ID:
721             return Phone.APN_TYPE_HIPRI;
722         case APN_IMS_ID:
723             return Phone.APN_TYPE_IMS;
724         case APN_FOTA_ID:
725             return Phone.APN_TYPE_FOTA;
726         case APN_CBS_ID:
727             return Phone.APN_TYPE_CBS;
728         default:
729             log("Unknown id (" + id + ") in apnIdToType");
730             return Phone.APN_TYPE_DEFAULT;
731         }
732     }
733 
getLinkProperties(String apnType)734     protected LinkProperties getLinkProperties(String apnType) {
735         int id = apnTypeToId(apnType);
736 
737         if (isApnIdEnabled(id)) {
738             // TODO - remove this cdma-only hack and support multiple DCs.
739             DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
740             return dcac.getLinkPropertiesSync();
741         } else {
742             return new LinkProperties();
743         }
744     }
745 
getLinkCapabilities(String apnType)746     protected LinkCapabilities getLinkCapabilities(String apnType) {
747         int id = apnTypeToId(apnType);
748         if (isApnIdEnabled(id)) {
749             // TODO - remove this cdma-only hack and support multiple DCs.
750             DataConnectionAc dcac = mDataConnectionAsyncChannels.get(0);
751             return dcac.getLinkCapabilitiesSync();
752         } else {
753             return new LinkCapabilities();
754         }
755     }
756 
757     // tell all active apns of the current condition
notifyDataConnection(String reason)758     protected void notifyDataConnection(String reason) {
759         for (int id = 0; id < APN_NUM_TYPES; id++) {
760             if (dataEnabled[id]) {
761                 mPhone.notifyDataConnection(reason, apnIdToType(id));
762             }
763         }
764         notifyOffApnsOfAvailability(reason);
765     }
766 
767     // a new APN has gone active and needs to send events to catch up with the
768     // current condition
notifyApnIdUpToCurrent(String reason, int apnId)769     private void notifyApnIdUpToCurrent(String reason, int apnId) {
770         switch (mState) {
771             case IDLE:
772             case INITING:
773                 break;
774             case CONNECTING:
775             case SCANNING:
776                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
777                 break;
778             case CONNECTED:
779             case DISCONNECTING:
780                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTING);
781                 mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.CONNECTED);
782                 break;
783         }
784     }
785 
786     // since we normally don't send info to a disconnected APN, we need to do this specially
notifyApnIdDisconnected(String reason, int apnId)787     private void notifyApnIdDisconnected(String reason, int apnId) {
788         mPhone.notifyDataConnection(reason, apnIdToType(apnId), Phone.DataState.DISCONNECTED);
789     }
790 
791     // disabled apn's still need avail/unavail notificiations - send them out
notifyOffApnsOfAvailability(String reason)792     protected void notifyOffApnsOfAvailability(String reason) {
793         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
794         for (int id = 0; id < APN_NUM_TYPES; id++) {
795             if (!isApnIdEnabled(id)) {
796                 notifyApnIdDisconnected(reason, id);
797             }
798         }
799     }
800 
isApnTypeEnabled(String apnType)801     public boolean isApnTypeEnabled(String apnType) {
802         if (apnType == null) {
803             return false;
804         } else {
805             return isApnIdEnabled(apnTypeToId(apnType));
806         }
807     }
808 
isApnIdEnabled(int id)809     protected synchronized boolean isApnIdEnabled(int id) {
810         if (id != APN_INVALID_ID) {
811             return dataEnabled[id];
812         }
813         return false;
814     }
815 
816     /**
817      * Ensure that we are connected to an APN of the specified type.
818      *
819      * @param type the APN type (currently the only valid values are
820      *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL})
821      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
822      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
823      *         broadcast will be sent by the ConnectivityManager when a
824      *         connection to the APN has been established.
825      */
enableApnType(String type)826     public synchronized int enableApnType(String type) {
827         int id = apnTypeToId(type);
828         if (id == APN_INVALID_ID) {
829             return Phone.APN_REQUEST_FAILED;
830         }
831 
832         if (DBG) {
833             log("enableApnType(" + type + "), isApnTypeActive = " + isApnTypeActive(type)
834                     + ", isApnIdEnabled =" + isApnIdEnabled(id) + " and state = " + mState);
835         }
836 
837         if (!isApnTypeAvailable(type)) {
838             if (DBG) log("type not available");
839             return Phone.APN_TYPE_NOT_AVAILABLE;
840         }
841 
842         if (isApnIdEnabled(id)) {
843             return Phone.APN_ALREADY_ACTIVE;
844         } else {
845             setEnabled(id, true);
846         }
847         return Phone.APN_REQUEST_STARTED;
848     }
849 
850     /**
851      * The APN of the specified type is no longer needed. Ensure that if use of
852      * the default APN has not been explicitly disabled, we are connected to the
853      * default APN.
854      *
855      * @param type the APN type. The only valid values are currently
856      *            {@link Phone#APN_TYPE_MMS} and {@link Phone#APN_TYPE_SUPL}.
857      * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
858      *         {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
859      *         broadcast will be sent by the ConnectivityManager when a
860      *         connection to the APN has been disconnected. A {@code
861      *         Phone.APN_REQUEST_FAILED} is returned if the type parameter is
862      *         invalid or if the apn wasn't enabled.
863      */
disableApnType(String type)864     public synchronized int disableApnType(String type) {
865         if (DBG) log("disableApnType(" + type + ")");
866         int id = apnTypeToId(type);
867         if (id == APN_INVALID_ID) {
868             return Phone.APN_REQUEST_FAILED;
869         }
870         if (isApnIdEnabled(id)) {
871             setEnabled(id, false);
872             if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
873                 if (dataEnabled[APN_DEFAULT_ID]) {
874                     return Phone.APN_ALREADY_ACTIVE;
875                 } else {
876                     return Phone.APN_REQUEST_STARTED;
877                 }
878             } else {
879                 return Phone.APN_REQUEST_STARTED;
880             }
881         } else {
882             return Phone.APN_REQUEST_FAILED;
883         }
884     }
885 
setEnabled(int id, boolean enable)886     protected void setEnabled(int id, boolean enable) {
887         if (DBG) {
888             log("setEnabled(" + id + ", " + enable + ") with old state = " + dataEnabled[id]
889                     + " and enabledCount = " + enabledCount);
890         }
891         Message msg = obtainMessage(EVENT_ENABLE_NEW_APN);
892         msg.arg1 = id;
893         msg.arg2 = (enable ? ENABLED : DISABLED);
894         sendMessage(msg);
895     }
896 
onEnableApn(int apnId, int enabled)897     protected void onEnableApn(int apnId, int enabled) {
898         if (DBG) {
899             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
900                     ", enabled=" + enabled + ", dataEnabled = " + dataEnabled[apnId] +
901                     ", enabledCount = " + enabledCount + ", isApnTypeActive = " +
902                     isApnTypeActive(apnIdToType(apnId)));
903         }
904         if (enabled == ENABLED) {
905             synchronized (this) {
906                 if (!dataEnabled[apnId]) {
907                     dataEnabled[apnId] = true;
908                     enabledCount++;
909                 }
910             }
911             String type = apnIdToType(apnId);
912             if (!isApnTypeActive(type)) {
913                 mRequestedApnType = type;
914                 onEnableNewApn();
915             } else {
916                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
917             }
918         } else {
919             // disable
920             boolean didDisable = false;
921             synchronized (this) {
922                 if (dataEnabled[apnId]) {
923                     dataEnabled[apnId] = false;
924                     enabledCount--;
925                     didDisable = true;
926                 }
927             }
928             if (didDisable && enabledCount == 0) {
929                 onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
930 
931                 // send the disconnect msg manually, since the normal route wont send
932                 // it (it's not enabled)
933                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
934                 if (dataEnabled[APN_DEFAULT_ID] == true
935                         && !isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
936                     // TODO - this is an ugly way to restore the default conn - should be done
937                     // by a real contention manager and policy that disconnects the lower pri
938                     // stuff as enable requests come in and pops them back on as we disable back
939                     // down to the lower pri stuff
940                     mRequestedApnType = Phone.APN_TYPE_DEFAULT;
941                     onEnableNewApn();
942                 }
943             }
944         }
945     }
946 
947     /**
948      * Called when we switch APNs.
949      *
950      * mRequestedApnType is set prior to call
951      * To be overridden.
952      */
onEnableNewApn()953     protected void onEnableNewApn() {
954     }
955 
956     /**
957      * Called when EVENT_RESET_DONE is received so goto
958      * IDLE state and send notifications to those interested.
959      *
960      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
961      * TODO - needs to pass some notion of which connection is reset..
962      */
onResetDone(AsyncResult ar)963     protected void onResetDone(AsyncResult ar) {
964         if (DBG) log("EVENT_RESET_DONE");
965         String reason = null;
966         if (ar.userObj instanceof String) {
967             reason = (String) ar.userObj;
968         }
969         gotoIdleAndNotifyDataConnection(reason);
970     }
971 
972     /**
973      * Prevent mobile data connections from being established, or once again
974      * allow mobile data connections. If the state toggles, then either tear
975      * down or set up data, as appropriate to match the new state.
976      *
977      * @param enable indicates whether to enable ({@code true}) or disable (
978      *            {@code false}) data
979      * @return {@code true} if the operation succeeded
980      */
setInternalDataEnabled(boolean enable)981     public boolean setInternalDataEnabled(boolean enable) {
982         if (DBG)
983             log("setInternalDataEnabled(" + enable + ")");
984 
985         Message msg = obtainMessage(EVENT_SET_INTERNAL_DATA_ENABLE);
986         msg.arg1 = (enable ? ENABLED : DISABLED);
987         sendMessage(msg);
988         return true;
989     }
990 
onSetInternalDataEnabled(boolean enabled)991     protected void onSetInternalDataEnabled(boolean enabled) {
992         synchronized (mDataEnabledLock) {
993             mInternalDataEnabled = enabled;
994             if (enabled) {
995                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
996                 resetAllRetryCounts();
997                 onTrySetupData(Phone.REASON_DATA_ENABLED);
998             } else {
999                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
1000                 cleanUpAllConnections(null);
1001             }
1002         }
1003     }
1004 
cleanUpAllConnections(String cause)1005     public void cleanUpAllConnections(String cause) {
1006         Message msg = obtainMessage(EVENT_CLEAN_UP_ALL_CONNECTIONS);
1007         msg.obj = cause;
1008         sendMessage(msg);
1009     }
1010 
isDisconnected()1011     public abstract boolean isDisconnected();
1012 
onSetUserDataEnabled(boolean enabled)1013     protected void onSetUserDataEnabled(boolean enabled) {
1014         synchronized (mDataEnabledLock) {
1015             final boolean prevEnabled = getAnyDataEnabled();
1016             if (mUserDataEnabled != enabled) {
1017                 mUserDataEnabled = enabled;
1018                 Settings.Secure.putInt(mPhone.getContext().getContentResolver(),
1019                         Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
1020                 if (prevEnabled != getAnyDataEnabled()) {
1021                     if (!prevEnabled) {
1022                         resetAllRetryCounts();
1023                         onTrySetupData(Phone.REASON_DATA_ENABLED);
1024                     } else {
1025                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
1026                     }
1027                 }
1028             }
1029         }
1030     }
1031 
onSetDependencyMet(String apnType, boolean met)1032     protected void onSetDependencyMet(String apnType, boolean met) {
1033     }
1034 
onSetPolicyDataEnabled(boolean enabled)1035     protected void onSetPolicyDataEnabled(boolean enabled) {
1036         synchronized (mDataEnabledLock) {
1037             final boolean prevEnabled = getAnyDataEnabled();
1038             if (mPolicyDataEnabled != enabled) {
1039                 mPolicyDataEnabled = enabled;
1040                 if (prevEnabled != getAnyDataEnabled()) {
1041                     if (!prevEnabled) {
1042                         resetAllRetryCounts();
1043                         onTrySetupData(Phone.REASON_DATA_ENABLED);
1044                     } else {
1045                         onCleanUpAllConnections(Phone.REASON_DATA_DISABLED);
1046                     }
1047                 }
1048             }
1049         }
1050     }
1051 
getReryConfig(boolean forDefault)1052     protected String getReryConfig(boolean forDefault) {
1053         int rt = mPhone.getServiceState().getRadioTechnology();
1054 
1055         if ((rt == ServiceState.RADIO_TECHNOLOGY_IS95A) ||
1056             (rt == ServiceState.RADIO_TECHNOLOGY_IS95B) ||
1057             (rt == ServiceState.RADIO_TECHNOLOGY_1xRTT) ||
1058             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_0) ||
1059             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_A) ||
1060             (rt == ServiceState.RADIO_TECHNOLOGY_EVDO_B) ||
1061             (rt == ServiceState.RADIO_TECHNOLOGY_EHRPD)) {
1062             // CDMA variant
1063             return SystemProperties.get("ro.cdma.data_retry_config");
1064         } else {
1065             // Use GSM varient for all others.
1066             if (forDefault) {
1067                 return SystemProperties.get("ro.gsm.data_retry_config");
1068             } else {
1069                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
1070             }
1071         }
1072     }
1073 
resetAllRetryCounts()1074     protected void resetAllRetryCounts() {
1075         for (DataConnection dc : mDataConnections.values()) {
1076             dc.resetRetryCount();
1077         }
1078     }
1079 }
1080