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