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.dataconnection;
18 
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.BroadcastReceiver;
22 import android.content.ContentResolver;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.content.SharedPreferences;
27 import android.database.ContentObserver;
28 import android.net.ConnectivityManager;
29 import android.net.LinkProperties;
30 import android.net.NetworkCapabilities;
31 import android.net.NetworkInfo;
32 import android.net.TrafficStats;
33 import android.net.wifi.WifiManager;
34 import android.os.AsyncResult;
35 import android.os.Build;
36 import android.os.Bundle;
37 import android.os.Handler;
38 import android.os.HandlerThread;
39 import android.os.Message;
40 import android.os.SystemClock;
41 import android.os.SystemProperties;
42 import android.preference.PreferenceManager;
43 import android.provider.Settings;
44 import android.provider.Settings.SettingNotFoundException;
45 import android.telephony.SubscriptionManager;
46 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
47 import android.telephony.TelephonyManager;
48 import android.text.TextUtils;
49 import android.util.EventLog;
50 import android.telephony.Rlog;
51 
52 import com.android.internal.R;
53 import com.android.internal.telephony.DctConstants;
54 import com.android.internal.telephony.EventLogTags;
55 import com.android.internal.telephony.Phone;
56 import com.android.internal.telephony.PhoneBase;
57 import com.android.internal.telephony.PhoneConstants;
58 import com.android.internal.telephony.uicc.IccRecords;
59 import com.android.internal.telephony.uicc.UiccController;
60 import com.android.internal.util.AsyncChannel;
61 import com.android.internal.util.ArrayUtils;
62 
63 import java.io.FileDescriptor;
64 import java.io.PrintWriter;
65 import java.util.ArrayList;
66 import java.util.Comparator;
67 import java.util.HashMap;
68 import java.util.List;
69 import java.util.Map.Entry;
70 import java.util.Set;
71 import java.util.concurrent.ConcurrentHashMap;
72 import java.util.concurrent.atomic.AtomicInteger;
73 import java.util.concurrent.atomic.AtomicReference;
74 import java.util.PriorityQueue;
75 
76 /**
77  * {@hide}
78  */
79 public abstract class DcTrackerBase extends Handler {
80     protected static final boolean DBG = true;
81     protected static final boolean VDBG = false; // STOPSHIP if true
82     protected static final boolean VDBG_STALL = true; // STOPSHIP if true
83     protected static final boolean RADIO_TESTS = false;
84 
85     static boolean mIsCleanupRequired = false;
86     /**
87      * Constants for the data connection activity:
88      * physical link down/up
89      */
90     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_INACTIVE = 0;
91     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_DOWN = 1;
92     protected static final int DATA_CONNECTION_ACTIVE_PH_LINK_UP = 2;
93 
94     /** Delay between APN attempts.
95         Note the property override mechanism is there just for testing purpose only. */
96     protected static final int APN_DELAY_DEFAULT_MILLIS = 20000;
97 
98     /** Delay between APN attempts when in fail fast mode */
99     protected static final int APN_FAIL_FAST_DELAY_DEFAULT_MILLIS = 3000;
100 
101     AlarmManager mAlarmManager;
102 
103     protected Object mDataEnabledLock = new Object();
104 
105     // responds to the setInternalDataEnabled call - used internally to turn off data
106     // for example during emergency calls
107     protected boolean mInternalDataEnabled = true;
108 
109     // responds to public (user) API to enable/disable data use
110     // independent of mInternalDataEnabled and requests for APN access
111     // persisted
112     protected boolean mUserDataEnabled = true;
113 
114     // TODO: move away from static state once 5587429 is fixed.
115     protected static boolean sPolicyDataEnabled = true;
116 
117     private boolean[] mDataEnabled = new boolean[DctConstants.APN_NUM_TYPES];
118 
119     private int mEnabledCount = 0;
120 
121     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
122     protected String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
123 
124     /** Retry configuration: A doubling of retry times from 5secs to 30minutes */
125     protected static final String DEFAULT_DATA_RETRY_CONFIG = "default_randomization=2000,"
126         + "5000,10000,20000,40000,80000:5000,160000:5000,"
127         + "320000:5000,640000:5000,1280000:5000,1800000:5000";
128 
129     /** Retry configuration for secondary networks: 4 tries in 20 sec */
130     protected static final String SECONDARY_DATA_RETRY_CONFIG =
131             "max_retries=3, 5000, 5000, 5000";
132 
133     /** Slow poll when attempting connection recovery. */
134     protected static final int POLL_NETSTAT_SLOW_MILLIS = 5000;
135     /** Default max failure count before attempting to network re-registration. */
136     protected static final int DEFAULT_MAX_PDP_RESET_FAIL = 3;
137 
138     /**
139      * After detecting a potential connection problem, this is the max number
140      * of subsequent polls before attempting recovery.
141      */
142     protected static final int NO_RECV_POLL_LIMIT = 24;
143     // 1 sec. default polling interval when screen is on.
144     protected static final int POLL_NETSTAT_MILLIS = 1000;
145     // 10 min. default polling interval when screen is off.
146     protected static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
147     // 2 min for round trip time
148     protected static final int POLL_LONGEST_RTT = 120 * 1000;
149     // Default sent packets without ack which triggers initial recovery steps
150     protected static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
151     // how long to wait before switching back to default APN
152     protected static final int RESTORE_DEFAULT_APN_DELAY = 1 * 60 * 1000;
153     // system property that can override the above value
154     protected static final String APN_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore";
155     // represents an invalid IP address
156     protected static final String NULL_IP = "0.0.0.0";
157 
158     // Default for the data stall alarm while non-aggressive stall detection
159     protected static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
160     // Default for the data stall alarm for aggressive stall detection
161     protected static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
162     // If attempt is less than this value we're doing first level recovery
163     protected static final int DATA_STALL_NO_RECV_POLL_LIMIT = 1;
164     // Tag for tracking stale alarms
165     protected static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag";
166 
167     protected static final boolean DATA_STALL_SUSPECTED = true;
168     protected static final boolean DATA_STALL_NOT_SUSPECTED = false;
169 
170     protected String RADIO_RESET_PROPERTY = "gsm.radioreset";
171 
172     protected static final String INTENT_RECONNECT_ALARM =
173             "com.android.internal.telephony.data-reconnect";
174     protected static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
175     protected static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
176             "reconnect_alarm_extra_reason";
177 
178     protected static final String INTENT_RESTART_TRYSETUP_ALARM =
179             "com.android.internal.telephony.data-restart-trysetup";
180     protected static final String INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE =
181             "restart_trysetup_alarm_extra_type";
182 
183     protected static final String INTENT_DATA_STALL_ALARM =
184             "com.android.internal.telephony.data-stall";
185 
186 
187 
188     protected static final String DEFALUT_DATA_ON_BOOT_PROP = "net.def_data_on_boot";
189 
190     protected DcTesterFailBringUpAll mDcTesterFailBringUpAll;
191     protected DcController mDcc;
192 
193     // member variables
194     protected PhoneBase mPhone;
195     protected UiccController mUiccController;
196     protected AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
197     protected DctConstants.Activity mActivity = DctConstants.Activity.NONE;
198     protected DctConstants.State mState = DctConstants.State.IDLE;
199     protected Handler mDataConnectionTracker = null;
200 
201     protected long mTxPkts;
202     protected long mRxPkts;
203     protected int mNetStatPollPeriod;
204     protected boolean mNetStatPollEnabled = false;
205 
206     protected TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
207     // Used to track stale data stall alarms.
208     protected int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
209     // The current data stall alarm intent
210     protected PendingIntent mDataStallAlarmIntent = null;
211     // Number of packets sent since the last received packet
212     protected long mSentSinceLastRecv;
213     // Controls when a simple recovery attempt it to be tried
214     protected int mNoRecvPollCount = 0;
215     // Refrence counter for enabling fail fast
216     protected static int sEnableFailFastRefCounter = 0;
217     // True if data stall detection is enabled
218     protected volatile boolean mDataStallDetectionEnabled = true;
219 
220     protected volatile boolean mFailFast = false;
221 
222     // True when in voice call
223     protected boolean mInVoiceCall = false;
224 
225     // wifi connection status will be updated by sticky intent
226     protected boolean mIsWifiConnected = false;
227 
228     /** Intent sent when the reconnect alarm fires. */
229     protected PendingIntent mReconnectIntent = null;
230 
231     /** CID of active data connection */
232     protected int mCidActive;
233 
234     // When false we will not auto attach and manually attaching is required.
235     protected boolean mAutoAttachOnCreationConfig = false;
236     protected boolean mAutoAttachOnCreation = false;
237 
238     // State of screen
239     // (TODO: Reconsider tying directly to screen, maybe this is
240     //        really a lower power mode")
241     protected boolean mIsScreenOn = true;
242 
243     /** Allows the generation of unique Id's for DataConnection objects */
244     protected AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
245 
246     /** The data connections. */
247     protected HashMap<Integer, DataConnection> mDataConnections =
248         new HashMap<Integer, DataConnection>();
249 
250     /** The data connection async channels */
251     protected HashMap<Integer, DcAsyncChannel> mDataConnectionAcHashMap =
252         new HashMap<Integer, DcAsyncChannel>();
253 
254     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
255     protected HashMap<String, Integer> mApnToDataConnectionId =
256                                     new HashMap<String, Integer>();
257 
258     /** Phone.APN_TYPE_* ===> ApnContext */
259     protected final ConcurrentHashMap<String, ApnContext> mApnContexts =
260                                     new ConcurrentHashMap<String, ApnContext>();
261 
262     /** kept in sync with mApnContexts
263      * Higher numbers are higher priority and sorted so highest priority is first */
264     protected final PriorityQueue<ApnContext>mPrioritySortedApnContexts =
265             new PriorityQueue<ApnContext>(5,
266             new Comparator<ApnContext>() {
267                 public int compare(ApnContext c1, ApnContext c2) {
268                     return c2.priority - c1.priority;
269                 }
270             } );
271 
272     /* Currently active APN */
273     protected ApnSetting mActiveApn;
274 
275     /** allApns holds all apns */
276     protected ArrayList<ApnSetting> mAllApnSettings = null;
277 
278     /** preferred apn */
279     protected ApnSetting mPreferredApn = null;
280 
281     /** Is packet service restricted by network */
282     protected boolean mIsPsRestricted = false;
283 
284     /** emergency apn Setting*/
285     protected ApnSetting mEmergencyApn = null;
286 
287     /* Once disposed dont handle any messages */
288     protected boolean mIsDisposed = false;
289 
290     protected ContentResolver mResolver;
291 
292     /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */
293     protected boolean mIsProvisioning = false;
294 
295     /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */
296     protected String mProvisioningUrl = null;
297 
298     /* Intent for the provisioning apn alarm */
299     protected static final String INTENT_PROVISIONING_APN_ALARM =
300             "com.android.internal.telephony.provisioning_apn_alarm";
301 
302     /* Tag for tracking stale alarms */
303     protected static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag";
304 
305     /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */
306     protected static final String DEBUG_PROV_APN_ALARM =
307             "persist.debug.prov_apn_alarm";
308 
309     /* Default for the provisioning apn alarm timeout */
310     protected static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15;
311 
312     /* The provision apn alarm intent used to disable the provisioning apn */
313     protected PendingIntent mProvisioningApnAlarmIntent = null;
314 
315     /* Used to track stale provisioning apn alarms */
316     protected int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime();
317 
318     protected AsyncChannel mReplyAc = new AsyncChannel();
319 
320     protected BroadcastReceiver mIntentReceiver = new BroadcastReceiver ()
321     {
322         @Override
323         public void onReceive(Context context, Intent intent)
324         {
325             String action = intent.getAction();
326             if (DBG) log("onReceive: action=" + action);
327             if (action.equals(Intent.ACTION_SCREEN_ON)) {
328                 mIsScreenOn = true;
329                 stopNetStatPoll();
330                 startNetStatPoll();
331                 restartDataStallAlarm();
332             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
333                 mIsScreenOn = false;
334                 stopNetStatPoll();
335                 startNetStatPoll();
336                 restartDataStallAlarm();
337             } else if (action.startsWith(INTENT_RECONNECT_ALARM)) {
338                 if (DBG) log("Reconnect alarm. Previous state was " + mState);
339                 onActionIntentReconnectAlarm(intent);
340             } else if (action.startsWith(INTENT_RESTART_TRYSETUP_ALARM)) {
341                 if (DBG) log("Restart trySetup alarm");
342                 onActionIntentRestartTrySetupAlarm(intent);
343             } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
344                 onActionIntentDataStallAlarm(intent);
345             } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) {
346                 onActionIntentProvisioningApnAlarm(intent);
347             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
348                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
349                         intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
350                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
351                 if (DBG) log("NETWORK_STATE_CHANGED_ACTION: mIsWifiConnected=" + mIsWifiConnected);
352             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
353                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
354                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
355 
356                 if (!enabled) {
357                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
358                     // quit and won't report disconnected until next enabling.
359                     mIsWifiConnected = false;
360                 }
361                 if (DBG) log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled
362                         + " mIsWifiConnected=" + mIsWifiConnected);
363             }
364         }
365     };
366 
367     private Runnable mPollNetStat = new Runnable()
368     {
369         @Override
370         public void run() {
371             updateDataActivity();
372 
373             if (mIsScreenOn) {
374                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
375                         Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
376             } else {
377                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
378                         Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
379                         POLL_NETSTAT_SCREEN_OFF_MILLIS);
380             }
381 
382             if (mNetStatPollEnabled) {
383                 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
384             }
385         }
386     };
387 
388     private SubscriptionManager mSubscriptionManager;
389     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
390             new OnSubscriptionsChangedListener() {
391         /**
392          * Callback invoked when there is any change to any SubscriptionInfo. Typically
393          * this method would invoke {@link SubscriptionManager#getActiveSubscriptionInfoList}
394          */
395         @Override
396         public void onSubscriptionsChanged() {
397             if (DBG) log("SubscriptionListener.onSubscriptionInfoChanged");
398             // Set the network type, in case the radio does not restore it.
399             int subId = mPhone.getSubId();
400             if (SubscriptionManager.isValidSubscriptionId(subId)) {
401                 if (mDataRoamingSettingObserver != null) {
402                     mDataRoamingSettingObserver.unregister();
403                 }
404                 // Watch for changes to Settings.Global.DATA_ROAMING
405                 mDataRoamingSettingObserver = new DataRoamingSettingObserver(mPhone,
406                         mPhone.getContext());
407                 mDataRoamingSettingObserver.register();
408             }
409         }
410     };
411 
412     private class DataRoamingSettingObserver extends ContentObserver {
413 
DataRoamingSettingObserver(Handler handler, Context context)414         public DataRoamingSettingObserver(Handler handler, Context context) {
415             super(handler);
416             mResolver = context.getContentResolver();
417         }
418 
register()419         public void register() {
420             String contentUri;
421             if (TelephonyManager.getDefault().getSimCount() == 1) {
422                 contentUri = Settings.Global.DATA_ROAMING;
423             } else {
424                 contentUri = Settings.Global.DATA_ROAMING + mPhone.getSubId();
425             }
426 
427             mResolver.registerContentObserver(Settings.Global.getUriFor(contentUri), false, this);
428         }
429 
unregister()430         public void unregister() {
431             mResolver.unregisterContentObserver(this);
432         }
433 
434         @Override
onChange(boolean selfChange)435         public void onChange(boolean selfChange) {
436             // already running on mPhone handler thread
437             if (mPhone.getServiceState().getDataRoaming()) {
438                 sendMessage(obtainMessage(DctConstants.EVENT_ROAMING_ON));
439             }
440         }
441     }
442     private DataRoamingSettingObserver mDataRoamingSettingObserver;
443 
444     /**
445      * The Initial MaxRetry sent to a DataConnection as a parameter
446      * to DataConnectionAc.bringUp. This value can be defined at compile
447      * time using the SystemProperty Settings.Global.DCT_INITIAL_MAX_RETRY
448      * and at runtime using gservices to change Settings.Global.DCT_INITIAL_MAX_RETRY.
449      */
450     private static final int DEFAULT_MDC_INITIAL_RETRY = 1;
getInitialMaxRetry()451     protected int getInitialMaxRetry() {
452         if (mFailFast) {
453             return 0;
454         }
455         // Get default value from system property or use DEFAULT_MDC_INITIAL_RETRY
456         int value = SystemProperties.getInt(
457                 Settings.Global.MDC_INITIAL_MAX_RETRY, DEFAULT_MDC_INITIAL_RETRY);
458 
459         // Check if its been overridden
460         return Settings.Global.getInt(mResolver,
461                 Settings.Global.MDC_INITIAL_MAX_RETRY, value);
462     }
463 
464     /**
465      * Maintain the sum of transmit and receive packets.
466      *
467      * The packet counts are initialized and reset to -1 and
468      * remain -1 until they can be updated.
469      */
470     public class TxRxSum {
471         public long txPkts;
472         public long rxPkts;
473 
TxRxSum()474         public TxRxSum() {
475             reset();
476         }
477 
TxRxSum(long txPkts, long rxPkts)478         public TxRxSum(long txPkts, long rxPkts) {
479             this.txPkts = txPkts;
480             this.rxPkts = rxPkts;
481         }
482 
TxRxSum(TxRxSum sum)483         public TxRxSum(TxRxSum sum) {
484             txPkts = sum.txPkts;
485             rxPkts = sum.rxPkts;
486         }
487 
reset()488         public void reset() {
489             txPkts = -1;
490             rxPkts = -1;
491         }
492 
493         @Override
toString()494         public String toString() {
495             return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
496         }
497 
updateTxRxSum()498         public void updateTxRxSum() {
499             this.txPkts = TrafficStats.getMobileTcpTxPackets();
500             this.rxPkts = TrafficStats.getMobileTcpRxPackets();
501         }
502     }
503 
onActionIntentReconnectAlarm(Intent intent)504     protected void onActionIntentReconnectAlarm(Intent intent) {
505         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
506         String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
507 
508         int phoneSubId = mPhone.getSubId();
509         int currSubId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
510                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
511         log("onActionIntentReconnectAlarm: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
512 
513         // Stop reconnect if not current subId is not correct.
514         // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
515         if (!SubscriptionManager.isValidSubscriptionId(currSubId) || (currSubId != phoneSubId)) {
516             log("receive ReconnectAlarm but subId incorrect, ignore");
517             return;
518         }
519 
520         ApnContext apnContext = mApnContexts.get(apnType);
521 
522         if (DBG) {
523             log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
524                     " apnType=" + apnType + " apnContext=" + apnContext +
525                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
526         }
527 
528         if ((apnContext != null) && (apnContext.isEnabled())) {
529             apnContext.setReason(reason);
530             DctConstants.State apnContextState = apnContext.getState();
531             if (DBG) {
532                 log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
533             }
534             if ((apnContextState == DctConstants.State.FAILED)
535                     || (apnContextState == DctConstants.State.IDLE)) {
536                 if (DBG) {
537                     log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
538                 }
539                 DcAsyncChannel dcac = apnContext.getDcAc();
540                 if (dcac != null) {
541                     if (DBG) {
542                         log("onActionIntentReconnectAlarm: tearDown apnContext=" + apnContext);
543                     }
544                     dcac.tearDown(apnContext, "", null);
545                 }
546                 apnContext.setDataConnectionAc(null);
547                 apnContext.setState(DctConstants.State.IDLE);
548             } else {
549                 if (DBG) log("onActionIntentReconnectAlarm: keep associated");
550             }
551             // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
552             sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
553 
554             apnContext.setReconnectIntent(null);
555         }
556     }
557 
onActionIntentRestartTrySetupAlarm(Intent intent)558     protected void onActionIntentRestartTrySetupAlarm(Intent intent) {
559         String apnType = intent.getStringExtra(INTENT_RESTART_TRYSETUP_ALARM_EXTRA_TYPE);
560         ApnContext apnContext = mApnContexts.get(apnType);
561         if (DBG) {
562             log("onActionIntentRestartTrySetupAlarm: mState=" + mState +
563                     " apnType=" + apnType + " apnContext=" + apnContext +
564                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
565         }
566         sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
567     }
568 
onActionIntentDataStallAlarm(Intent intent)569     protected void onActionIntentDataStallAlarm(Intent intent) {
570         if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
571         Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM,
572                 intent.getAction());
573         msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
574         sendMessage(msg);
575     }
576 
577     ConnectivityManager mCm;
578 
579     /**
580      * Default constructor
581      */
DcTrackerBase(PhoneBase phone)582     protected DcTrackerBase(PhoneBase phone) {
583         super();
584         mPhone = phone;
585         if (DBG) log("DCT.constructor");
586         mResolver = mPhone.getContext().getContentResolver();
587         mUiccController = UiccController.getInstance();
588         mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
589         mAlarmManager =
590                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
591         mCm = (ConnectivityManager) mPhone.getContext().getSystemService(
592                 Context.CONNECTIVITY_SERVICE);
593 
594 
595         int phoneSubId = mPhone.getSubId();
596         IntentFilter filter = new IntentFilter();
597         filter.addAction(Intent.ACTION_SCREEN_ON);
598         filter.addAction(Intent.ACTION_SCREEN_OFF);
599         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
600         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
601         filter.addAction(INTENT_DATA_STALL_ALARM);
602         filter.addAction(INTENT_PROVISIONING_APN_ALARM);
603 
604         mUserDataEnabled = getDataEnabled();
605 
606         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
607 
608         // This preference tells us 1) initial condition for "dataEnabled",
609         // and 2) whether the RIL will setup the baseband to auto-PS attach.
610 
611         mDataEnabled[DctConstants.APN_DEFAULT_ID] =
612                 SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP,true);
613         if (mDataEnabled[DctConstants.APN_DEFAULT_ID]) {
614             mEnabledCount++;
615         }
616 
617         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
618         mAutoAttachOnCreation = sp.getBoolean(PhoneBase.DATA_DISABLED_ON_BOOT_KEY, false);
619 
620         mSubscriptionManager = SubscriptionManager.from(mPhone.getContext());
621         mSubscriptionManager
622                 .addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
623 
624         HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
625         dcHandlerThread.start();
626         Handler dcHandler = new Handler(dcHandlerThread.getLooper());
627         mDcc = DcController.makeDcc(mPhone, this, dcHandler);
628         mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler);
629     }
630 
dispose()631     public void dispose() {
632         if (DBG) log("DCT.dispose");
633         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
634             dcac.disconnect();
635         }
636         mDataConnectionAcHashMap.clear();
637         mIsDisposed = true;
638         mPhone.getContext().unregisterReceiver(mIntentReceiver);
639         mUiccController.unregisterForIccChanged(this);
640         if (mDataRoamingSettingObserver != null) {
641             mDataRoamingSettingObserver.unregister();
642         }
643         mSubscriptionManager
644                 .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
645         mDcc.dispose();
646         mDcTesterFailBringUpAll.dispose();
647     }
648 
getSubId()649     public long getSubId() {
650         return mPhone.getSubId();
651     }
652 
getActivity()653     public DctConstants.Activity getActivity() {
654         return mActivity;
655     }
656 
setActivity(DctConstants.Activity activity)657     void setActivity(DctConstants.Activity activity) {
658         log("setActivity = " + activity);
659         mActivity = activity;
660         mPhone.notifyDataActivity();
661     }
662 
incApnRefCount(String name)663     public void incApnRefCount(String name) {
664 
665     }
666 
decApnRefCount(String name)667     public void decApnRefCount(String name) {
668 
669     }
670 
isApnSupported(String name)671     public boolean isApnSupported(String name) {
672         return false;
673     }
674 
getApnPriority(String name)675     public int getApnPriority(String name) {
676         return -1;
677     }
678 
679 
isApnTypeActive(String type)680     public boolean isApnTypeActive(String type) {
681         // TODO: support simultaneous with List instead
682         if (PhoneConstants.APN_TYPE_DUN.equals(type)) {
683             ApnSetting dunApn = fetchDunApn();
684             if (dunApn != null) {
685                 return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
686             }
687         }
688         return mActiveApn != null && mActiveApn.canHandleType(type);
689     }
690 
fetchDunApn()691     protected ApnSetting fetchDunApn() {
692         if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
693             log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
694             return null;
695         }
696         int bearer = -1;
697         ApnSetting retDunSetting = null;
698         String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN);
699         List<ApnSetting> dunSettings = ApnSetting.arrayFromString(apnData);
700         IccRecords r = mIccRecords.get();
701         for (ApnSetting dunSetting : dunSettings) {
702             String operator = (r != null) ? r.getOperatorNumeric() : "";
703             if (dunSetting.bearer != 0) {
704                 if (bearer == -1) bearer = mPhone.getServiceState().getRilDataRadioTechnology();
705                 if (dunSetting.bearer != bearer) continue;
706             }
707             if (dunSetting.numeric.equals(operator)) {
708                 if (dunSetting.hasMvnoParams()) {
709                     if (r != null &&
710                             mvnoMatches(r, dunSetting.mvnoType, dunSetting.mvnoMatchData)) {
711                         if (VDBG) {
712                             log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
713                         }
714                         return dunSetting;
715                     }
716                 } else {
717                     if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
718                     return dunSetting;
719                 }
720             }
721         }
722 
723         Context c = mPhone.getContext();
724         String[] apnArrayData = c.getResources().getStringArray(R.array.config_tether_apndata);
725         for (String apn : apnArrayData) {
726             ApnSetting dunSetting = ApnSetting.fromString(apn);
727             if (dunSetting != null) {
728                 if (dunSetting.bearer != 0) {
729                     if (bearer == -1) bearer = mPhone.getServiceState().getRilDataRadioTechnology();
730                     if (dunSetting.bearer != bearer) continue;
731                 }
732                 if (dunSetting.hasMvnoParams()) {
733                     if (r != null &&
734                             mvnoMatches(r, dunSetting.mvnoType, dunSetting.mvnoMatchData)) {
735                         if (VDBG) log("fetchDunApn: config_tether_apndata mvno dunSetting="
736                                 + dunSetting);
737                         return dunSetting;
738                     }
739                 } else {
740                     retDunSetting = dunSetting;
741                 }
742             }
743         }
744 
745         if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + retDunSetting);
746         return retDunSetting;
747     }
748 
hasMatchedTetherApnSetting()749     public boolean hasMatchedTetherApnSetting() {
750         ApnSetting matched = fetchDunApn();
751         log("hasMatchedTetherApnSetting: APN=" + matched);
752         return matched != null;
753     }
754 
getActiveApnTypes()755     public String[] getActiveApnTypes() {
756         String[] result;
757         if (mActiveApn != null) {
758             result = mActiveApn.types;
759         } else {
760             result = new String[1];
761             result[0] = PhoneConstants.APN_TYPE_DEFAULT;
762         }
763         return result;
764     }
765 
766     /** TODO: See if we can remove */
getActiveApnString(String apnType)767     public String getActiveApnString(String apnType) {
768         String result = null;
769         if (mActiveApn != null) {
770             result = mActiveApn.apn;
771         }
772         return result;
773     }
774 
775     /**
776      * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value.
777      */
setDataOnRoamingEnabled(boolean enabled)778     public void setDataOnRoamingEnabled(boolean enabled) {
779         final int phoneSubId = mPhone.getSubId();
780         if (getDataOnRoamingEnabled() != enabled) {
781             int roaming = enabled ? 1 : 0;
782 
783             // For single SIM phones, this is a per phone property.
784             if (TelephonyManager.getDefault().getSimCount() == 1) {
785                 Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING, roaming);
786             } else {
787                 Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING + phoneSubId, roaming);
788             }
789 
790             mSubscriptionManager.setDataRoaming(roaming, phoneSubId);
791             // will trigger handleDataOnRoamingChange() through observer
792             if (DBG) {
793                log("setDataOnRoamingEnabled: set phoneSubId=" + phoneSubId
794                        + " isRoaming=" + enabled);
795             }
796         } else {
797             if (DBG) {
798                 log("setDataOnRoamingEnabled: unchanged phoneSubId=" + phoneSubId
799                         + " isRoaming=" + enabled);
800              }
801         }
802     }
803 
804     /**
805      * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
806      */
getDataOnRoamingEnabled()807     public boolean getDataOnRoamingEnabled() {
808         boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get(
809                 "ro.com.android.dataroaming", "false"));
810         final int phoneSubId = mPhone.getSubId();
811 
812         try {
813             // For single SIM phones, this is a per phone property.
814             if (TelephonyManager.getDefault().getSimCount() == 1) {
815                 isDataRoamingEnabled = Settings.Global.getInt(mResolver,
816                         Settings.Global.DATA_ROAMING, isDataRoamingEnabled ? 1 : 0) != 0;
817             } else {
818                 isDataRoamingEnabled = TelephonyManager.getIntWithSubId(mResolver,
819                         Settings.Global.DATA_ROAMING, phoneSubId) != 0;
820             }
821         } catch (SettingNotFoundException snfe) {
822             if (DBG) log("getDataOnRoamingEnabled: SettingNofFoundException snfe=" + snfe);
823         }
824         if (DBG) {
825             log("getDataOnRoamingEnabled: phoneSubId=" + phoneSubId +
826                     " isDataRoamingEnabled=" + isDataRoamingEnabled);
827         }
828         return isDataRoamingEnabled;
829     }
830 
831     /**
832      * Modify {@link android.provider.Settings.Global#MOBILE_DATA} value.
833      */
setDataEnabled(boolean enable)834     public void setDataEnabled(boolean enable) {
835         Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE);
836         msg.arg1 = enable ? 1 : 0;
837         if (DBG) log("setDataEnabled: sendMessage: enable=" + enable);
838         sendMessage(msg);
839     }
840 
841     /**
842      * Return current {@link android.provider.Settings.Global#MOBILE_DATA} value.
843      */
getDataEnabled()844     public boolean getDataEnabled() {
845         boolean retVal = "true".equalsIgnoreCase(SystemProperties.get(
846                 "ro.com.android.mobiledata", "true"));
847         try {
848             if (TelephonyManager.getDefault().getSimCount() == 1) {
849                 retVal = Settings.Global.getInt(mResolver, Settings.Global.MOBILE_DATA,
850                         retVal ? 1 : 0) != 0;
851             } else {
852                 int phoneSubId = mPhone.getSubId();
853                 retVal = TelephonyManager.getIntWithSubId(mResolver, Settings.Global.MOBILE_DATA,
854                         phoneSubId) != 0;
855             }
856             if (DBG) log("getDataEnabled: getIntWithSubId retVal=" + retVal);
857         } catch (SettingNotFoundException snfe) {
858             retVal = "true".equalsIgnoreCase(
859                     SystemProperties.get("ro.com.android.mobiledata", "true"));
860             if (DBG) {
861                 log("getDataEnabled: system property ro.com.android.mobiledata retVal=" + retVal);
862             }
863         }
864         return retVal;
865     }
866 
867     // abstract methods
restartRadio()868     protected abstract void restartRadio();
log(String s)869     protected abstract void log(String s);
loge(String s)870     protected abstract void loge(String s);
isDataAllowed()871     protected abstract boolean isDataAllowed();
isApnTypeAvailable(String type)872     protected abstract boolean isApnTypeAvailable(String type);
getState(String apnType)873     public    abstract DctConstants.State getState(String apnType);
isProvisioningApn(String apnType)874     protected abstract boolean isProvisioningApn(String apnType);
setState(DctConstants.State s)875     protected abstract void setState(DctConstants.State s);
gotoIdleAndNotifyDataConnection(String reason)876     protected abstract void gotoIdleAndNotifyDataConnection(String reason);
877 
onTrySetupData(String reason)878     protected abstract boolean onTrySetupData(String reason);
onRoamingOff()879     protected abstract void onRoamingOff();
onRoamingOn()880     protected abstract void onRoamingOn();
onRadioAvailable()881     protected abstract void onRadioAvailable();
onRadioOffOrNotAvailable()882     protected abstract void onRadioOffOrNotAvailable();
onDataSetupComplete(AsyncResult ar)883     protected abstract void onDataSetupComplete(AsyncResult ar);
onDataSetupCompleteError(AsyncResult ar)884     protected abstract void onDataSetupCompleteError(AsyncResult ar);
onDisconnectDone(int connId, AsyncResult ar)885     protected abstract void onDisconnectDone(int connId, AsyncResult ar);
onDisconnectDcRetrying(int connId, AsyncResult ar)886     protected abstract void onDisconnectDcRetrying(int connId, AsyncResult ar);
onVoiceCallStarted()887     protected abstract void onVoiceCallStarted();
onVoiceCallEnded()888     protected abstract void onVoiceCallEnded();
onCleanUpConnection(boolean tearDown, int apnId, String reason)889     protected abstract void onCleanUpConnection(boolean tearDown, int apnId, String reason);
onCleanUpAllConnections(String cause)890     protected abstract void onCleanUpAllConnections(String cause);
isDataPossible(String apnType)891     public abstract boolean isDataPossible(String apnType);
onUpdateIcc()892     protected abstract void onUpdateIcc();
completeConnection(ApnContext apnContext)893     protected abstract void completeConnection(ApnContext apnContext);
setDataAllowed(boolean enable, Message response)894     public abstract void setDataAllowed(boolean enable, Message response);
getPcscfAddress(String apnType)895     public abstract String[] getPcscfAddress(String apnType);
setImsRegistrationState(boolean registered)896     public abstract void setImsRegistrationState(boolean registered);
mvnoMatches(IccRecords r, String mvno_type, String mvno_match_data)897     protected abstract boolean mvnoMatches(IccRecords r, String mvno_type, String mvno_match_data);
isPermanentFail(DcFailCause dcFailCause)898     protected abstract boolean isPermanentFail(DcFailCause dcFailCause);
899 
900     @Override
handleMessage(Message msg)901     public void handleMessage(Message msg) {
902         switch (msg.what) {
903             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
904                 log("DISCONNECTED_CONNECTED: msg=" + msg);
905                 DcAsyncChannel dcac = (DcAsyncChannel) msg.obj;
906                 mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync());
907                 dcac.disconnected();
908                 break;
909             }
910             case DctConstants.EVENT_ENABLE_NEW_APN:
911                 onEnableApn(msg.arg1, msg.arg2);
912                 break;
913 
914             case DctConstants.EVENT_TRY_SETUP_DATA:
915                 String reason = null;
916                 if (msg.obj instanceof String) {
917                     reason = (String) msg.obj;
918                 }
919                 onTrySetupData(reason);
920                 break;
921 
922             case DctConstants.EVENT_DATA_STALL_ALARM:
923                 onDataStallAlarm(msg.arg1);
924                 break;
925 
926             case DctConstants.EVENT_ROAMING_OFF:
927                 onRoamingOff();
928                 break;
929 
930             case DctConstants.EVENT_ROAMING_ON:
931                 onRoamingOn();
932                 break;
933 
934             case DctConstants.EVENT_RADIO_AVAILABLE:
935                 onRadioAvailable();
936                 break;
937 
938             case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
939                 onRadioOffOrNotAvailable();
940                 break;
941 
942             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
943                 mCidActive = msg.arg1;
944                 onDataSetupComplete((AsyncResult) msg.obj);
945                 break;
946 
947             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
948                 onDataSetupCompleteError((AsyncResult) msg.obj);
949                 break;
950 
951             case DctConstants.EVENT_DISCONNECT_DONE:
952                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
953                 onDisconnectDone(msg.arg1, (AsyncResult) msg.obj);
954                 break;
955 
956             case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
957                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
958                 onDisconnectDcRetrying(msg.arg1, (AsyncResult) msg.obj);
959                 break;
960 
961             case DctConstants.EVENT_VOICE_CALL_STARTED:
962                 onVoiceCallStarted();
963                 break;
964 
965             case DctConstants.EVENT_VOICE_CALL_ENDED:
966                 onVoiceCallEnded();
967                 break;
968 
969             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS: {
970                 onCleanUpAllConnections((String) msg.obj);
971                 break;
972             }
973             case DctConstants.EVENT_CLEAN_UP_CONNECTION: {
974                 boolean tearDown = (msg.arg1 == 0) ? false : true;
975                 onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
976                 break;
977             }
978             case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: {
979                 boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
980                 onSetInternalDataEnabled(enabled);
981                 break;
982             }
983             case DctConstants.EVENT_RESET_DONE: {
984                 if (DBG) log("EVENT_RESET_DONE");
985                 onResetDone((AsyncResult) msg.obj);
986                 break;
987             }
988             case DctConstants.CMD_SET_USER_DATA_ENABLE: {
989                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
990                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
991                 onSetUserDataEnabled(enabled);
992                 break;
993             }
994             case DctConstants.CMD_SET_DEPENDENCY_MET: {
995                 boolean met = (msg.arg1 == DctConstants.ENABLED) ? true : false;
996                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
997                 Bundle bundle = msg.getData();
998                 if (bundle != null) {
999                     String apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
1000                     if (apnType != null) {
1001                         onSetDependencyMet(apnType, met);
1002                     }
1003                 }
1004                 break;
1005             }
1006             case DctConstants.CMD_SET_POLICY_DATA_ENABLE: {
1007                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
1008                 onSetPolicyDataEnabled(enabled);
1009                 break;
1010             }
1011             case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
1012                 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1;
1013                 if (DBG) {
1014                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
1015                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
1016                 }
1017                 if (sEnableFailFastRefCounter < 0) {
1018                     final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
1019                             + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0";
1020                     loge(s);
1021                     sEnableFailFastRefCounter = 0;
1022                 }
1023                 final boolean enabled = sEnableFailFastRefCounter > 0;
1024                 if (DBG) {
1025                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled
1026                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
1027                 }
1028                 if (mFailFast != enabled) {
1029                     mFailFast = enabled;
1030                     mDataStallDetectionEnabled = !enabled;
1031                     if (mDataStallDetectionEnabled
1032                             && (getOverallState() == DctConstants.State.CONNECTED)
1033                             && (!mInVoiceCall ||
1034                                     mPhone.getServiceStateTracker()
1035                                         .isConcurrentVoiceAndDataAllowed())) {
1036                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall");
1037                         stopDataStallAlarm();
1038                         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1039                     } else {
1040                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall");
1041                         stopDataStallAlarm();
1042                     }
1043                 }
1044 
1045                 break;
1046             }
1047             case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: {
1048                 Bundle bundle = msg.getData();
1049                 if (bundle != null) {
1050                     try {
1051                         mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY);
1052                     } catch(ClassCastException e) {
1053                         loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e);
1054                         mProvisioningUrl = null;
1055                     }
1056                 }
1057                 if (TextUtils.isEmpty(mProvisioningUrl)) {
1058                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring");
1059                     mIsProvisioning = false;
1060                     mProvisioningUrl = null;
1061                 } else {
1062                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl);
1063                     mIsProvisioning = true;
1064                     startProvisioningApnAlarm();
1065                 }
1066                 break;
1067             }
1068             case DctConstants.EVENT_PROVISIONING_APN_ALARM: {
1069                 if (DBG) log("EVENT_PROVISIONING_APN_ALARM");
1070                 ApnContext apnCtx = mApnContexts.get("default");
1071                 if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) {
1072                     if (mProvisioningApnAlarmTag == msg.arg1) {
1073                         if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting");
1074                         mIsProvisioning = false;
1075                         mProvisioningUrl = null;
1076                         stopProvisioningApnAlarm();
1077                         sendCleanUpConnection(true, apnCtx);
1078                     } else {
1079                         if (DBG) {
1080                             log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
1081                                     + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag
1082                                     + " != arg1:" + msg.arg1);
1083                         }
1084                     }
1085                 } else {
1086                     if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore");
1087                 }
1088                 break;
1089             }
1090             case DctConstants.CMD_IS_PROVISIONING_APN: {
1091                 if (DBG) log("CMD_IS_PROVISIONING_APN");
1092                 boolean isProvApn;
1093                 try {
1094                     String apnType = null;
1095                     Bundle bundle = msg.getData();
1096                     if (bundle != null) {
1097                         apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
1098                     }
1099                     if (TextUtils.isEmpty(apnType)) {
1100                         loge("CMD_IS_PROVISIONING_APN: apnType is empty");
1101                         isProvApn = false;
1102                     } else {
1103                         isProvApn = isProvisioningApn(apnType);
1104                     }
1105                 } catch (ClassCastException e) {
1106                     loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring");
1107                     isProvApn = false;
1108                 }
1109                 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn);
1110                 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN,
1111                         isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED);
1112                 break;
1113             }
1114             case DctConstants.EVENT_ICC_CHANGED: {
1115                 onUpdateIcc();
1116                 break;
1117             }
1118             case DctConstants.EVENT_RESTART_RADIO: {
1119                 restartRadio();
1120                 break;
1121             }
1122             case DctConstants.CMD_NET_STAT_POLL: {
1123                 if (msg.arg1 == DctConstants.ENABLED) {
1124                     handleStartNetStatPoll((DctConstants.Activity)msg.obj);
1125                 } else if (msg.arg1 == DctConstants.DISABLED) {
1126                     handleStopNetStatPoll((DctConstants.Activity)msg.obj);
1127                 }
1128                 break;
1129             }
1130             default:
1131                 Rlog.e("DATA", "Unidentified event msg=" + msg);
1132                 break;
1133         }
1134     }
1135 
1136     /**
1137      * Report on whether data connectivity is enabled
1138      *
1139      * @return {@code false} if data connectivity has been explicitly disabled,
1140      *         {@code true} otherwise.
1141      */
getAnyDataEnabled()1142     public boolean getAnyDataEnabled() {
1143         final boolean result;
1144         synchronized (mDataEnabledLock) {
1145             result = (mInternalDataEnabled && mUserDataEnabled && sPolicyDataEnabled
1146                     && (mEnabledCount != 0));
1147         }
1148         if (!result && DBG) log("getAnyDataEnabled " + result);
1149         return result;
1150     }
1151 
isEmergency()1152     protected boolean isEmergency() {
1153         final boolean result;
1154         synchronized (mDataEnabledLock) {
1155             result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
1156         }
1157         log("isEmergency: result=" + result);
1158         return result;
1159     }
1160 
apnTypeToId(String type)1161     protected int apnTypeToId(String type) {
1162         if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DEFAULT)) {
1163             return DctConstants.APN_DEFAULT_ID;
1164         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_MMS)) {
1165             return DctConstants.APN_MMS_ID;
1166         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_SUPL)) {
1167             return DctConstants.APN_SUPL_ID;
1168         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_DUN)) {
1169             return DctConstants.APN_DUN_ID;
1170         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_HIPRI)) {
1171             return DctConstants.APN_HIPRI_ID;
1172         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IMS)) {
1173             return DctConstants.APN_IMS_ID;
1174         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_FOTA)) {
1175             return DctConstants.APN_FOTA_ID;
1176         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_CBS)) {
1177             return DctConstants.APN_CBS_ID;
1178         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_IA)) {
1179             return DctConstants.APN_IA_ID;
1180         } else if (TextUtils.equals(type, PhoneConstants.APN_TYPE_EMERGENCY)) {
1181             return DctConstants.APN_EMERGENCY_ID;
1182         } else {
1183             return DctConstants.APN_INVALID_ID;
1184         }
1185     }
1186 
apnIdToType(int id)1187     protected String apnIdToType(int id) {
1188         switch (id) {
1189         case DctConstants.APN_DEFAULT_ID:
1190             return PhoneConstants.APN_TYPE_DEFAULT;
1191         case DctConstants.APN_MMS_ID:
1192             return PhoneConstants.APN_TYPE_MMS;
1193         case DctConstants.APN_SUPL_ID:
1194             return PhoneConstants.APN_TYPE_SUPL;
1195         case DctConstants.APN_DUN_ID:
1196             return PhoneConstants.APN_TYPE_DUN;
1197         case DctConstants.APN_HIPRI_ID:
1198             return PhoneConstants.APN_TYPE_HIPRI;
1199         case DctConstants.APN_IMS_ID:
1200             return PhoneConstants.APN_TYPE_IMS;
1201         case DctConstants.APN_FOTA_ID:
1202             return PhoneConstants.APN_TYPE_FOTA;
1203         case DctConstants.APN_CBS_ID:
1204             return PhoneConstants.APN_TYPE_CBS;
1205         case DctConstants.APN_IA_ID:
1206             return PhoneConstants.APN_TYPE_IA;
1207         case DctConstants.APN_EMERGENCY_ID:
1208             return PhoneConstants.APN_TYPE_EMERGENCY;
1209         default:
1210             log("Unknown id (" + id + ") in apnIdToType");
1211             return PhoneConstants.APN_TYPE_DEFAULT;
1212         }
1213     }
1214 
getLinkProperties(String apnType)1215     public LinkProperties getLinkProperties(String apnType) {
1216         int id = apnTypeToId(apnType);
1217 
1218         if (isApnIdEnabled(id)) {
1219             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
1220             return dcac.getLinkPropertiesSync();
1221         } else {
1222             return new LinkProperties();
1223         }
1224     }
1225 
getNetworkCapabilities(String apnType)1226     public NetworkCapabilities getNetworkCapabilities(String apnType) {
1227         int id = apnTypeToId(apnType);
1228         if (isApnIdEnabled(id)) {
1229             DcAsyncChannel dcac = mDataConnectionAcHashMap.get(0);
1230             return dcac.getNetworkCapabilitiesSync();
1231         } else {
1232             return new NetworkCapabilities();
1233         }
1234     }
1235 
1236     // tell all active apns of the current condition
notifyDataConnection(String reason)1237     protected void notifyDataConnection(String reason) {
1238         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
1239             if (mDataEnabled[id]) {
1240                 mPhone.notifyDataConnection(reason, apnIdToType(id));
1241             }
1242         }
1243         notifyOffApnsOfAvailability(reason);
1244     }
1245 
1246     // a new APN has gone active and needs to send events to catch up with the
1247     // current condition
notifyApnIdUpToCurrent(String reason, int apnId)1248     private void notifyApnIdUpToCurrent(String reason, int apnId) {
1249         switch (mState) {
1250             case IDLE:
1251                 break;
1252             case RETRYING:
1253             case CONNECTING:
1254             case SCANNING:
1255                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1256                         PhoneConstants.DataState.CONNECTING);
1257                 break;
1258             case CONNECTED:
1259             case DISCONNECTING:
1260                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1261                         PhoneConstants.DataState.CONNECTING);
1262                 mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1263                         PhoneConstants.DataState.CONNECTED);
1264                 break;
1265             default:
1266                 // Ignore
1267                 break;
1268         }
1269     }
1270 
1271     // since we normally don't send info to a disconnected APN, we need to do this specially
notifyApnIdDisconnected(String reason, int apnId)1272     private void notifyApnIdDisconnected(String reason, int apnId) {
1273         mPhone.notifyDataConnection(reason, apnIdToType(apnId),
1274                 PhoneConstants.DataState.DISCONNECTED);
1275     }
1276 
1277     // disabled apn's still need avail/unavail notificiations - send them out
notifyOffApnsOfAvailability(String reason)1278     protected void notifyOffApnsOfAvailability(String reason) {
1279         if (DBG) log("notifyOffApnsOfAvailability - reason= " + reason);
1280         for (int id = 0; id < DctConstants.APN_NUM_TYPES; id++) {
1281             if (!isApnIdEnabled(id)) {
1282                 notifyApnIdDisconnected(reason, id);
1283             }
1284         }
1285     }
1286 
isApnTypeEnabled(String apnType)1287     public boolean isApnTypeEnabled(String apnType) {
1288         if (apnType == null) {
1289             return false;
1290         } else {
1291             return isApnIdEnabled(apnTypeToId(apnType));
1292         }
1293     }
1294 
isApnIdEnabled(int id)1295     protected synchronized boolean isApnIdEnabled(int id) {
1296         if (id != DctConstants.APN_INVALID_ID) {
1297             return mDataEnabled[id];
1298         }
1299         return false;
1300     }
1301 
setEnabled(int id, boolean enable)1302     protected void setEnabled(int id, boolean enable) {
1303         if (DBG) {
1304             log("setEnabled(" + id + ", " + enable + ") with old state = " + mDataEnabled[id]
1305                     + " and enabledCount = " + mEnabledCount);
1306         }
1307         Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
1308         msg.arg1 = id;
1309         msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
1310         sendMessage(msg);
1311     }
1312 
onEnableApn(int apnId, int enabled)1313     protected void onEnableApn(int apnId, int enabled) {
1314         if (DBG) {
1315             log("EVENT_APN_ENABLE_REQUEST apnId=" + apnId + ", apnType=" + apnIdToType(apnId) +
1316                     ", enabled=" + enabled + ", dataEnabled = " + mDataEnabled[apnId] +
1317                     ", enabledCount = " + mEnabledCount + ", isApnTypeActive = " +
1318                     isApnTypeActive(apnIdToType(apnId)));
1319         }
1320         if (enabled == DctConstants.ENABLED) {
1321             synchronized (this) {
1322                 if (!mDataEnabled[apnId]) {
1323                     mDataEnabled[apnId] = true;
1324                     mEnabledCount++;
1325                 }
1326             }
1327             String type = apnIdToType(apnId);
1328             if (!isApnTypeActive(type)) {
1329                 mRequestedApnType = type;
1330                 onEnableNewApn();
1331             } else {
1332                 notifyApnIdUpToCurrent(Phone.REASON_APN_SWITCHED, apnId);
1333             }
1334         } else {
1335             // disable
1336             boolean didDisable = false;
1337             synchronized (this) {
1338                 if (mDataEnabled[apnId]) {
1339                     mDataEnabled[apnId] = false;
1340                     mEnabledCount--;
1341                     didDisable = true;
1342                 }
1343             }
1344             if (didDisable) {
1345                 if ((mEnabledCount == 0) || (apnId == DctConstants.APN_DUN_ID)) {
1346                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
1347                     onCleanUpConnection(true, apnId, Phone.REASON_DATA_DISABLED);
1348                 }
1349 
1350                 // send the disconnect msg manually, since the normal route wont send
1351                 // it (it's not enabled)
1352                 notifyApnIdDisconnected(Phone.REASON_DATA_DISABLED, apnId);
1353                 if (mDataEnabled[DctConstants.APN_DEFAULT_ID] == true
1354                         && !isApnTypeActive(PhoneConstants.APN_TYPE_DEFAULT)) {
1355                     // TODO - this is an ugly way to restore the default conn - should be done
1356                     // by a real contention manager and policy that disconnects the lower pri
1357                     // stuff as enable requests come in and pops them back on as we disable back
1358                     // down to the lower pri stuff
1359                     mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
1360                     onEnableNewApn();
1361                 }
1362             }
1363         }
1364     }
1365 
1366     /**
1367      * Called when we switch APNs.
1368      *
1369      * mRequestedApnType is set prior to call
1370      * To be overridden.
1371      */
onEnableNewApn()1372     protected void onEnableNewApn() {
1373     }
1374 
1375     /**
1376      * Called when EVENT_RESET_DONE is received so goto
1377      * IDLE state and send notifications to those interested.
1378      *
1379      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
1380      * TODO - needs to pass some notion of which connection is reset..
1381      */
onResetDone(AsyncResult ar)1382     protected void onResetDone(AsyncResult ar) {
1383         if (DBG) log("EVENT_RESET_DONE");
1384         String reason = null;
1385         if (ar.userObj instanceof String) {
1386             reason = (String) ar.userObj;
1387         }
1388         gotoIdleAndNotifyDataConnection(reason);
1389     }
1390 
1391     /**
1392      * Prevent mobile data connections from being established, or once again
1393      * allow mobile data connections. If the state toggles, then either tear
1394      * down or set up data, as appropriate to match the new state.
1395      *
1396      * @param enable indicates whether to enable ({@code true}) or disable (
1397      *            {@code false}) data
1398      * @return {@code true} if the operation succeeded
1399      */
setInternalDataEnabled(boolean enable)1400     public boolean setInternalDataEnabled(boolean enable) {
1401         if (DBG)
1402             log("setInternalDataEnabled(" + enable + ")");
1403 
1404         Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE);
1405         msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
1406         sendMessage(msg);
1407         return true;
1408     }
1409 
onSetInternalDataEnabled(boolean enabled)1410     protected void onSetInternalDataEnabled(boolean enabled) {
1411         synchronized (mDataEnabledLock) {
1412             mInternalDataEnabled = enabled;
1413             if (enabled) {
1414                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
1415                 onTrySetupData(Phone.REASON_DATA_ENABLED);
1416             } else {
1417                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
1418                 cleanUpAllConnections(null);
1419             }
1420         }
1421     }
1422 
cleanUpAllConnections(String cause)1423     public void cleanUpAllConnections(String cause) {
1424         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
1425         msg.obj = cause;
1426         sendMessage(msg);
1427     }
1428 
isDisconnected()1429     public abstract boolean isDisconnected();
1430 
onSetUserDataEnabled(boolean enabled)1431     protected void onSetUserDataEnabled(boolean enabled) {
1432         synchronized (mDataEnabledLock) {
1433             if (mUserDataEnabled != enabled) {
1434                 mUserDataEnabled = enabled;
1435 
1436                 // For single SIM phones, this is a per phone property.
1437                 if (TelephonyManager.getDefault().getSimCount() == 1) {
1438                     Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
1439                 } else {
1440                     int phoneSubId = mPhone.getSubId();
1441                     Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA + phoneSubId,
1442                             enabled ? 1 : 0);
1443                 }
1444                 if (getDataOnRoamingEnabled() == false &&
1445                         mPhone.getServiceState().getDataRoaming() == true) {
1446                     if (enabled) {
1447                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
1448                     } else {
1449                         notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
1450                     }
1451                 }
1452 
1453                 if (enabled) {
1454                     onTrySetupData(Phone.REASON_DATA_ENABLED);
1455                 } else {
1456                     onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
1457                 }
1458             }
1459         }
1460     }
1461 
onSetDependencyMet(String apnType, boolean met)1462     protected void onSetDependencyMet(String apnType, boolean met) {
1463     }
1464 
onSetPolicyDataEnabled(boolean enabled)1465     protected void onSetPolicyDataEnabled(boolean enabled) {
1466         synchronized (mDataEnabledLock) {
1467             final boolean prevEnabled = getAnyDataEnabled();
1468             if (sPolicyDataEnabled != enabled) {
1469                 sPolicyDataEnabled = enabled;
1470                 if (prevEnabled != getAnyDataEnabled()) {
1471                     if (!prevEnabled) {
1472                         onTrySetupData(Phone.REASON_DATA_ENABLED);
1473                     } else {
1474                         onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
1475                     }
1476                 }
1477             }
1478         }
1479     }
1480 
getReryConfig(boolean forDefault)1481     protected String getReryConfig(boolean forDefault) {
1482         int nt = mPhone.getServiceState().getNetworkType();
1483 
1484         if ((nt == TelephonyManager.NETWORK_TYPE_CDMA) ||
1485             (nt == TelephonyManager.NETWORK_TYPE_1xRTT) ||
1486             (nt == TelephonyManager.NETWORK_TYPE_EVDO_0) ||
1487             (nt == TelephonyManager.NETWORK_TYPE_EVDO_A) ||
1488             (nt == TelephonyManager.NETWORK_TYPE_EVDO_B) ||
1489             (nt == TelephonyManager.NETWORK_TYPE_EHRPD)) {
1490             // CDMA variant
1491             return SystemProperties.get("ro.cdma.data_retry_config");
1492         } else {
1493             // Use GSM varient for all others.
1494             if (forDefault) {
1495                 return SystemProperties.get("ro.gsm.data_retry_config");
1496             } else {
1497                 return SystemProperties.get("ro.gsm.2nd_data_retry_config");
1498             }
1499         }
1500     }
1501 
resetPollStats()1502     protected void resetPollStats() {
1503         mTxPkts = -1;
1504         mRxPkts = -1;
1505         mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
1506     }
1507 
getOverallState()1508     protected abstract DctConstants.State getOverallState();
1509 
startNetStatPoll()1510     void startNetStatPoll() {
1511         if (getOverallState() == DctConstants.State.CONNECTED
1512                 && mNetStatPollEnabled == false) {
1513             if (DBG) {
1514                 log("startNetStatPoll");
1515             }
1516             resetPollStats();
1517             mNetStatPollEnabled = true;
1518             mPollNetStat.run();
1519         }
1520         if (mPhone != null) {
1521             mPhone.notifyDataActivity();
1522         }
1523     }
1524 
stopNetStatPoll()1525     void stopNetStatPoll() {
1526         mNetStatPollEnabled = false;
1527         removeCallbacks(mPollNetStat);
1528         if (DBG) {
1529             log("stopNetStatPoll");
1530         }
1531 
1532         // To sync data activity icon in the case of switching data connection to send MMS.
1533         if (mPhone != null) {
1534             mPhone.notifyDataActivity();
1535         }
1536     }
1537 
sendStartNetStatPoll(DctConstants.Activity activity)1538     public void sendStartNetStatPoll(DctConstants.Activity activity) {
1539         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
1540         msg.arg1 = DctConstants.ENABLED;
1541         msg.obj = activity;
1542         sendMessage(msg);
1543     }
1544 
handleStartNetStatPoll(DctConstants.Activity activity)1545     protected void handleStartNetStatPoll(DctConstants.Activity activity) {
1546         startNetStatPoll();
1547         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1548         setActivity(activity);
1549     }
1550 
sendStopNetStatPoll(DctConstants.Activity activity)1551     public void sendStopNetStatPoll(DctConstants.Activity activity) {
1552         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
1553         msg.arg1 = DctConstants.DISABLED;
1554         msg.obj = activity;
1555         sendMessage(msg);
1556     }
1557 
handleStopNetStatPoll(DctConstants.Activity activity)1558     protected void handleStopNetStatPoll(DctConstants.Activity activity) {
1559         stopNetStatPoll();
1560         stopDataStallAlarm();
1561         setActivity(activity);
1562     }
1563 
updateDataActivity()1564     public void updateDataActivity() {
1565         long sent, received;
1566 
1567         DctConstants.Activity newActivity;
1568 
1569         TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts);
1570         TxRxSum curTxRxSum = new TxRxSum();
1571         curTxRxSum.updateTxRxSum();
1572         mTxPkts = curTxRxSum.txPkts;
1573         mRxPkts = curTxRxSum.rxPkts;
1574 
1575         if (VDBG) {
1576             log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum);
1577         }
1578 
1579         if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) {
1580             sent = mTxPkts - preTxRxSum.txPkts;
1581             received = mRxPkts - preTxRxSum.rxPkts;
1582 
1583             if (VDBG)
1584                 log("updateDataActivity: sent=" + sent + " received=" + received);
1585             if (sent > 0 && received > 0) {
1586                 newActivity = DctConstants.Activity.DATAINANDOUT;
1587             } else if (sent > 0 && received == 0) {
1588                 newActivity = DctConstants.Activity.DATAOUT;
1589             } else if (sent == 0 && received > 0) {
1590                 newActivity = DctConstants.Activity.DATAIN;
1591             } else {
1592                 newActivity = (mActivity == DctConstants.Activity.DORMANT) ?
1593                         mActivity : DctConstants.Activity.NONE;
1594             }
1595 
1596             if (mActivity != newActivity && mIsScreenOn) {
1597                 if (VDBG)
1598                     log("updateDataActivity: newActivity=" + newActivity);
1599                 mActivity = newActivity;
1600                 mPhone.notifyDataActivity();
1601             }
1602         }
1603     }
1604 
1605     // Recovery action taken in case of data stall
1606     protected static class RecoveryAction {
1607         public static final int GET_DATA_CALL_LIST      = 0;
1608         public static final int CLEANUP                 = 1;
1609         public static final int REREGISTER              = 2;
1610         public static final int RADIO_RESTART           = 3;
1611         public static final int RADIO_RESTART_WITH_PROP = 4;
1612 
isAggressiveRecovery(int value)1613         private static boolean isAggressiveRecovery(int value) {
1614             return ((value == RecoveryAction.CLEANUP) ||
1615                     (value == RecoveryAction.REREGISTER) ||
1616                     (value == RecoveryAction.RADIO_RESTART) ||
1617                     (value == RecoveryAction.RADIO_RESTART_WITH_PROP));
1618         }
1619     }
1620 
getRecoveryAction()1621     public int getRecoveryAction() {
1622         int action = Settings.System.getInt(mResolver,
1623                 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
1624         if (VDBG_STALL) log("getRecoveryAction: " + action);
1625         return action;
1626     }
putRecoveryAction(int action)1627     public void putRecoveryAction(int action) {
1628         Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action);
1629         if (VDBG_STALL) log("putRecoveryAction: " + action);
1630     }
1631 
isConnected()1632     protected boolean isConnected() {
1633         return false;
1634     }
1635 
doRecovery()1636     protected void doRecovery() {
1637         if (getOverallState() == DctConstants.State.CONNECTED) {
1638             // Go through a series of recovery steps, each action transitions to the next action
1639             int recoveryAction = getRecoveryAction();
1640             switch (recoveryAction) {
1641             case RecoveryAction.GET_DATA_CALL_LIST:
1642                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
1643                         mSentSinceLastRecv);
1644                 if (DBG) log("doRecovery() get data call list");
1645                 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED));
1646                 putRecoveryAction(RecoveryAction.CLEANUP);
1647                 break;
1648             case RecoveryAction.CLEANUP:
1649                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv);
1650                 if (DBG) log("doRecovery() cleanup all connections");
1651                 cleanUpAllConnections(Phone.REASON_PDP_RESET);
1652                 putRecoveryAction(RecoveryAction.REREGISTER);
1653                 break;
1654             case RecoveryAction.REREGISTER:
1655                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
1656                         mSentSinceLastRecv);
1657                 if (DBG) log("doRecovery() re-register");
1658                 mPhone.getServiceStateTracker().reRegisterNetwork(null);
1659                 putRecoveryAction(RecoveryAction.RADIO_RESTART);
1660                 break;
1661             case RecoveryAction.RADIO_RESTART:
1662                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
1663                         mSentSinceLastRecv);
1664                 if (DBG) log("restarting radio");
1665                 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP);
1666                 restartRadio();
1667                 break;
1668             case RecoveryAction.RADIO_RESTART_WITH_PROP:
1669                 // This is in case radio restart has not recovered the data.
1670                 // It will set an additional "gsm.radioreset" property to tell
1671                 // RIL or system to take further action.
1672                 // The implementation of hard reset recovery action is up to OEM product.
1673                 // Once RADIO_RESET property is consumed, it is expected to set back
1674                 // to false by RIL.
1675                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1);
1676                 if (DBG) log("restarting radio with gsm.radioreset to true");
1677                 SystemProperties.set(RADIO_RESET_PROPERTY, "true");
1678                 // give 1 sec so property change can be notified.
1679                 try {
1680                     Thread.sleep(1000);
1681                 } catch (InterruptedException e) {}
1682                 restartRadio();
1683                 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
1684                 break;
1685             default:
1686                 throw new RuntimeException("doRecovery: Invalid recoveryAction=" +
1687                     recoveryAction);
1688             }
1689             mSentSinceLastRecv = 0;
1690         }
1691     }
1692 
updateDataStallInfo()1693     private void updateDataStallInfo() {
1694         long sent, received;
1695 
1696         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
1697         mDataStallTxRxSum.updateTxRxSum();
1698 
1699         if (VDBG_STALL) {
1700             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
1701                     " preTxRxSum=" + preTxRxSum);
1702         }
1703 
1704         sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts;
1705         received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts;
1706 
1707         if (RADIO_TESTS) {
1708             if (SystemProperties.getBoolean("radio.test.data.stall", false)) {
1709                 log("updateDataStallInfo: radio.test.data.stall true received = 0;");
1710                 received = 0;
1711             }
1712         }
1713         if ( sent > 0 && received > 0 ) {
1714             if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
1715             mSentSinceLastRecv = 0;
1716             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
1717         } else if (sent > 0 && received == 0) {
1718             if (mPhone.getState() == PhoneConstants.State.IDLE) {
1719                 mSentSinceLastRecv += sent;
1720             } else {
1721                 mSentSinceLastRecv = 0;
1722             }
1723             if (DBG) {
1724                 log("updateDataStallInfo: OUT sent=" + sent +
1725                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
1726             }
1727         } else if (sent == 0 && received > 0) {
1728             if (VDBG_STALL) log("updateDataStallInfo: IN");
1729             mSentSinceLastRecv = 0;
1730             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
1731         } else {
1732             if (VDBG_STALL) log("updateDataStallInfo: NONE");
1733         }
1734     }
1735 
onDataStallAlarm(int tag)1736     protected void onDataStallAlarm(int tag) {
1737         if (mDataStallAlarmTag != tag) {
1738             if (DBG) {
1739                 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag);
1740             }
1741             return;
1742         }
1743         updateDataStallInfo();
1744 
1745         int hangWatchdogTrigger = Settings.Global.getInt(mResolver,
1746                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
1747                 NUMBER_SENT_PACKETS_OF_HANG);
1748 
1749         boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
1750         if (mSentSinceLastRecv >= hangWatchdogTrigger) {
1751             if (DBG) {
1752                 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
1753             }
1754             suspectedStall = DATA_STALL_SUSPECTED;
1755             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
1756         } else {
1757             if (VDBG_STALL) {
1758                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
1759                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
1760             }
1761         }
1762         startDataStallAlarm(suspectedStall);
1763     }
1764 
startDataStallAlarm(boolean suspectedStall)1765     protected void startDataStallAlarm(boolean suspectedStall) {
1766         int nextAction = getRecoveryAction();
1767         int delayInMs;
1768 
1769         if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
1770             // If screen is on or data stall is currently suspected, set the alarm
1771             // with an aggresive timeout.
1772             if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
1773                 delayInMs = Settings.Global.getInt(mResolver,
1774                         Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
1775                         DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
1776             } else {
1777                 delayInMs = Settings.Global.getInt(mResolver,
1778                         Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
1779                         DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
1780             }
1781 
1782             mDataStallAlarmTag += 1;
1783             if (VDBG_STALL) {
1784                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
1785                         " delay=" + (delayInMs / 1000) + "s");
1786             }
1787             Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
1788             intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
1789             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
1790                     PendingIntent.FLAG_UPDATE_CURRENT);
1791             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1792                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
1793         } else {
1794             if (VDBG_STALL) {
1795                 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
1796             }
1797         }
1798     }
1799 
stopDataStallAlarm()1800     protected void stopDataStallAlarm() {
1801         if (VDBG_STALL) {
1802             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
1803                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
1804         }
1805         mDataStallAlarmTag += 1;
1806         if (mDataStallAlarmIntent != null) {
1807             mAlarmManager.cancel(mDataStallAlarmIntent);
1808             mDataStallAlarmIntent = null;
1809         }
1810     }
1811 
restartDataStallAlarm()1812     protected void restartDataStallAlarm() {
1813         if (isConnected() == false) return;
1814         // To be called on screen status change.
1815         // Do not cancel the alarm if it is set with aggressive timeout.
1816         int nextAction = getRecoveryAction();
1817 
1818         if (RecoveryAction.isAggressiveRecovery(nextAction)) {
1819             if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
1820             return;
1821         }
1822         if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
1823         stopDataStallAlarm();
1824         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1825     }
1826 
setInitialAttachApn()1827     protected void setInitialAttachApn() {
1828         ApnSetting iaApnSetting = null;
1829         ApnSetting defaultApnSetting = null;
1830         ApnSetting firstApnSetting = null;
1831 
1832         log("setInitialApn: E mPreferredApn=" + mPreferredApn);
1833 
1834         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
1835             firstApnSetting = mAllApnSettings.get(0);
1836             log("setInitialApn: firstApnSetting=" + firstApnSetting);
1837 
1838             // Search for Initial APN setting and the first apn that can handle default
1839             for (ApnSetting apn : mAllApnSettings) {
1840                 // Can't use apn.canHandleType(), as that returns true for APNs that have no type.
1841                 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA) &&
1842                         apn.carrierEnabled) {
1843                     // The Initial Attach APN is highest priority so use it if there is one
1844                     log("setInitialApn: iaApnSetting=" + apn);
1845                     iaApnSetting = apn;
1846                     break;
1847                 } else if ((defaultApnSetting == null)
1848                         && (apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT))) {
1849                     // Use the first default apn if no better choice
1850                     log("setInitialApn: defaultApnSetting=" + apn);
1851                     defaultApnSetting = apn;
1852                 }
1853             }
1854         }
1855 
1856         // The priority of apn candidates from highest to lowest is:
1857         //   1) APN_TYPE_IA (Inital Attach)
1858         //   2) mPreferredApn, i.e. the current preferred apn
1859         //   3) The first apn that than handle APN_TYPE_DEFAULT
1860         //   4) The first APN we can find.
1861 
1862         ApnSetting initialAttachApnSetting = null;
1863         if (iaApnSetting != null) {
1864             if (DBG) log("setInitialAttachApn: using iaApnSetting");
1865             initialAttachApnSetting = iaApnSetting;
1866         } else if (mPreferredApn != null) {
1867             if (DBG) log("setInitialAttachApn: using mPreferredApn");
1868             initialAttachApnSetting = mPreferredApn;
1869         } else if (defaultApnSetting != null) {
1870             if (DBG) log("setInitialAttachApn: using defaultApnSetting");
1871             initialAttachApnSetting = defaultApnSetting;
1872         } else if (firstApnSetting != null) {
1873             if (DBG) log("setInitialAttachApn: using firstApnSetting");
1874             initialAttachApnSetting = firstApnSetting;
1875         }
1876 
1877         if (initialAttachApnSetting == null) {
1878             if (DBG) log("setInitialAttachApn: X There in no available apn");
1879         } else {
1880             if (DBG) log("setInitialAttachApn: X selected Apn=" + initialAttachApnSetting);
1881 
1882             mPhone.mCi.setInitialAttachApn(initialAttachApnSetting.apn,
1883                     initialAttachApnSetting.protocol, initialAttachApnSetting.authType,
1884                     initialAttachApnSetting.user, initialAttachApnSetting.password, null);
1885         }
1886     }
1887 
setDataProfilesAsNeeded()1888     protected void setDataProfilesAsNeeded() {
1889         if (DBG) log("setDataProfilesAsNeeded");
1890         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
1891             ArrayList<DataProfile> dps = new ArrayList<DataProfile>();
1892             for (ApnSetting apn : mAllApnSettings) {
1893                 if (apn.modemCognitive) {
1894                     DataProfile dp = new DataProfile(apn,
1895                             mPhone.getServiceState().getDataRoaming());
1896                     boolean isDup = false;
1897                     for(DataProfile dpIn : dps) {
1898                         if (dp.equals(dpIn)) {
1899                             isDup = true;
1900                             break;
1901                         }
1902                     }
1903                     if (!isDup) {
1904                         dps.add(dp);
1905                     }
1906                 }
1907             }
1908             if(dps.size() > 0) {
1909                 mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]), null);
1910             }
1911         }
1912     }
1913 
onActionIntentProvisioningApnAlarm(Intent intent)1914     protected void onActionIntentProvisioningApnAlarm(Intent intent) {
1915         if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction());
1916         Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM,
1917                 intent.getAction());
1918         msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0);
1919         sendMessage(msg);
1920     }
1921 
startProvisioningApnAlarm()1922     protected void startProvisioningApnAlarm() {
1923         int delayInMs = Settings.Global.getInt(mResolver,
1924                                 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
1925                                 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT);
1926         if (Build.IS_DEBUGGABLE) {
1927             // Allow debug code to use a system property to provide another value
1928             String delayInMsStrg = Integer.toString(delayInMs);
1929             delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg);
1930             try {
1931                 delayInMs = Integer.parseInt(delayInMsStrg);
1932             } catch (NumberFormatException e) {
1933                 loge("startProvisioningApnAlarm: e=" + e);
1934             }
1935         }
1936         mProvisioningApnAlarmTag += 1;
1937         if (DBG) {
1938             log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag +
1939                     " delay=" + (delayInMs / 1000) + "s");
1940         }
1941         Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM);
1942         intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag);
1943         mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
1944                 PendingIntent.FLAG_UPDATE_CURRENT);
1945         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1946                 SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent);
1947     }
1948 
stopProvisioningApnAlarm()1949     protected void stopProvisioningApnAlarm() {
1950         if (DBG) {
1951             log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag +
1952                     " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent);
1953         }
1954         mProvisioningApnAlarmTag += 1;
1955         if (mProvisioningApnAlarmIntent != null) {
1956             mAlarmManager.cancel(mProvisioningApnAlarmIntent);
1957             mProvisioningApnAlarmIntent = null;
1958         }
1959     }
1960 
sendCleanUpConnection(boolean tearDown, ApnContext apnContext)1961     void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
1962         if (DBG)log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
1963         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
1964         msg.arg1 = tearDown ? 1 : 0;
1965         msg.arg2 = 0;
1966         msg.obj = apnContext;
1967         sendMessage(msg);
1968     }
1969 
sendRestartRadio()1970     void sendRestartRadio() {
1971         if (DBG)log("sendRestartRadio:");
1972         Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO);
1973         sendMessage(msg);
1974     }
1975 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1976     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1977         pw.println("DcTrackerBase:");
1978         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
1979         pw.println(" mInternalDataEnabled=" + mInternalDataEnabled);
1980         pw.println(" mUserDataEnabled=" + mUserDataEnabled);
1981         pw.println(" sPolicyDataEnabed=" + sPolicyDataEnabled);
1982         pw.println(" mDataEnabled:");
1983         for(int i=0; i < mDataEnabled.length; i++) {
1984             pw.printf("  mDataEnabled[%d]=%b\n", i, mDataEnabled[i]);
1985         }
1986         pw.flush();
1987         pw.println(" mEnabledCount=" + mEnabledCount);
1988         pw.println(" mRequestedApnType=" + mRequestedApnType);
1989         pw.println(" mPhone=" + mPhone.getPhoneName());
1990         pw.println(" mActivity=" + mActivity);
1991         pw.println(" mState=" + mState);
1992         pw.println(" mTxPkts=" + mTxPkts);
1993         pw.println(" mRxPkts=" + mRxPkts);
1994         pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
1995         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
1996         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
1997         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
1998         pw.println(" mDataStallDetectionEanbled=" + mDataStallDetectionEnabled);
1999         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
2000         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
2001         pw.println(" mResolver=" + mResolver);
2002         pw.println(" mIsWifiConnected=" + mIsWifiConnected);
2003         pw.println(" mReconnectIntent=" + mReconnectIntent);
2004         pw.println(" mCidActive=" + mCidActive);
2005         pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation);
2006         pw.println(" mIsScreenOn=" + mIsScreenOn);
2007         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
2008         pw.flush();
2009         pw.println(" ***************************************");
2010         DcController dcc = mDcc;
2011         if (dcc != null) {
2012             dcc.dump(fd, pw, args);
2013         } else {
2014             pw.println(" mDcc=null");
2015         }
2016         pw.println(" ***************************************");
2017         HashMap<Integer, DataConnection> dcs = mDataConnections;
2018         if (dcs != null) {
2019             Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
2020             pw.println(" mDataConnections: count=" + mDcSet.size());
2021             for (Entry<Integer, DataConnection> entry : mDcSet) {
2022                 pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
2023                 entry.getValue().dump(fd, pw, args);
2024             }
2025         } else {
2026             pw.println("mDataConnections=null");
2027         }
2028         pw.println(" ***************************************");
2029         pw.flush();
2030         HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
2031         if (apnToDcId != null) {
2032             Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
2033             pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
2034             for (Entry<String, Integer> entry : apnToDcIdSet) {
2035                 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
2036             }
2037         } else {
2038             pw.println("mApnToDataConnectionId=null");
2039         }
2040         pw.println(" ***************************************");
2041         pw.flush();
2042         ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
2043         if (apnCtxs != null) {
2044             Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
2045             pw.println(" mApnContexts size=" + apnCtxsSet.size());
2046             for (Entry<String, ApnContext> entry : apnCtxsSet) {
2047                 entry.getValue().dump(fd, pw, args);
2048             }
2049             pw.println(" ***************************************");
2050         } else {
2051             pw.println(" mApnContexts=null");
2052         }
2053         pw.flush();
2054         pw.println(" mActiveApn=" + mActiveApn);
2055         ArrayList<ApnSetting> apnSettings = mAllApnSettings;
2056         if (apnSettings != null) {
2057             pw.println(" mAllApnSettings size=" + apnSettings.size());
2058             for (int i=0; i < apnSettings.size(); i++) {
2059                 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i));
2060             }
2061             pw.flush();
2062         } else {
2063             pw.println(" mAllApnSettings=null");
2064         }
2065         pw.println(" mPreferredApn=" + mPreferredApn);
2066         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
2067         pw.println(" mIsDisposed=" + mIsDisposed);
2068         pw.println(" mIntentReceiver=" + mIntentReceiver);
2069         pw.println(" mDataRoamingSettingObserver=" + mDataRoamingSettingObserver);
2070         pw.flush();
2071     }
2072 }
2073