• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.dataconnection;
18 
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.app.ProgressDialog;
22 import android.content.ActivityNotFoundException;
23 import android.content.BroadcastReceiver;
24 import android.content.ContentResolver;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.IntentFilter;
29 import android.content.SharedPreferences;
30 import android.content.res.Resources;
31 import android.database.ContentObserver;
32 import android.database.Cursor;
33 import android.net.ConnectivityManager;
34 import android.net.LinkProperties;
35 import android.net.NetworkCapabilities;
36 import android.net.NetworkConfig;
37 import android.net.NetworkInfo;
38 import android.net.NetworkRequest;
39 import android.net.NetworkUtils;
40 import android.net.ProxyInfo;
41 import android.net.TrafficStats;
42 import android.net.Uri;
43 import android.net.wifi.WifiManager;
44 import android.os.AsyncResult;
45 import android.os.Build;
46 import android.os.Bundle;
47 import android.os.Handler;
48 import android.os.HandlerThread;
49 import android.os.Message;
50 import android.os.RegistrantList;
51 import android.os.ServiceManager;
52 import android.os.SystemClock;
53 import android.os.SystemProperties;
54 import android.preference.PreferenceManager;
55 import android.provider.Settings;
56 import android.provider.Settings.SettingNotFoundException;
57 import android.provider.Telephony;
58 import android.telephony.CellLocation;
59 import android.telephony.PcoData;
60 import android.telephony.Rlog;
61 import android.telephony.ServiceState;
62 import android.telephony.SubscriptionManager;
63 import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener;
64 import android.telephony.TelephonyManager;
65 import android.telephony.cdma.CdmaCellLocation;
66 import android.telephony.gsm.GsmCellLocation;
67 import android.text.TextUtils;
68 import android.util.EventLog;
69 import android.util.LocalLog;
70 import android.util.Pair;
71 import android.util.SparseArray;
72 import android.view.WindowManager;
73 
74 import com.android.internal.R;
75 import com.android.internal.annotations.VisibleForTesting;
76 import com.android.internal.telephony.DctConstants;
77 import com.android.internal.telephony.EventLogTags;
78 import com.android.internal.telephony.GsmCdmaPhone;
79 import com.android.internal.telephony.ITelephony;
80 import com.android.internal.telephony.Phone;
81 import com.android.internal.telephony.PhoneConstants;
82 import com.android.internal.telephony.RILConstants;
83 import com.android.internal.telephony.ServiceStateTracker;
84 import com.android.internal.telephony.TelephonyIntents;
85 import com.android.internal.telephony.uicc.IccRecords;
86 import com.android.internal.telephony.uicc.UiccController;
87 import com.android.internal.util.ArrayUtils;
88 import com.android.internal.util.AsyncChannel;
89 
90 import java.io.FileDescriptor;
91 import java.io.PrintWriter;
92 import java.util.ArrayList;
93 import java.util.Arrays;
94 import java.util.Comparator;
95 import java.util.HashMap;
96 import java.util.HashSet;
97 import java.util.List;
98 import java.util.Map.Entry;
99 import java.util.Objects;
100 import java.util.PriorityQueue;
101 import java.util.Set;
102 
103 import java.util.concurrent.ConcurrentHashMap;
104 import java.util.concurrent.atomic.AtomicBoolean;
105 import java.util.concurrent.atomic.AtomicInteger;
106 import java.util.concurrent.atomic.AtomicReference;
107 /**
108  * {@hide}
109  */
110 public class DcTracker extends Handler {
111     private static final String LOG_TAG = "DCT";
112     private static final boolean DBG = true;
113     private static final boolean VDBG = false; // STOPSHIP if true
114     private static final boolean VDBG_STALL = false; // STOPSHIP if true
115     private static final boolean RADIO_TESTS = false;
116 
117     public AtomicBoolean isCleanupRequired = new AtomicBoolean(false);
118 
119     private final AlarmManager mAlarmManager;
120 
121     /* Currently requested APN type (TODO: This should probably be a parameter not a member) */
122     private String mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
123 
124     // All data enabling/disabling related settings
125     private final DataEnabledSettings mDataEnabledSettings = new DataEnabledSettings();
126 
127     /**
128      * After detecting a potential connection problem, this is the max number
129      * of subsequent polls before attempting recovery.
130      */
131     // 1 sec. default polling interval when screen is on.
132     private static final int POLL_NETSTAT_MILLIS = 1000;
133     // 10 min. default polling interval when screen is off.
134     private static final int POLL_NETSTAT_SCREEN_OFF_MILLIS = 1000*60*10;
135     // Default sent packets without ack which triggers initial recovery steps
136     private static final int NUMBER_SENT_PACKETS_OF_HANG = 10;
137 
138     // Default for the data stall alarm while non-aggressive stall detection
139     private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6;
140     // Default for the data stall alarm for aggressive stall detection
141     private static final int DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60;
142     // Tag for tracking stale alarms
143     private static final String DATA_STALL_ALARM_TAG_EXTRA = "data.stall.alram.tag";
144 
145     private static final boolean DATA_STALL_SUSPECTED = true;
146     private static final boolean DATA_STALL_NOT_SUSPECTED = false;
147 
148     private String RADIO_RESET_PROPERTY = "gsm.radioreset";
149 
150     private static final String INTENT_RECONNECT_ALARM =
151             "com.android.internal.telephony.data-reconnect";
152     private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "reconnect_alarm_extra_type";
153     private static final String INTENT_RECONNECT_ALARM_EXTRA_REASON =
154             "reconnect_alarm_extra_reason";
155 
156     private static final String INTENT_DATA_STALL_ALARM =
157             "com.android.internal.telephony.data-stall";
158 
159     @VisibleForTesting
160     public static class DataAllowFailReason {
161         private HashSet<DataAllowFailReasonType> mDataAllowFailReasonSet = new HashSet<>();
162 
addDataAllowFailReason(DataAllowFailReasonType type)163         public void addDataAllowFailReason(DataAllowFailReasonType type) {
164             mDataAllowFailReasonSet.add(type);
165         }
166 
getDataAllowFailReason()167         public String getDataAllowFailReason() {
168             StringBuilder failureReason = new StringBuilder();
169             failureReason.append("isDataAllowed: No");
170             for(DataAllowFailReasonType reason : mDataAllowFailReasonSet) {
171                 failureReason.append(reason.mFailReasonStr);
172             }
173             return failureReason.toString();
174         }
175 
isFailForSingleReason(DataAllowFailReasonType failReasonType)176         public boolean isFailForSingleReason(DataAllowFailReasonType failReasonType) {
177             return (mDataAllowFailReasonSet.size() == 1) &&
178                     (mDataAllowFailReasonSet.contains(failReasonType));
179         }
180 
clearAllReasons()181         public void clearAllReasons() {
182             mDataAllowFailReasonSet.clear();
183         }
184 
isFailed()185         public boolean isFailed() {
186             return mDataAllowFailReasonSet.size() > 0;
187         }
188     }
189 
190     @VisibleForTesting
191     public enum DataAllowFailReasonType {
192         NOT_ATTACHED(" - Not attached"),
193         RECORD_NOT_LOADED(" - SIM not loaded"),
194         ROAMING_DISABLED(" - Roaming and data roaming not enabled"),
195         INVALID_PHONE_STATE(" - PhoneState is not idle"),
196         CONCURRENT_VOICE_DATA_NOT_ALLOWED(" - Concurrent voice and data not allowed"),
197         PS_RESTRICTED(" - mIsPsRestricted= true"),
198         UNDESIRED_POWER_STATE(" - desiredPowerState= false"),
199         INTERNAL_DATA_DISABLED(" - mInternalDataEnabled= false"),
200         DEFAULT_DATA_UNSELECTED(" - defaultDataSelected= false"),
201         RADIO_DISABLED_BY_CARRIER(" - powerStateFromCarrier= false");
202 
203         public String mFailReasonStr;
204 
DataAllowFailReasonType(String reason)205         DataAllowFailReasonType(String reason) {
206             mFailReasonStr = reason;
207         }
208     }
209 
210     private DcTesterFailBringUpAll mDcTesterFailBringUpAll;
211     private DcController mDcc;
212 
213     /** kept in sync with mApnContexts
214      * Higher numbers are higher priority and sorted so highest priority is first */
215     private final PriorityQueue<ApnContext>mPrioritySortedApnContexts =
216             new PriorityQueue<ApnContext>(5,
217             new Comparator<ApnContext>() {
218                 public int compare(ApnContext c1, ApnContext c2) {
219                     return c2.priority - c1.priority;
220                 }
221             } );
222 
223     /** allApns holds all apns */
224     private ArrayList<ApnSetting> mAllApnSettings = null;
225 
226     /** preferred apn */
227     private ApnSetting mPreferredApn = null;
228 
229     /** Is packet service restricted by network */
230     private boolean mIsPsRestricted = false;
231 
232     /** emergency apn Setting*/
233     private ApnSetting mEmergencyApn = null;
234 
235     /* Once disposed dont handle any messages */
236     private boolean mIsDisposed = false;
237 
238     private ContentResolver mResolver;
239 
240     /* Set to true with CMD_ENABLE_MOBILE_PROVISIONING */
241     private boolean mIsProvisioning = false;
242 
243     /* The Url passed as object parameter in CMD_ENABLE_MOBILE_PROVISIONING */
244     private String mProvisioningUrl = null;
245 
246     /* Intent for the provisioning apn alarm */
247     private static final String INTENT_PROVISIONING_APN_ALARM =
248             "com.android.internal.telephony.provisioning_apn_alarm";
249 
250     /* Tag for tracking stale alarms */
251     private static final String PROVISIONING_APN_ALARM_TAG_EXTRA = "provisioning.apn.alarm.tag";
252 
253     /* Debug property for overriding the PROVISIONING_APN_ALARM_DELAY_IN_MS */
254     private static final String DEBUG_PROV_APN_ALARM = "persist.debug.prov_apn_alarm";
255 
256     /* Default for the provisioning apn alarm timeout */
257     private static final int PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT = 1000 * 60 * 15;
258 
259     /* The provision apn alarm intent used to disable the provisioning apn */
260     private PendingIntent mProvisioningApnAlarmIntent = null;
261 
262     /* Used to track stale provisioning apn alarms */
263     private int mProvisioningApnAlarmTag = (int) SystemClock.elapsedRealtime();
264 
265     private AsyncChannel mReplyAc = new AsyncChannel();
266 
267     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver () {
268         @Override
269         public void onReceive(Context context, Intent intent) {
270             String action = intent.getAction();
271 
272             if (action.equals(Intent.ACTION_SCREEN_ON)) {
273                 if (DBG) log("screen on");
274                 mIsScreenOn = true;
275                 stopNetStatPoll();
276                 startNetStatPoll();
277                 restartDataStallAlarm();
278             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
279                 if (DBG) log("screen off");
280                 mIsScreenOn = false;
281                 stopNetStatPoll();
282                 startNetStatPoll();
283                 restartDataStallAlarm();
284             } else if (action.startsWith(INTENT_RECONNECT_ALARM)) {
285                 if (DBG) log("Reconnect alarm. Previous state was " + mState);
286                 onActionIntentReconnectAlarm(intent);
287             } else if (action.equals(INTENT_DATA_STALL_ALARM)) {
288                 if (DBG) log("Data stall alarm");
289                 onActionIntentDataStallAlarm(intent);
290             } else if (action.equals(INTENT_PROVISIONING_APN_ALARM)) {
291                 if (DBG) log("Provisioning apn alarm");
292                 onActionIntentProvisioningApnAlarm(intent);
293             } else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
294                 final android.net.NetworkInfo networkInfo = (NetworkInfo)
295                 intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
296                 mIsWifiConnected = (networkInfo != null && networkInfo.isConnected());
297                 if (DBG) log("NETWORK_STATE_CHANGED_ACTION: mIsWifiConnected=" + mIsWifiConnected);
298             } else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
299                 if (DBG) log("Wifi state changed");
300                 final boolean enabled = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
301                         WifiManager.WIFI_STATE_UNKNOWN) == WifiManager.WIFI_STATE_ENABLED;
302                 if (!enabled) {
303                     // when WiFi got disabled, the NETWORK_STATE_CHANGED_ACTION
304                     // quit and won't report disconnected until next enabling.
305                     mIsWifiConnected = false;
306                 }
307                 if (DBG) {
308                     log("WIFI_STATE_CHANGED_ACTION: enabled=" + enabled
309                             + " mIsWifiConnected=" + mIsWifiConnected);
310                 }
311             } else {
312                 if (DBG) log("onReceive: Unknown action=" + action);
313             }
314         }
315     };
316 
317     private final Runnable mPollNetStat = new Runnable() {
318         @Override
319         public void run() {
320             updateDataActivity();
321 
322             if (mIsScreenOn) {
323                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
324                         Settings.Global.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
325             } else {
326                 mNetStatPollPeriod = Settings.Global.getInt(mResolver,
327                         Settings.Global.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
328                         POLL_NETSTAT_SCREEN_OFF_MILLIS);
329             }
330 
331             if (mNetStatPollEnabled) {
332                 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
333             }
334         }
335     };
336 
337     private SubscriptionManager mSubscriptionManager;
338     private final OnSubscriptionsChangedListener mOnSubscriptionsChangedListener =
339             new OnSubscriptionsChangedListener() {
340                 public final AtomicInteger mPreviousSubId =
341                         new AtomicInteger(SubscriptionManager.INVALID_SUBSCRIPTION_ID);
342 
343                 /**
344                  * Callback invoked when there is any change to any SubscriptionInfo. Typically
345                  * this method invokes {@link SubscriptionManager#getActiveSubscriptionInfoList}
346                  */
347                 @Override
348                 public void onSubscriptionsChanged() {
349                     if (DBG) log("SubscriptionListener.onSubscriptionInfoChanged");
350                     // Set the network type, in case the radio does not restore it.
351                     int subId = mPhone.getSubId();
352                     if (SubscriptionManager.isValidSubscriptionId(subId)) {
353                         registerSettingsObserver();
354                     }
355                     if (mPreviousSubId.getAndSet(subId) != subId &&
356                             SubscriptionManager.isValidSubscriptionId(subId)) {
357                         onRecordsLoadedOrSubIdChanged();
358                     }
359                 }
360             };
361 
362     private static class SettingsObserver extends ContentObserver {
363         final private HashMap<Uri, Integer> mUriEventMap;
364         final private Context mContext;
365         final private Handler mHandler;
366         final private static String TAG = "DcTracker.SettingsObserver";
367 
SettingsObserver(Context context, Handler handler)368         SettingsObserver(Context context, Handler handler) {
369             super(null);
370             mUriEventMap = new HashMap<Uri, Integer>();
371             mContext = context;
372             mHandler = handler;
373         }
374 
observe(Uri uri, int what)375         void observe(Uri uri, int what) {
376             mUriEventMap.put(uri, what);
377             final ContentResolver resolver = mContext.getContentResolver();
378             resolver.registerContentObserver(uri, false, this);
379         }
380 
unobserve()381         void unobserve() {
382             final ContentResolver resolver = mContext.getContentResolver();
383             resolver.unregisterContentObserver(this);
384         }
385 
386         @Override
onChange(boolean selfChange)387         public void onChange(boolean selfChange) {
388             Rlog.e(TAG, "Should never be reached.");
389         }
390 
391         @Override
onChange(boolean selfChange, Uri uri)392         public void onChange(boolean selfChange, Uri uri) {
393             final Integer what = mUriEventMap.get(uri);
394             if (what != null) {
395                 mHandler.obtainMessage(what.intValue()).sendToTarget();
396             } else {
397                 Rlog.e(TAG, "No matching event to send for URI=" + uri);
398             }
399         }
400     }
401 
402     private final SettingsObserver mSettingsObserver;
403 
registerSettingsObserver()404     private void registerSettingsObserver() {
405         mSettingsObserver.unobserve();
406         String simSuffix = "";
407         if (TelephonyManager.getDefault().getSimCount() > 1) {
408             simSuffix = Integer.toString(mPhone.getSubId());
409         }
410 
411         mSettingsObserver.observe(
412                 Settings.Global.getUriFor(Settings.Global.DATA_ROAMING + simSuffix),
413                 DctConstants.EVENT_ROAMING_ON);
414         mSettingsObserver.observe(
415                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONED),
416                 DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE);
417         mSettingsObserver.observe(
418                 Settings.Global.getUriFor(Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED),
419                 DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE);
420     }
421 
422     /**
423      * Maintain the sum of transmit and receive packets.
424      *
425      * The packet counts are initialized and reset to -1 and
426      * remain -1 until they can be updated.
427      */
428     public static class TxRxSum {
429         public long txPkts;
430         public long rxPkts;
431 
TxRxSum()432         public TxRxSum() {
433             reset();
434         }
435 
TxRxSum(long txPkts, long rxPkts)436         public TxRxSum(long txPkts, long rxPkts) {
437             this.txPkts = txPkts;
438             this.rxPkts = rxPkts;
439         }
440 
TxRxSum(TxRxSum sum)441         public TxRxSum(TxRxSum sum) {
442             txPkts = sum.txPkts;
443             rxPkts = sum.rxPkts;
444         }
445 
reset()446         public void reset() {
447             txPkts = -1;
448             rxPkts = -1;
449         }
450 
451         @Override
toString()452         public String toString() {
453             return "{txSum=" + txPkts + " rxSum=" + rxPkts + "}";
454         }
455 
updateTxRxSum()456         public void updateTxRxSum() {
457             this.txPkts = TrafficStats.getMobileTcpTxPackets();
458             this.rxPkts = TrafficStats.getMobileTcpRxPackets();
459         }
460     }
461 
onActionIntentReconnectAlarm(Intent intent)462     private void onActionIntentReconnectAlarm(Intent intent) {
463         String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
464         String apnType = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE);
465 
466         int phoneSubId = mPhone.getSubId();
467         int currSubId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
468                 SubscriptionManager.INVALID_SUBSCRIPTION_ID);
469         log("onActionIntentReconnectAlarm: currSubId = " + currSubId + " phoneSubId=" + phoneSubId);
470 
471         // Stop reconnect if not current subId is not correct.
472         // FIXME STOPSHIP - phoneSubId is coming up as -1 way after boot and failing this?
473         if (!SubscriptionManager.isValidSubscriptionId(currSubId) || (currSubId != phoneSubId)) {
474             log("receive ReconnectAlarm but subId incorrect, ignore");
475             return;
476         }
477 
478         ApnContext apnContext = mApnContexts.get(apnType);
479 
480         if (DBG) {
481             log("onActionIntentReconnectAlarm: mState=" + mState + " reason=" + reason +
482                     " apnType=" + apnType + " apnContext=" + apnContext +
483                     " mDataConnectionAsyncChannels=" + mDataConnectionAcHashMap);
484         }
485 
486         if ((apnContext != null) && (apnContext.isEnabled())) {
487             apnContext.setReason(reason);
488             DctConstants.State apnContextState = apnContext.getState();
489             if (DBG) {
490                 log("onActionIntentReconnectAlarm: apnContext state=" + apnContextState);
491             }
492             if ((apnContextState == DctConstants.State.FAILED)
493                     || (apnContextState == DctConstants.State.IDLE)) {
494                 if (DBG) {
495                     log("onActionIntentReconnectAlarm: state is FAILED|IDLE, disassociate");
496                 }
497                 DcAsyncChannel dcac = apnContext.getDcAc();
498                 if (dcac != null) {
499                     if (DBG) {
500                         log("onActionIntentReconnectAlarm: tearDown apnContext=" + apnContext);
501                     }
502                     dcac.tearDown(apnContext, "", null);
503                 }
504                 apnContext.setDataConnectionAc(null);
505                 apnContext.setState(DctConstants.State.IDLE);
506             } else {
507                 if (DBG) log("onActionIntentReconnectAlarm: keep associated");
508             }
509             // TODO: IF already associated should we send the EVENT_TRY_SETUP_DATA???
510             sendMessage(obtainMessage(DctConstants.EVENT_TRY_SETUP_DATA, apnContext));
511 
512             apnContext.setReconnectIntent(null);
513         }
514     }
515 
onActionIntentDataStallAlarm(Intent intent)516     private void onActionIntentDataStallAlarm(Intent intent) {
517         if (VDBG_STALL) log("onActionIntentDataStallAlarm: action=" + intent.getAction());
518         Message msg = obtainMessage(DctConstants.EVENT_DATA_STALL_ALARM,
519                 intent.getAction());
520         msg.arg1 = intent.getIntExtra(DATA_STALL_ALARM_TAG_EXTRA, 0);
521         sendMessage(msg);
522     }
523 
524     private final ConnectivityManager mCm;
525 
526     /**
527      * List of messages that are waiting to be posted, when data call disconnect
528      * is complete
529      */
530     private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>();
531 
532     private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
533 
534     // member variables
535     private final Phone mPhone;
536     private final UiccController mUiccController;
537     private final AtomicReference<IccRecords> mIccRecords = new AtomicReference<IccRecords>();
538     private DctConstants.Activity mActivity = DctConstants.Activity.NONE;
539     private DctConstants.State mState = DctConstants.State.IDLE;
540     private final Handler mDataConnectionTracker;
541 
542     private long mTxPkts;
543     private long mRxPkts;
544     private int mNetStatPollPeriod;
545     private boolean mNetStatPollEnabled = false;
546 
547     private TxRxSum mDataStallTxRxSum = new TxRxSum(0, 0);
548     // Used to track stale data stall alarms.
549     private int mDataStallAlarmTag = (int) SystemClock.elapsedRealtime();
550     // The current data stall alarm intent
551     private PendingIntent mDataStallAlarmIntent = null;
552     // Number of packets sent since the last received packet
553     private long mSentSinceLastRecv;
554     // Controls when a simple recovery attempt it to be tried
555     private int mNoRecvPollCount = 0;
556     // Reference counter for enabling fail fast
557     private static int sEnableFailFastRefCounter = 0;
558     // True if data stall detection is enabled
559     private volatile boolean mDataStallDetectionEnabled = true;
560 
561     private volatile boolean mFailFast = false;
562 
563     // True when in voice call
564     private boolean mInVoiceCall = false;
565 
566     // wifi connection status will be updated by sticky intent
567     private boolean mIsWifiConnected = false;
568 
569     /** Intent sent when the reconnect alarm fires. */
570     private PendingIntent mReconnectIntent = null;
571 
572     // When false we will not auto attach and manually attaching is required.
573     private boolean mAutoAttachOnCreationConfig = false;
574     private AtomicBoolean mAutoAttachOnCreation = new AtomicBoolean(false);
575 
576     // State of screen
577     // (TODO: Reconsider tying directly to screen, maybe this is
578     //        really a lower power mode")
579     private boolean mIsScreenOn = true;
580 
581     // Indicates if we found mvno-specific APNs in the full APN list.
582     // used to determine if we can accept mno-specific APN for tethering.
583     private boolean mMvnoMatched = false;
584 
585     /** Allows the generation of unique Id's for DataConnection objects */
586     private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
587 
588     /** The data connections. */
589     private HashMap<Integer, DataConnection> mDataConnections =
590             new HashMap<Integer, DataConnection>();
591 
592     /** The data connection async channels */
593     private HashMap<Integer, DcAsyncChannel> mDataConnectionAcHashMap =
594             new HashMap<Integer, DcAsyncChannel>();
595 
596     /** Convert an ApnType string to Id (TODO: Use "enumeration" instead of String for ApnType) */
597     private HashMap<String, Integer> mApnToDataConnectionId = new HashMap<String, Integer>();
598 
599     /** Phone.APN_TYPE_* ===> ApnContext */
600     private final ConcurrentHashMap<String, ApnContext> mApnContexts =
601             new ConcurrentHashMap<String, ApnContext>();
602 
603     private final SparseArray<ApnContext> mApnContextsById = new SparseArray<ApnContext>();
604 
605     private int mDisconnectPendingCount = 0;
606 
607     /** Indicate if metered APNs are disabled.
608      *  set to block all the metered APNs from continuously sending requests, which causes
609      *  undesired network load */
610     private boolean mMeteredApnDisabled = false;
611 
612     /**
613      * Handles changes to the APN db.
614      */
615     private class ApnChangeObserver extends ContentObserver {
ApnChangeObserver()616         public ApnChangeObserver () {
617             super(mDataConnectionTracker);
618         }
619 
620         @Override
onChange(boolean selfChange)621         public void onChange(boolean selfChange) {
622             sendMessage(obtainMessage(DctConstants.EVENT_APN_CHANGED));
623         }
624     }
625 
626     //***** Instance Variables
627 
628     private boolean mReregisterOnReconnectFailure = false;
629 
630 
631     //***** Constants
632 
633     // Used by puppetmaster/*/radio_stress.py
634     private static final String PUPPET_MASTER_RADIO_STRESS_TEST = "gsm.defaultpdpcontext.active";
635 
636     private static final int POLL_PDP_MILLIS = 5 * 1000;
637 
638     private static final int PROVISIONING_SPINNER_TIMEOUT_MILLIS = 120 * 1000;
639 
640     static final Uri PREFERAPN_NO_UPDATE_URI_USING_SUBID =
641                         Uri.parse("content://telephony/carriers/preferapn_no_update/subId/");
642     static final String APN_ID = "apn_id";
643 
644     private boolean mCanSetPreferApn = false;
645 
646     private AtomicBoolean mAttached = new AtomicBoolean(false);
647 
648     /** Watches for changes to the APN db. */
649     private ApnChangeObserver mApnObserver;
650 
651     private final String mProvisionActionName;
652     private BroadcastReceiver mProvisionBroadcastReceiver;
653     private ProgressDialog mProvisioningSpinner;
654 
655     public boolean mImsRegistrationState = false;
656 
657     //***** Constructor
DcTracker(Phone phone)658     public DcTracker(Phone phone) {
659         super();
660         mPhone = phone;
661 
662         if (DBG) log("DCT.constructor");
663 
664         mResolver = mPhone.getContext().getContentResolver();
665         mUiccController = UiccController.getInstance();
666         mUiccController.registerForIccChanged(this, DctConstants.EVENT_ICC_CHANGED, null);
667         mAlarmManager =
668                 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
669         mCm = (ConnectivityManager) mPhone.getContext().getSystemService(
670                 Context.CONNECTIVITY_SERVICE);
671 
672 
673         IntentFilter filter = new IntentFilter();
674         filter.addAction(Intent.ACTION_SCREEN_ON);
675         filter.addAction(Intent.ACTION_SCREEN_OFF);
676         filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
677         filter.addAction(WifiManager.WIFI_STATE_CHANGED_ACTION);
678         filter.addAction(INTENT_DATA_STALL_ALARM);
679         filter.addAction(INTENT_PROVISIONING_APN_ALARM);
680 
681         // TODO - redundent with update call below?
682         mDataEnabledSettings.setUserDataEnabled(getDataEnabled());
683 
684         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
685 
686         SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext());
687         mAutoAttachOnCreation.set(sp.getBoolean(Phone.DATA_DISABLED_ON_BOOT_KEY, false));
688 
689         mSubscriptionManager = SubscriptionManager.from(mPhone.getContext());
690         mSubscriptionManager.addOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
691 
692         HandlerThread dcHandlerThread = new HandlerThread("DcHandlerThread");
693         dcHandlerThread.start();
694         Handler dcHandler = new Handler(dcHandlerThread.getLooper());
695         mDcc = DcController.makeDcc(mPhone, this, dcHandler);
696         mDcTesterFailBringUpAll = new DcTesterFailBringUpAll(mPhone, dcHandler);
697 
698         mDataConnectionTracker = this;
699         registerForAllEvents();
700         update();
701         mApnObserver = new ApnChangeObserver();
702         phone.getContext().getContentResolver().registerContentObserver(
703                 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
704 
705         initApnContexts();
706 
707         for (ApnContext apnContext : mApnContexts.values()) {
708             // Register the reconnect and restart actions.
709             filter = new IntentFilter();
710             filter.addAction(INTENT_RECONNECT_ALARM + '.' + apnContext.getApnType());
711             mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
712         }
713 
714         // Add Emergency APN to APN setting list by default to support EPDN in sim absent cases
715         initEmergencyApnSetting();
716         addEmergencyApnSetting();
717 
718         mProvisionActionName = "com.android.internal.telephony.PROVISION" + phone.getPhoneId();
719 
720         mSettingsObserver = new SettingsObserver(mPhone.getContext(), this);
721         registerSettingsObserver();
722     }
723 
724     @VisibleForTesting
DcTracker()725     public DcTracker() {
726         mAlarmManager = null;
727         mCm = null;
728         mPhone = null;
729         mUiccController = null;
730         mDataConnectionTracker = null;
731         mProvisionActionName = null;
732         mSettingsObserver = new SettingsObserver(null, this);
733     }
734 
registerServiceStateTrackerEvents()735     public void registerServiceStateTrackerEvents() {
736         mPhone.getServiceStateTracker().registerForDataConnectionAttached(this,
737                 DctConstants.EVENT_DATA_CONNECTION_ATTACHED, null);
738         mPhone.getServiceStateTracker().registerForDataConnectionDetached(this,
739                 DctConstants.EVENT_DATA_CONNECTION_DETACHED, null);
740         mPhone.getServiceStateTracker().registerForDataRoamingOn(this,
741                 DctConstants.EVENT_ROAMING_ON, null);
742         mPhone.getServiceStateTracker().registerForDataRoamingOff(this,
743                 DctConstants.EVENT_ROAMING_OFF, null);
744         mPhone.getServiceStateTracker().registerForPsRestrictedEnabled(this,
745                 DctConstants.EVENT_PS_RESTRICT_ENABLED, null);
746         mPhone.getServiceStateTracker().registerForPsRestrictedDisabled(this,
747                 DctConstants.EVENT_PS_RESTRICT_DISABLED, null);
748         mPhone.getServiceStateTracker().registerForDataRegStateOrRatChanged(this,
749                 DctConstants.EVENT_DATA_RAT_CHANGED, null);
750     }
751 
unregisterServiceStateTrackerEvents()752     public void unregisterServiceStateTrackerEvents() {
753         mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
754         mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
755         mPhone.getServiceStateTracker().unregisterForDataRoamingOn(this);
756         mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
757         mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
758         mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
759         mPhone.getServiceStateTracker().unregisterForDataRegStateOrRatChanged(this);
760     }
761 
registerForAllEvents()762     private void registerForAllEvents() {
763         mPhone.mCi.registerForAvailable(this, DctConstants.EVENT_RADIO_AVAILABLE, null);
764         mPhone.mCi.registerForOffOrNotAvailable(this,
765                 DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
766         mPhone.mCi.registerForDataNetworkStateChanged(this,
767                 DctConstants.EVENT_DATA_STATE_CHANGED, null);
768         // Note, this is fragile - the Phone is now presenting a merged picture
769         // of PS (volte) & CS and by diving into its internals you're just seeing
770         // the CS data.  This works well for the purposes this is currently used for
771         // but that may not always be the case.  Should probably be redesigned to
772         // accurately reflect what we're really interested in (registerForCSVoiceCallEnded).
773         mPhone.getCallTracker().registerForVoiceCallEnded(this,
774                 DctConstants.EVENT_VOICE_CALL_ENDED, null);
775         mPhone.getCallTracker().registerForVoiceCallStarted(this,
776                 DctConstants.EVENT_VOICE_CALL_STARTED, null);
777         registerServiceStateTrackerEvents();
778      //   SubscriptionManager.registerForDdsSwitch(this,
779      //          DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS, null);
780         mPhone.mCi.registerForPcoData(this, DctConstants.EVENT_PCO_DATA_RECEIVED, null);
781     }
782 
dispose()783     public void dispose() {
784         if (DBG) log("DCT.dispose");
785 
786         if (mProvisionBroadcastReceiver != null) {
787             mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
788             mProvisionBroadcastReceiver = null;
789         }
790         if (mProvisioningSpinner != null) {
791             mProvisioningSpinner.dismiss();
792             mProvisioningSpinner = null;
793         }
794 
795         cleanUpAllConnections(true, null);
796 
797         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
798             dcac.disconnect();
799         }
800         mDataConnectionAcHashMap.clear();
801         mIsDisposed = true;
802         mPhone.getContext().unregisterReceiver(mIntentReceiver);
803         mUiccController.unregisterForIccChanged(this);
804         mSettingsObserver.unobserve();
805 
806         mSubscriptionManager
807                 .removeOnSubscriptionsChangedListener(mOnSubscriptionsChangedListener);
808         mDcc.dispose();
809         mDcTesterFailBringUpAll.dispose();
810 
811         mPhone.getContext().getContentResolver().unregisterContentObserver(mApnObserver);
812         mApnContexts.clear();
813         mApnContextsById.clear();
814         mPrioritySortedApnContexts.clear();
815         unregisterForAllEvents();
816 
817         destroyDataConnections();
818     }
819 
unregisterForAllEvents()820     private void unregisterForAllEvents() {
821          //Unregister for all events
822         mPhone.mCi.unregisterForAvailable(this);
823         mPhone.mCi.unregisterForOffOrNotAvailable(this);
824         IccRecords r = mIccRecords.get();
825         if (r != null) {
826             r.unregisterForRecordsLoaded(this);
827             mIccRecords.set(null);
828         }
829         mPhone.mCi.unregisterForDataNetworkStateChanged(this);
830         mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
831         mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
832         unregisterServiceStateTrackerEvents();
833         //SubscriptionManager.unregisterForDdsSwitch(this);
834         mPhone.mCi.unregisterForPcoData(this);
835     }
836 
837     /**
838      * Called when EVENT_RESET_DONE is received so goto
839      * IDLE state and send notifications to those interested.
840      *
841      * TODO - currently unused.  Needs to be hooked into DataConnection cleanup
842      * TODO - needs to pass some notion of which connection is reset..
843      */
onResetDone(AsyncResult ar)844     private void onResetDone(AsyncResult ar) {
845         if (DBG) log("EVENT_RESET_DONE");
846         String reason = null;
847         if (ar.userObj instanceof String) {
848             reason = (String) ar.userObj;
849         }
850         gotoIdleAndNotifyDataConnection(reason);
851     }
852 
853     /**
854      * Modify {@link android.provider.Settings.Global#MOBILE_DATA} value.
855      */
setDataEnabled(boolean enable)856     public void setDataEnabled(boolean enable) {
857         Message msg = obtainMessage(DctConstants.CMD_SET_USER_DATA_ENABLE);
858         msg.arg1 = enable ? 1 : 0;
859         if (DBG) log("setDataEnabled: sendMessage: enable=" + enable);
860         sendMessage(msg);
861     }
862 
onSetUserDataEnabled(boolean enabled)863     private void onSetUserDataEnabled(boolean enabled) {
864         synchronized (mDataEnabledSettings) {
865             if (mDataEnabledSettings.isUserDataEnabled() != enabled) {
866                 mDataEnabledSettings.setUserDataEnabled(enabled);
867 
868                 //TODO: We should move the followings into DataEnabledSettings class.
869                 // For single SIM phones, this is a per phone property.
870                 if (TelephonyManager.getDefault().getSimCount() == 1) {
871                     Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA, enabled ? 1 : 0);
872                 } else {
873                     int phoneSubId = mPhone.getSubId();
874                     Settings.Global.putInt(mResolver, Settings.Global.MOBILE_DATA + phoneSubId,
875                             enabled ? 1 : 0);
876                 }
877                 if (getDataOnRoamingEnabled() == false &&
878                         mPhone.getServiceState().getDataRoaming() == true) {
879                     if (enabled) {
880                         notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
881                     } else {
882                         notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
883                     }
884                 }
885 
886                 // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
887                 // handle the rest from there.
888                 if (enabled) {
889                     teardownRestrictedMeteredConnections();
890                     onTrySetupData(Phone.REASON_DATA_ENABLED);
891                 } else {
892                     onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
893                 }
894             }
895         }
896     }
897 
898     /**
899      * Handle reverting restricted networks back to unrestricted.
900      * If we're changing user data to enabled and this makes data
901      * truely enabled (not disabled by other factors) we need to
902      * tear down any metered apn type that was enabled anyway by
903      * a privileged request.  This allows us to reconnect
904      * to it in an unrestricted way.
905      */
teardownRestrictedMeteredConnections()906     private void teardownRestrictedMeteredConnections() {
907         if (mDataEnabledSettings.isDataEnabled(true)) {
908             for (ApnContext apnContext : mApnContexts.values()) {
909                 if (apnContext.isConnectedOrConnecting() &&
910                         apnContext.getApnSetting().isMetered(mPhone.getContext(),
911                         mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {
912                     if (DBG) log("tearing down restricted metered net: " + apnContext);
913                     apnContext.setReason(Phone.REASON_DATA_ENABLED);
914                     cleanUpConnection(true, apnContext);
915                 }
916             }
917         }
918     }
919 
onDeviceProvisionedChange()920     private void onDeviceProvisionedChange() {
921         if (getDataEnabled()) {
922             mDataEnabledSettings.setUserDataEnabled(true);
923             teardownRestrictedMeteredConnections();
924             onTrySetupData(Phone.REASON_DATA_ENABLED);
925         } else {
926             mDataEnabledSettings.setUserDataEnabled(false);
927             onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
928         }
929     }
930 
931 
getSubId()932     public long getSubId() {
933         return mPhone.getSubId();
934     }
935 
getActivity()936     public DctConstants.Activity getActivity() {
937         return mActivity;
938     }
939 
setActivity(DctConstants.Activity activity)940     private void setActivity(DctConstants.Activity activity) {
941         log("setActivity = " + activity);
942         mActivity = activity;
943         mPhone.notifyDataActivity();
944     }
945 
requestNetwork(NetworkRequest networkRequest, LocalLog log)946     public void requestNetwork(NetworkRequest networkRequest, LocalLog log) {
947         final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest);
948         final ApnContext apnContext = mApnContextsById.get(apnId);
949         log.log("DcTracker.requestNetwork for " + networkRequest + " found " + apnContext);
950         if (apnContext != null) apnContext.requestNetwork(networkRequest, log);
951     }
952 
releaseNetwork(NetworkRequest networkRequest, LocalLog log)953     public void releaseNetwork(NetworkRequest networkRequest, LocalLog log) {
954         final int apnId = ApnContext.apnIdForNetworkRequest(networkRequest);
955         final ApnContext apnContext = mApnContextsById.get(apnId);
956         log.log("DcTracker.releaseNetwork for " + networkRequest + " found " + apnContext);
957         if (apnContext != null) apnContext.releaseNetwork(networkRequest, log);
958     }
959 
isApnSupported(String name)960     public boolean isApnSupported(String name) {
961         if (name == null) {
962             loge("isApnSupported: name=null");
963             return false;
964         }
965         ApnContext apnContext = mApnContexts.get(name);
966         if (apnContext == null) {
967             loge("Request for unsupported mobile name: " + name);
968             return false;
969         }
970         return true;
971     }
972 
getApnPriority(String name)973     public int getApnPriority(String name) {
974         ApnContext apnContext = mApnContexts.get(name);
975         if (apnContext == null) {
976             loge("Request for unsupported mobile name: " + name);
977         }
978         return apnContext.priority;
979     }
980 
981     // Turn telephony radio on or off.
setRadio(boolean on)982     private void setRadio(boolean on) {
983         final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
984         try {
985             phone.setRadio(on);
986         } catch (Exception e) {
987             // Ignore.
988         }
989     }
990 
991     // Class to handle Intent dispatched with user selects the "Sign-in to network"
992     // notification.
993     private class ProvisionNotificationBroadcastReceiver extends BroadcastReceiver {
994         private final String mNetworkOperator;
995         // Mobile provisioning URL.  Valid while provisioning notification is up.
996         // Set prior to notification being posted as URL contains ICCID which
997         // disappears when radio is off (which is the case when notification is up).
998         private final String mProvisionUrl;
999 
ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator)1000         public ProvisionNotificationBroadcastReceiver(String provisionUrl, String networkOperator) {
1001             mNetworkOperator = networkOperator;
1002             mProvisionUrl = provisionUrl;
1003         }
1004 
setEnableFailFastMobileData(int enabled)1005         private void setEnableFailFastMobileData(int enabled) {
1006             sendMessage(obtainMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled, 0));
1007         }
1008 
enableMobileProvisioning()1009         private void enableMobileProvisioning() {
1010             final Message msg = obtainMessage(DctConstants.CMD_ENABLE_MOBILE_PROVISIONING);
1011             msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, mProvisionUrl));
1012             sendMessage(msg);
1013         }
1014 
1015         @Override
onReceive(Context context, Intent intent)1016         public void onReceive(Context context, Intent intent) {
1017             // Turning back on the radio can take time on the order of a minute, so show user a
1018             // spinner so they know something is going on.
1019             mProvisioningSpinner = new ProgressDialog(context);
1020             mProvisioningSpinner.setTitle(mNetworkOperator);
1021             mProvisioningSpinner.setMessage(
1022                     // TODO: Don't borrow "Connecting..." i18n string; give Telephony a version.
1023                     context.getText(com.android.internal.R.string.media_route_status_connecting));
1024             mProvisioningSpinner.setIndeterminate(true);
1025             mProvisioningSpinner.setCancelable(true);
1026             // Allow non-Activity Service Context to create a View.
1027             mProvisioningSpinner.getWindow().setType(
1028                     WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
1029             mProvisioningSpinner.show();
1030             // After timeout, hide spinner so user can at least use their device.
1031             // TODO: Indicate to user that it is taking an unusually long time to connect?
1032             sendMessageDelayed(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER,
1033                     mProvisioningSpinner), PROVISIONING_SPINNER_TIMEOUT_MILLIS);
1034             // This code is almost identical to the old
1035             // ConnectivityService.handleMobileProvisioningAction code.
1036             setRadio(true);
1037             setEnableFailFastMobileData(DctConstants.ENABLED);
1038             enableMobileProvisioning();
1039         }
1040     }
1041 
isDataPossible(String apnType)1042     public boolean isDataPossible(String apnType) {
1043         ApnContext apnContext = mApnContexts.get(apnType);
1044         if (apnContext == null) {
1045             return false;
1046         }
1047         boolean apnContextIsEnabled = apnContext.isEnabled();
1048         DctConstants.State apnContextState = apnContext.getState();
1049         boolean apnTypePossible = !(apnContextIsEnabled &&
1050                 (apnContextState == DctConstants.State.FAILED));
1051         boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
1052         // Set the emergency APN availability status as TRUE irrespective of conditions checked in
1053         // isDataAllowed() like IN_SERVICE, MOBILE DATA status etc.
1054         boolean dataAllowed = isEmergencyApn || isDataAllowed(null);
1055         boolean possible = dataAllowed && apnTypePossible;
1056 
1057         if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
1058                     || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
1059                 && (mPhone.getServiceState().getRilDataRadioTechnology()
1060                 == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
1061             log("Default data call activation not possible in iwlan.");
1062             possible = false;
1063         }
1064 
1065         if (VDBG) {
1066             log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
1067                             "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
1068                     apnType, possible, dataAllowed, apnTypePossible,
1069                     apnContextIsEnabled, apnContextState));
1070         }
1071         return possible;
1072     }
1073 
1074     @Override
finalize()1075     protected void finalize() {
1076         if(DBG) log("finalize");
1077     }
1078 
addApnContext(String type, NetworkConfig networkConfig)1079     private ApnContext addApnContext(String type, NetworkConfig networkConfig) {
1080         ApnContext apnContext = new ApnContext(mPhone, type, LOG_TAG, networkConfig, this);
1081         mApnContexts.put(type, apnContext);
1082         mApnContextsById.put(ApnContext.apnIdForApnName(type), apnContext);
1083         mPrioritySortedApnContexts.add(apnContext);
1084         return apnContext;
1085     }
1086 
initApnContexts()1087     private void initApnContexts() {
1088         log("initApnContexts: E");
1089         // Load device network attributes from resources
1090         String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
1091                 com.android.internal.R.array.networkAttributes);
1092         for (String networkConfigString : networkConfigStrings) {
1093             NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
1094             ApnContext apnContext = null;
1095 
1096             switch (networkConfig.type) {
1097             case ConnectivityManager.TYPE_MOBILE:
1098                 apnContext = addApnContext(PhoneConstants.APN_TYPE_DEFAULT, networkConfig);
1099                 break;
1100             case ConnectivityManager.TYPE_MOBILE_MMS:
1101                 apnContext = addApnContext(PhoneConstants.APN_TYPE_MMS, networkConfig);
1102                 break;
1103             case ConnectivityManager.TYPE_MOBILE_SUPL:
1104                 apnContext = addApnContext(PhoneConstants.APN_TYPE_SUPL, networkConfig);
1105                 break;
1106             case ConnectivityManager.TYPE_MOBILE_DUN:
1107                 apnContext = addApnContext(PhoneConstants.APN_TYPE_DUN, networkConfig);
1108                 break;
1109             case ConnectivityManager.TYPE_MOBILE_HIPRI:
1110                 apnContext = addApnContext(PhoneConstants.APN_TYPE_HIPRI, networkConfig);
1111                 break;
1112             case ConnectivityManager.TYPE_MOBILE_FOTA:
1113                 apnContext = addApnContext(PhoneConstants.APN_TYPE_FOTA, networkConfig);
1114                 break;
1115             case ConnectivityManager.TYPE_MOBILE_IMS:
1116                 apnContext = addApnContext(PhoneConstants.APN_TYPE_IMS, networkConfig);
1117                 break;
1118             case ConnectivityManager.TYPE_MOBILE_CBS:
1119                 apnContext = addApnContext(PhoneConstants.APN_TYPE_CBS, networkConfig);
1120                 break;
1121             case ConnectivityManager.TYPE_MOBILE_IA:
1122                 apnContext = addApnContext(PhoneConstants.APN_TYPE_IA, networkConfig);
1123                 break;
1124             case ConnectivityManager.TYPE_MOBILE_EMERGENCY:
1125                 apnContext = addApnContext(PhoneConstants.APN_TYPE_EMERGENCY, networkConfig);
1126                 break;
1127             default:
1128                 log("initApnContexts: skipping unknown type=" + networkConfig.type);
1129                 continue;
1130             }
1131             log("initApnContexts: apnContext=" + apnContext);
1132         }
1133 
1134         if (VDBG) log("initApnContexts: X mApnContexts=" + mApnContexts);
1135     }
1136 
getLinkProperties(String apnType)1137     public LinkProperties getLinkProperties(String apnType) {
1138         ApnContext apnContext = mApnContexts.get(apnType);
1139         if (apnContext != null) {
1140             DcAsyncChannel dcac = apnContext.getDcAc();
1141             if (dcac != null) {
1142                 if (DBG) log("return link properites for " + apnType);
1143                 return dcac.getLinkPropertiesSync();
1144             }
1145         }
1146         if (DBG) log("return new LinkProperties");
1147         return new LinkProperties();
1148     }
1149 
getNetworkCapabilities(String apnType)1150     public NetworkCapabilities getNetworkCapabilities(String apnType) {
1151         ApnContext apnContext = mApnContexts.get(apnType);
1152         if (apnContext!=null) {
1153             DcAsyncChannel dataConnectionAc = apnContext.getDcAc();
1154             if (dataConnectionAc != null) {
1155                 if (DBG) {
1156                     log("get active pdp is not null, return NetworkCapabilities for " + apnType);
1157                 }
1158                 return dataConnectionAc.getNetworkCapabilitiesSync();
1159             }
1160         }
1161         if (DBG) log("return new NetworkCapabilities");
1162         return new NetworkCapabilities();
1163     }
1164 
1165     // Return all active apn types
getActiveApnTypes()1166     public String[] getActiveApnTypes() {
1167         if (DBG) log("get all active apn types");
1168         ArrayList<String> result = new ArrayList<String>();
1169 
1170         for (ApnContext apnContext : mApnContexts.values()) {
1171             if (mAttached.get() && apnContext.isReady()) {
1172                 result.add(apnContext.getApnType());
1173             }
1174         }
1175 
1176         return result.toArray(new String[0]);
1177     }
1178 
1179     // Return active apn of specific apn type
getActiveApnString(String apnType)1180     public String getActiveApnString(String apnType) {
1181         if (VDBG) log( "get active apn string for type:" + apnType);
1182         ApnContext apnContext = mApnContexts.get(apnType);
1183         if (apnContext != null) {
1184             ApnSetting apnSetting = apnContext.getApnSetting();
1185             if (apnSetting != null) {
1186                 return apnSetting.apn;
1187             }
1188         }
1189         return null;
1190     }
1191 
1192     // Return state of specific apn type
getState(String apnType)1193     public DctConstants.State getState(String apnType) {
1194         ApnContext apnContext = mApnContexts.get(apnType);
1195         if (apnContext != null) {
1196             return apnContext.getState();
1197         }
1198         return DctConstants.State.FAILED;
1199     }
1200 
1201     // Return if apn type is a provisioning apn.
isProvisioningApn(String apnType)1202     private boolean isProvisioningApn(String apnType) {
1203         ApnContext apnContext = mApnContexts.get(apnType);
1204         if (apnContext != null) {
1205             return apnContext.isProvisioningApn();
1206         }
1207         return false;
1208     }
1209 
1210     // Return state of overall
getOverallState()1211     public DctConstants.State getOverallState() {
1212         boolean isConnecting = false;
1213         boolean isFailed = true; // All enabled Apns should be FAILED.
1214         boolean isAnyEnabled = false;
1215 
1216         for (ApnContext apnContext : mApnContexts.values()) {
1217             if (apnContext.isEnabled()) {
1218                 isAnyEnabled = true;
1219                 switch (apnContext.getState()) {
1220                 case CONNECTED:
1221                 case DISCONNECTING:
1222                     if (VDBG) log("overall state is CONNECTED");
1223                     return DctConstants.State.CONNECTED;
1224                 case RETRYING:
1225                 case CONNECTING:
1226                     isConnecting = true;
1227                     isFailed = false;
1228                     break;
1229                 case IDLE:
1230                 case SCANNING:
1231                     isFailed = false;
1232                     break;
1233                 default:
1234                     isAnyEnabled = true;
1235                     break;
1236                 }
1237             }
1238         }
1239 
1240         if (!isAnyEnabled) { // Nothing enabled. return IDLE.
1241             if (VDBG) log( "overall state is IDLE");
1242             return DctConstants.State.IDLE;
1243         }
1244 
1245         if (isConnecting) {
1246             if (VDBG) log( "overall state is CONNECTING");
1247             return DctConstants.State.CONNECTING;
1248         } else if (!isFailed) {
1249             if (VDBG) log( "overall state is IDLE");
1250             return DctConstants.State.IDLE;
1251         } else {
1252             if (VDBG) log( "overall state is FAILED");
1253             return DctConstants.State.FAILED;
1254         }
1255     }
1256 
1257     /**
1258      * Report on whether data connectivity is enabled for any APN.
1259      * @return {@code false} if data connectivity has been explicitly disabled,
1260      * {@code true} otherwise.
1261      */
getAnyDataEnabled()1262     public boolean getAnyDataEnabled() {
1263         if (!mDataEnabledSettings.isDataEnabled(true)) return false;
1264         DataAllowFailReason failureReason = new DataAllowFailReason();
1265         if (!isDataAllowed(failureReason)) {
1266             if (DBG) log(failureReason.getDataAllowFailReason());
1267             return false;
1268         }
1269         for (ApnContext apnContext : mApnContexts.values()) {
1270             // Make sure we don't have a context that is going down
1271             // and is explicitly disabled.
1272             if (isDataAllowedForApn(apnContext)) {
1273                 return true;
1274             }
1275         }
1276         return false;
1277     }
1278 
1279     @VisibleForTesting
isDataEnabled(boolean checkUserDataEnabled)1280     public boolean isDataEnabled(boolean checkUserDataEnabled) {
1281         return mDataEnabledSettings.isDataEnabled(checkUserDataEnabled);
1282     }
1283 
isDataAllowedForApn(ApnContext apnContext)1284     private boolean isDataAllowedForApn(ApnContext apnContext) {
1285         //If RAT is iwlan then dont allow default/IA PDP at all.
1286         //Rest of APN types can be evaluated for remaining conditions.
1287         if ((apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
1288                     || apnContext.getApnType().equals(PhoneConstants.APN_TYPE_IA))
1289                 && (mPhone.getServiceState().getRilDataRadioTechnology()
1290                 == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN)) {
1291             log("Default data call activation not allowed in iwlan.");
1292             return false;
1293         }
1294 
1295         return apnContext.isReady();
1296     }
1297 
1298     //****** Called from ServiceStateTracker
1299     /**
1300      * Invoked when ServiceStateTracker observes a transition from GPRS
1301      * attach to detach.
1302      */
onDataConnectionDetached()1303     private void onDataConnectionDetached() {
1304         /*
1305          * We presently believe it is unnecessary to tear down the PDP context
1306          * when GPRS detaches, but we should stop the network polling.
1307          */
1308         if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
1309         stopNetStatPoll();
1310         stopDataStallAlarm();
1311         notifyDataConnection(Phone.REASON_DATA_DETACHED);
1312         mAttached.set(false);
1313     }
1314 
onDataConnectionAttached()1315     private void onDataConnectionAttached() {
1316         if (DBG) log("onDataConnectionAttached");
1317         mAttached.set(true);
1318         if (getOverallState() == DctConstants.State.CONNECTED) {
1319             if (DBG) log("onDataConnectionAttached: start polling notify attached");
1320             startNetStatPoll();
1321             startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
1322             notifyDataConnection(Phone.REASON_DATA_ATTACHED);
1323         } else {
1324             // update APN availability so that APN can be enabled.
1325             notifyOffApnsOfAvailability(Phone.REASON_DATA_ATTACHED);
1326         }
1327         if (mAutoAttachOnCreationConfig) {
1328             mAutoAttachOnCreation.set(true);
1329         }
1330         setupDataOnConnectableApns(Phone.REASON_DATA_ATTACHED);
1331     }
1332 
isDataAllowed(DataAllowFailReason failureReason)1333     private boolean isDataAllowed(DataAllowFailReason failureReason) {
1334         final boolean internalDataEnabled;
1335         internalDataEnabled = mDataEnabledSettings.isInternalDataEnabled();
1336 
1337         boolean attachedState = mAttached.get();
1338         boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
1339         boolean radioStateFromCarrier = mPhone.getServiceStateTracker().getPowerStateFromCarrier();
1340         int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
1341         if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN) {
1342             desiredPowerState = true;
1343             radioStateFromCarrier = true;
1344         }
1345 
1346         IccRecords r = mIccRecords.get();
1347         boolean recordsLoaded = false;
1348         if (r != null) {
1349             recordsLoaded = r.getRecordsLoaded();
1350             if (DBG && !recordsLoaded) log("isDataAllowed getRecordsLoaded=" + recordsLoaded);
1351         }
1352 
1353         int dataSub = SubscriptionManager.getDefaultDataSubscriptionId();
1354         boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId(dataSub);
1355 
1356         PhoneConstants.State state = PhoneConstants.State.IDLE;
1357         // Note this is explicitly not using mPhone.getState.  See b/19090488.
1358         // mPhone.getState reports the merge of CS and PS (volte) voice call state
1359         // but we only care about CS calls here for data/voice concurrency issues.
1360         // Calling getCallTracker currently gives you just the CS side where the
1361         // ImsCallTracker is held internally where applicable.
1362         // This should be redesigned to ask explicitly what we want:
1363         // voiceCallStateAllowDataCall, or dataCallAllowed or something similar.
1364         if (mPhone.getCallTracker() != null) {
1365             state = mPhone.getCallTracker().getState();
1366         }
1367 
1368         if (failureReason != null) failureReason.clearAllReasons();
1369         if (!(attachedState || mAutoAttachOnCreation.get())) {
1370             if(failureReason == null) return false;
1371             failureReason.addDataAllowFailReason(DataAllowFailReasonType.NOT_ATTACHED);
1372         }
1373         if (!recordsLoaded) {
1374             if(failureReason == null) return false;
1375             failureReason.addDataAllowFailReason(DataAllowFailReasonType.RECORD_NOT_LOADED);
1376         }
1377         if (state != PhoneConstants.State.IDLE &&
1378                 !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
1379             if(failureReason == null) return false;
1380             failureReason.addDataAllowFailReason(DataAllowFailReasonType.INVALID_PHONE_STATE);
1381             failureReason.addDataAllowFailReason(
1382                     DataAllowFailReasonType.CONCURRENT_VOICE_DATA_NOT_ALLOWED);
1383         }
1384         if (!internalDataEnabled) {
1385             if(failureReason == null) return false;
1386             failureReason.addDataAllowFailReason(DataAllowFailReasonType.INTERNAL_DATA_DISABLED);
1387         }
1388         if (!defaultDataSelected) {
1389             if(failureReason == null) return false;
1390             failureReason.addDataAllowFailReason(
1391                     DataAllowFailReasonType.DEFAULT_DATA_UNSELECTED);
1392         }
1393         if (mPhone.getServiceState().getDataRoaming() && !getDataOnRoamingEnabled()) {
1394             if(failureReason == null) return false;
1395             failureReason.addDataAllowFailReason(DataAllowFailReasonType.ROAMING_DISABLED);
1396         }
1397         if (mIsPsRestricted) {
1398             if(failureReason == null) return false;
1399             failureReason.addDataAllowFailReason(DataAllowFailReasonType.PS_RESTRICTED);
1400         }
1401         if (!desiredPowerState) {
1402             if(failureReason == null) return false;
1403             failureReason.addDataAllowFailReason(DataAllowFailReasonType.UNDESIRED_POWER_STATE);
1404         }
1405         if (!radioStateFromCarrier) {
1406             if(failureReason == null) return false;
1407             failureReason.addDataAllowFailReason(DataAllowFailReasonType.RADIO_DISABLED_BY_CARRIER);
1408         }
1409 
1410         return failureReason == null || !failureReason.isFailed();
1411     }
1412 
1413     // arg for setupDataOnConnectableApns
1414     private enum RetryFailures {
1415         // retry failed networks always (the old default)
1416         ALWAYS,
1417         // retry only when a substantial change has occurred.  Either:
1418         // 1) we were restricted by voice/data concurrency and aren't anymore
1419         // 2) our apn list has change
1420         ONLY_ON_CHANGE
1421     };
1422 
setupDataOnConnectableApns(String reason)1423     private void setupDataOnConnectableApns(String reason) {
1424         setupDataOnConnectableApns(reason, RetryFailures.ALWAYS);
1425     }
1426 
setupDataOnConnectableApns(String reason, RetryFailures retryFailures)1427     private void setupDataOnConnectableApns(String reason, RetryFailures retryFailures) {
1428         if (VDBG) log("setupDataOnConnectableApns: " + reason);
1429 
1430         if (DBG && !VDBG) {
1431             StringBuilder sb = new StringBuilder(120);
1432             for (ApnContext apnContext : mPrioritySortedApnContexts) {
1433                 sb.append(apnContext.getApnType());
1434                 sb.append(":[state=");
1435                 sb.append(apnContext.getState());
1436                 sb.append(",enabled=");
1437                 sb.append(apnContext.isEnabled());
1438                 sb.append("] ");
1439             }
1440             log("setupDataOnConnectableApns: " + reason + " " + sb);
1441         }
1442 
1443         for (ApnContext apnContext : mPrioritySortedApnContexts) {
1444             ArrayList<ApnSetting> waitingApns = null;
1445 
1446             if (VDBG) log("setupDataOnConnectableApns: apnContext " + apnContext);
1447 
1448             if (apnContext.getState() == DctConstants.State.FAILED
1449                     || apnContext.getState() == DctConstants.State.SCANNING) {
1450                 if (retryFailures == RetryFailures.ALWAYS) {
1451                     apnContext.releaseDataConnection(reason);
1452                 } else if (apnContext.isConcurrentVoiceAndDataAllowed() == false &&
1453                         mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
1454                     // RetryFailures.ONLY_ON_CHANGE - check if voice concurrency has changed
1455                     apnContext.releaseDataConnection(reason);
1456                 } else {
1457                     // RetryFailures.ONLY_ON_CHANGE - check if the apns have changed
1458                     int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
1459                     ArrayList<ApnSetting> originalApns = apnContext.getWaitingApns();
1460                     if (originalApns != null && originalApns.isEmpty() == false) {
1461                         waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
1462                         if (originalApns.size() != waitingApns.size() ||
1463                                 originalApns.containsAll(waitingApns) == false) {
1464                             apnContext.releaseDataConnection(reason);
1465                         } else {
1466                             continue;
1467                         }
1468                     } else {
1469                         continue;
1470                     }
1471                 }
1472             }
1473             if (apnContext.isConnectable()) {
1474                 log("isConnectable() call trySetupData");
1475                 apnContext.setReason(reason);
1476                 trySetupData(apnContext, waitingApns);
1477             }
1478         }
1479     }
1480 
isEmergency()1481     boolean isEmergency() {
1482         final boolean result = mPhone.isInEcm() || mPhone.isInEmergencyCall();
1483         log("isEmergency: result=" + result);
1484         return result;
1485     }
1486 
trySetupData(ApnContext apnContext)1487     private boolean trySetupData(ApnContext apnContext) {
1488         return trySetupData(apnContext, null);
1489     }
1490 
trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns)1491     private boolean trySetupData(ApnContext apnContext, ArrayList<ApnSetting> waitingApns) {
1492         if (DBG) {
1493             log("trySetupData for type:" + apnContext.getApnType() +
1494                     " due to " + apnContext.getReason() + ", mIsPsRestricted=" + mIsPsRestricted);
1495         }
1496         apnContext.requestLog("trySetupData due to " + apnContext.getReason());
1497 
1498         if (mPhone.getSimulatedRadioControl() != null) {
1499             // Assume data is connected on the simulator
1500             // FIXME  this can be improved
1501             apnContext.setState(DctConstants.State.CONNECTED);
1502             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1503 
1504             log("trySetupData: X We're on the simulator; assuming connected retValue=true");
1505             return true;
1506         }
1507 
1508         // Allow SETUP_DATA request for E-APN to be completed during emergency call
1509         // and MOBILE DATA On/Off cases as well.
1510         boolean isEmergencyApn = apnContext.getApnType().equals(PhoneConstants.APN_TYPE_EMERGENCY);
1511         final ServiceStateTracker sst = mPhone.getServiceStateTracker();
1512 
1513         // set to false if apn type is non-metered or if we have a restricted (priveleged)
1514         // request for the network.
1515         // TODO - may want restricted requests to only apply to carrier-limited data access
1516         //        rather than applying to user limited as well.
1517         // Exclude DUN for the purposes of the override until we get finer grained
1518         // intention in NetworkRequests
1519         boolean checkUserDataEnabled =
1520                 ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
1521                         mPhone.getSubId(), mPhone.getServiceState().getDataRoaming()) &&
1522                 apnContext.hasNoRestrictedRequests(true /*exclude DUN */);
1523 
1524         DataAllowFailReason failureReason = new DataAllowFailReason();
1525 
1526         // allow data if currently in roaming service, roaming setting disabled
1527         // and requested apn type is non-metered for roaming.
1528         boolean isDataAllowed = isDataAllowed(failureReason) ||
1529                 (failureReason.isFailForSingleReason(DataAllowFailReasonType.ROAMING_DISABLED) &&
1530                 !(ApnSetting.isMeteredApnType(apnContext.getApnType(), mPhone.getContext(),
1531                 mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())));
1532 
1533         if (apnContext.isConnectable() && (isEmergencyApn ||
1534                 (isDataAllowed && isDataAllowedForApn(apnContext) &&
1535                         mDataEnabledSettings.isDataEnabled(checkUserDataEnabled) && !isEmergency()))) {
1536             if (apnContext.getState() == DctConstants.State.FAILED) {
1537                 String str = "trySetupData: make a FAILED ApnContext IDLE so its reusable";
1538                 if (DBG) log(str);
1539                 apnContext.requestLog(str);
1540                 apnContext.setState(DctConstants.State.IDLE);
1541             }
1542             int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
1543             apnContext.setConcurrentVoiceAndDataAllowed(sst.isConcurrentVoiceAndDataAllowed());
1544             if (apnContext.getState() == DctConstants.State.IDLE) {
1545                 if (waitingApns == null) {
1546                     waitingApns = buildWaitingApns(apnContext.getApnType(), radioTech);
1547                 }
1548                 if (waitingApns.isEmpty()) {
1549                     notifyNoData(DcFailCause.MISSING_UNKNOWN_APN, apnContext);
1550                     notifyOffApnsOfAvailability(apnContext.getReason());
1551                     String str = "trySetupData: X No APN found retValue=false";
1552                     if (DBG) log(str);
1553                     apnContext.requestLog(str);
1554                     return false;
1555                 } else {
1556                     apnContext.setWaitingApns(waitingApns);
1557                     if (DBG) {
1558                         log ("trySetupData: Create from mAllApnSettings : "
1559                                     + apnListToString(mAllApnSettings));
1560                     }
1561                 }
1562             }
1563 
1564             boolean retValue = setupData(apnContext, radioTech);
1565             notifyOffApnsOfAvailability(apnContext.getReason());
1566 
1567             if (DBG) log("trySetupData: X retValue=" + retValue);
1568             return retValue;
1569         } else {
1570             if (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT)
1571                     && apnContext.isConnectable()) {
1572                 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
1573             }
1574             notifyOffApnsOfAvailability(apnContext.getReason());
1575 
1576             StringBuilder str = new StringBuilder();
1577 
1578             str.append("trySetupData failed. apnContext = [type=" + apnContext.getApnType() +
1579                     ", mState=" + apnContext.getState() + ", mDataEnabled=" +
1580                     apnContext.isEnabled() + ", mDependencyMet=" +
1581                     apnContext.getDependencyMet() + "] ");
1582 
1583             if (!apnContext.isConnectable()) {
1584                 str.append("isConnectable = false. ");
1585             }
1586             if (!isDataAllowed) {
1587                 str.append("data not allowed: " + failureReason.getDataAllowFailReason() + ". ");
1588             }
1589             if (!isDataAllowedForApn(apnContext)) {
1590                 str.append("isDataAllowedForApn = false. RAT = " +
1591                         mPhone.getServiceState().getRilDataRadioTechnology());
1592             }
1593             if (!mDataEnabledSettings.isDataEnabled(checkUserDataEnabled)) {
1594                 str.append("isDataEnabled(" + checkUserDataEnabled + ") = false. " +
1595                         "isInternalDataEnabled = " + mDataEnabledSettings.isInternalDataEnabled() +
1596                         ", userDataEnabled = " + mDataEnabledSettings.isUserDataEnabled() +
1597                         ", isPolicyDataEnabled = " + mDataEnabledSettings.isPolicyDataEnabled() +
1598                         ", isCarrierDataEnabled = " +
1599                         mDataEnabledSettings.isCarrierDataEnabled());
1600             }
1601             if (isEmergency()) {
1602                 str.append("emergency = true");
1603             }
1604 
1605             if (DBG) log(str.toString());
1606             apnContext.requestLog(str.toString());
1607 
1608             return false;
1609         }
1610     }
1611 
1612     // Disabled apn's still need avail/unavail notifications - send them out
notifyOffApnsOfAvailability(String reason)1613     private void notifyOffApnsOfAvailability(String reason) {
1614         if (DBG) {
1615             DataAllowFailReason failureReason = new DataAllowFailReason();
1616             if (!isDataAllowed(failureReason)) {
1617                 log(failureReason.getDataAllowFailReason());
1618             }
1619         }
1620         for (ApnContext apnContext : mApnContexts.values()) {
1621             if (!mAttached.get() || !apnContext.isReady()) {
1622                 if (VDBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
1623                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
1624                                             apnContext.getApnType(),
1625                                             PhoneConstants.DataState.DISCONNECTED);
1626             } else {
1627                 if (VDBG) {
1628                     log("notifyOffApnsOfAvailability skipped apn due to attached && isReady " +
1629                             apnContext.toString());
1630                 }
1631             }
1632         }
1633     }
1634 
1635     /**
1636      * If tearDown is true, this only tears down a CONNECTED session. Presently,
1637      * there is no mechanism for abandoning an CONNECTING session,
1638      * but would likely involve cancelling pending async requests or
1639      * setting a flag or new state to ignore them when they came in
1640      * @param tearDown true if the underlying DataConnection should be
1641      * disconnected.
1642      * @param reason reason for the clean up.
1643      * @return boolean - true if we did cleanup any connections, false if they
1644      *                   were already all disconnected.
1645      */
cleanUpAllConnections(boolean tearDown, String reason)1646     private boolean cleanUpAllConnections(boolean tearDown, String reason) {
1647         if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
1648         boolean didDisconnect = false;
1649         boolean disableMeteredOnly = false;
1650 
1651         // reasons that only metered apn will be torn down
1652         if (!TextUtils.isEmpty(reason)) {
1653             disableMeteredOnly = reason.equals(Phone.REASON_DATA_SPECIFIC_DISABLED) ||
1654                     reason.equals(Phone.REASON_ROAMING_ON) ||
1655                     reason.equals(Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
1656         }
1657 
1658         for (ApnContext apnContext : mApnContexts.values()) {
1659             if (apnContext.isDisconnected() == false) didDisconnect = true;
1660             if (disableMeteredOnly) {
1661                 // Use ApnSetting to decide metered or non-metered.
1662                 // Tear down all metered data connections.
1663                 ApnSetting apnSetting = apnContext.getApnSetting();
1664                 if (apnSetting != null && apnSetting.isMetered(mPhone.getContext(),
1665                         mPhone.getSubId(), mPhone.getServiceState().getDataRoaming())) {
1666                     if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType());
1667                     apnContext.setReason(reason);
1668                     cleanUpConnection(tearDown, apnContext);
1669                 }
1670             } else {
1671                 // TODO - only do cleanup if not disconnected
1672                 apnContext.setReason(reason);
1673                 cleanUpConnection(tearDown, apnContext);
1674             }
1675         }
1676 
1677         stopNetStatPoll();
1678         stopDataStallAlarm();
1679 
1680         // TODO: Do we need mRequestedApnType?
1681         mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
1682 
1683         log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount);
1684         if (tearDown && mDisconnectPendingCount == 0) {
1685             notifyDataDisconnectComplete();
1686             notifyAllDataDisconnected();
1687         }
1688 
1689         return didDisconnect;
1690     }
1691 
1692     /**
1693      * Cleanup all connections.
1694      *
1695      * TODO: Cleanup only a specified connection passed as a parameter.
1696      *       Also, make sure when you clean up a conn, if it is last apply
1697      *       logic as though it is cleanupAllConnections
1698      *
1699      * @param cause for the clean up.
1700      */
onCleanUpAllConnections(String cause)1701     private void onCleanUpAllConnections(String cause) {
1702         cleanUpAllConnections(true, cause);
1703     }
1704 
sendCleanUpConnection(boolean tearDown, ApnContext apnContext)1705     void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
1706         if (DBG) log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
1707         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
1708         msg.arg1 = tearDown ? 1 : 0;
1709         msg.arg2 = 0;
1710         msg.obj = apnContext;
1711         sendMessage(msg);
1712     }
1713 
cleanUpConnection(boolean tearDown, ApnContext apnContext)1714     private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
1715         if (apnContext == null) {
1716             if (DBG) log("cleanUpConnection: apn context is null");
1717             return;
1718         }
1719 
1720         DcAsyncChannel dcac = apnContext.getDcAc();
1721         String str = "cleanUpConnection: tearDown=" + tearDown + " reason=" +
1722                 apnContext.getReason();
1723         if (VDBG) log(str + " apnContext=" + apnContext);
1724         apnContext.requestLog(str);
1725         if (tearDown) {
1726             if (apnContext.isDisconnected()) {
1727                 // The request is tearDown and but ApnContext is not connected.
1728                 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC.
1729                 apnContext.setState(DctConstants.State.IDLE);
1730                 if (!apnContext.isReady()) {
1731                     if (dcac != null) {
1732                         str = "cleanUpConnection: teardown, disconnected, !ready";
1733                         if (DBG) log(str + " apnContext=" + apnContext);
1734                         apnContext.requestLog(str);
1735                         dcac.tearDown(apnContext, "", null);
1736                     }
1737                     apnContext.setDataConnectionAc(null);
1738                 }
1739             } else {
1740                 // Connection is still there. Try to clean up.
1741                 if (dcac != null) {
1742                     if (apnContext.getState() != DctConstants.State.DISCONNECTING) {
1743                         boolean disconnectAll = false;
1744                         if (PhoneConstants.APN_TYPE_DUN.equals(apnContext.getApnType())) {
1745                             // CAF_MSIM is this below condition required.
1746                             // if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) {
1747                             if (teardownForDun()) {
1748                                 if (DBG) {
1749                                     log("cleanUpConnection: disconnectAll DUN connection");
1750                                 }
1751                                 // we need to tear it down - we brought it up just for dun and
1752                                 // other people are camped on it and now dun is done.  We need
1753                                 // to stop using it and let the normal apn list get used to find
1754                                 // connections for the remaining desired connections
1755                                 disconnectAll = true;
1756                             }
1757                         }
1758                         final int generation = apnContext.getConnectionGeneration();
1759                         str = "cleanUpConnection: tearing down" + (disconnectAll ? " all" : "") +
1760                                 " using gen#" + generation;
1761                         if (DBG) log(str + "apnContext=" + apnContext);
1762                         apnContext.requestLog(str);
1763                         Pair<ApnContext, Integer> pair =
1764                                 new Pair<ApnContext, Integer>(apnContext, generation);
1765                         Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
1766                         if (disconnectAll) {
1767                             apnContext.getDcAc().tearDownAll(apnContext.getReason(), msg);
1768                         } else {
1769                             apnContext.getDcAc()
1770                                 .tearDown(apnContext, apnContext.getReason(), msg);
1771                         }
1772                         apnContext.setState(DctConstants.State.DISCONNECTING);
1773                         mDisconnectPendingCount++;
1774                     }
1775                 } else {
1776                     // apn is connected but no reference to dcac.
1777                     // Should not be happen, but reset the state in case.
1778                     apnContext.setState(DctConstants.State.IDLE);
1779                     apnContext.requestLog("cleanUpConnection: connected, bug no DCAC");
1780                     mPhone.notifyDataConnection(apnContext.getReason(),
1781                                                 apnContext.getApnType());
1782                 }
1783             }
1784         } else {
1785             // force clean up the data connection.
1786             if (dcac != null) dcac.reqReset();
1787             apnContext.setState(DctConstants.State.IDLE);
1788             mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1789             apnContext.setDataConnectionAc(null);
1790         }
1791 
1792         // Make sure reconnection alarm is cleaned up if there is no ApnContext
1793         // associated to the connection.
1794         if (dcac != null) {
1795             cancelReconnectAlarm(apnContext);
1796         }
1797         str = "cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason();
1798         if (DBG) log(str + " apnContext=" + apnContext + " dcac=" + apnContext.getDcAc());
1799         apnContext.requestLog(str);
1800     }
1801 
fetchDunApn()1802     ApnSetting fetchDunApn() {
1803         if (SystemProperties.getBoolean("net.tethering.noprovisioning", false)) {
1804             log("fetchDunApn: net.tethering.noprovisioning=true ret: null");
1805             return null;
1806         }
1807         int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
1808         ApnSetting retDunSetting = null;
1809         String apnData = Settings.Global.getString(mResolver, Settings.Global.TETHER_DUN_APN);
1810         List<ApnSetting> dunSettings = ApnSetting.arrayFromString(apnData);
1811         IccRecords r = mIccRecords.get();
1812         for (ApnSetting dunSetting : dunSettings) {
1813             String operator = (r != null) ? r.getOperatorNumeric() : "";
1814             if (!ServiceState.bitmaskHasTech(dunSetting.bearerBitmask, bearer)) continue;
1815             if (dunSetting.numeric.equals(operator)) {
1816                 if (dunSetting.hasMvnoParams()) {
1817                     if (r != null && ApnSetting.mvnoMatches(r, dunSetting.mvnoType,
1818                             dunSetting.mvnoMatchData)) {
1819                         if (VDBG) {
1820                             log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
1821                         }
1822                         return dunSetting;
1823                     }
1824                 } else if (mMvnoMatched == false) {
1825                     if (VDBG) log("fetchDunApn: global TETHER_DUN_APN dunSetting=" + dunSetting);
1826                     return dunSetting;
1827                 }
1828             }
1829         }
1830 
1831         Context c = mPhone.getContext();
1832         String[] apnArrayData = c.getResources().getStringArray(R.array.config_tether_apndata);
1833         for (String apn : apnArrayData) {
1834             ApnSetting dunSetting = ApnSetting.fromString(apn);
1835             if (dunSetting != null) {
1836                 if (!ServiceState.bitmaskHasTech(dunSetting.bearerBitmask, bearer)) continue;
1837                 if (dunSetting.hasMvnoParams()) {
1838                     if (r != null && ApnSetting.mvnoMatches(r, dunSetting.mvnoType,
1839                             dunSetting.mvnoMatchData)) {
1840                         if (VDBG) {
1841                             log("fetchDunApn: config_tether_apndata mvno dunSetting=" + dunSetting);
1842                         }
1843                         return dunSetting;
1844                     }
1845                 } else if (mMvnoMatched == false) {
1846                     retDunSetting = dunSetting;
1847                 }
1848             }
1849         }
1850 
1851         if (VDBG) log("fetchDunApn: config_tether_apndata dunSetting=" + retDunSetting);
1852         return retDunSetting;
1853     }
1854 
hasMatchedTetherApnSetting()1855     public boolean hasMatchedTetherApnSetting() {
1856         ApnSetting matched = fetchDunApn();
1857         log("hasMatchedTetherApnSetting: APN=" + matched);
1858         return matched != null;
1859     }
1860 
1861     /**
1862      * Determine if DUN connection is special and we need to teardown on start/stop
1863      */
teardownForDun()1864     private boolean teardownForDun() {
1865         // CDMA always needs to do this the profile id is correct
1866         final int rilRat = mPhone.getServiceState().getRilDataRadioTechnology();
1867         if (ServiceState.isCdma(rilRat)) return true;
1868 
1869         return (fetchDunApn() != null);
1870     }
1871 
1872     /**
1873      * Cancels the alarm associated with apnContext.
1874      *
1875      * @param apnContext on which the alarm should be stopped.
1876      */
cancelReconnectAlarm(ApnContext apnContext)1877     private void cancelReconnectAlarm(ApnContext apnContext) {
1878         if (apnContext == null) return;
1879 
1880         PendingIntent intent = apnContext.getReconnectIntent();
1881 
1882         if (intent != null) {
1883                 AlarmManager am =
1884                     (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
1885                 am.cancel(intent);
1886                 apnContext.setReconnectIntent(null);
1887         }
1888     }
1889 
1890     /**
1891      * @param types comma delimited list of APN types
1892      * @return array of APN types
1893      */
parseTypes(String types)1894     private String[] parseTypes(String types) {
1895         String[] result;
1896         // If unset, set to DEFAULT.
1897         if (types == null || types.equals("")) {
1898             result = new String[1];
1899             result[0] = PhoneConstants.APN_TYPE_ALL;
1900         } else {
1901             result = types.split(",");
1902         }
1903         return result;
1904     }
1905 
isPermanentFail(DcFailCause dcFailCause)1906     boolean isPermanentFail(DcFailCause dcFailCause) {
1907         return (dcFailCause.isPermanentFail() &&
1908                 (mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST));
1909     }
1910 
makeApnSetting(Cursor cursor)1911     private ApnSetting makeApnSetting(Cursor cursor) {
1912         String[] types = parseTypes(
1913                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
1914         ApnSetting apn = new ApnSetting(
1915                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
1916                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
1917                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
1918                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
1919                 NetworkUtils.trimV4AddrZeros(
1920                         cursor.getString(
1921                         cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY))),
1922                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
1923                 NetworkUtils.trimV4AddrZeros(
1924                         cursor.getString(
1925                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC))),
1926                 NetworkUtils.trimV4AddrZeros(
1927                         cursor.getString(
1928                         cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY))),
1929                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
1930                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
1931                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
1932                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
1933                 types,
1934                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
1935                 cursor.getString(cursor.getColumnIndexOrThrow(
1936                         Telephony.Carriers.ROAMING_PROTOCOL)),
1937                 cursor.getInt(cursor.getColumnIndexOrThrow(
1938                         Telephony.Carriers.CARRIER_ENABLED)) == 1,
1939                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER)),
1940                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.BEARER_BITMASK)),
1941                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROFILE_ID)),
1942                 cursor.getInt(cursor.getColumnIndexOrThrow(
1943                         Telephony.Carriers.MODEM_COGNITIVE)) == 1,
1944                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS)),
1945                 cursor.getInt(cursor.getColumnIndexOrThrow(
1946                         Telephony.Carriers.WAIT_TIME)),
1947                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MAX_CONNS_TIME)),
1948                 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.MTU)),
1949                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_TYPE)),
1950                 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MVNO_MATCH_DATA)));
1951         return apn;
1952     }
1953 
createApnList(Cursor cursor)1954     private ArrayList<ApnSetting> createApnList(Cursor cursor) {
1955         ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>();
1956         ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>();
1957         IccRecords r = mIccRecords.get();
1958 
1959         if (cursor.moveToFirst()) {
1960             do {
1961                 ApnSetting apn = makeApnSetting(cursor);
1962                 if (apn == null) {
1963                     continue;
1964                 }
1965 
1966                 if (apn.hasMvnoParams()) {
1967                     if (r != null && ApnSetting.mvnoMatches(r, apn.mvnoType, apn.mvnoMatchData)) {
1968                         mvnoApns.add(apn);
1969                     }
1970                 } else {
1971                     mnoApns.add(apn);
1972                 }
1973             } while (cursor.moveToNext());
1974         }
1975 
1976         ArrayList<ApnSetting> result;
1977         if (mvnoApns.isEmpty()) {
1978             result = mnoApns;
1979             mMvnoMatched = false;
1980         } else {
1981             result = mvnoApns;
1982             mMvnoMatched = true;
1983         }
1984         if (DBG) log("createApnList: X result=" + result);
1985         return result;
1986     }
1987 
dataConnectionNotInUse(DcAsyncChannel dcac)1988     private boolean dataConnectionNotInUse(DcAsyncChannel dcac) {
1989         if (DBG) log("dataConnectionNotInUse: check if dcac is inuse dcac=" + dcac);
1990         for (ApnContext apnContext : mApnContexts.values()) {
1991             if (apnContext.getDcAc() == dcac) {
1992                 if (DBG) log("dataConnectionNotInUse: in use by apnContext=" + apnContext);
1993                 return false;
1994             }
1995         }
1996         // TODO: Fix retry handling so free DataConnections have empty apnlists.
1997         // Probably move retry handling into DataConnections and reduce complexity
1998         // of DCT.
1999         if (DBG) log("dataConnectionNotInUse: tearDownAll");
2000         dcac.tearDownAll("No connection", null);
2001         if (DBG) log("dataConnectionNotInUse: not in use return true");
2002         return true;
2003     }
2004 
findFreeDataConnection()2005     private DcAsyncChannel findFreeDataConnection() {
2006         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
2007             if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) {
2008                 if (DBG) {
2009                     log("findFreeDataConnection: found free DataConnection=" +
2010                         " dcac=" + dcac);
2011                 }
2012                 return dcac;
2013             }
2014         }
2015         log("findFreeDataConnection: NO free DataConnection");
2016         return null;
2017     }
2018 
setupData(ApnContext apnContext, int radioTech)2019     private boolean setupData(ApnContext apnContext, int radioTech) {
2020         if (DBG) log("setupData: apnContext=" + apnContext);
2021         apnContext.requestLog("setupData");
2022         ApnSetting apnSetting;
2023         DcAsyncChannel dcac = null;
2024 
2025         apnSetting = apnContext.getNextApnSetting();
2026 
2027         if (apnSetting == null) {
2028             if (DBG) log("setupData: return for no apn found!");
2029             return false;
2030         }
2031 
2032         int profileId = apnSetting.profileId;
2033         if (profileId == 0) {
2034             profileId = getApnProfileID(apnContext.getApnType());
2035         }
2036 
2037         // On CDMA, if we're explicitly asking for DUN, we need have
2038         // a dun-profiled connection so we can't share an existing one
2039         // On GSM/LTE we can share existing apn connections provided they support
2040         // this type.
2041         if (apnContext.getApnType() != PhoneConstants.APN_TYPE_DUN ||
2042                 teardownForDun() == false) {
2043             dcac = checkForCompatibleConnectedApnContext(apnContext);
2044             if (dcac != null) {
2045                 // Get the dcacApnSetting for the connection we want to share.
2046                 ApnSetting dcacApnSetting = dcac.getApnSettingSync();
2047                 if (dcacApnSetting != null) {
2048                     // Setting is good, so use it.
2049                     apnSetting = dcacApnSetting;
2050                 }
2051             }
2052         }
2053         if (dcac == null) {
2054             if (isOnlySingleDcAllowed(radioTech)) {
2055                 if (isHigherPriorityApnContextActive(apnContext)) {
2056                     if (DBG) {
2057                         log("setupData: Higher priority ApnContext active.  Ignoring call");
2058                     }
2059                     return false;
2060                 }
2061 
2062                 // Only lower priority calls left.  Disconnect them all in this single PDP case
2063                 // so that we can bring up the requested higher priority call (once we receive
2064                 // response for deactivate request for the calls we are about to disconnect
2065                 if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
2066                     // If any call actually requested to be disconnected, means we can't
2067                     // bring up this connection yet as we need to wait for those data calls
2068                     // to be disconnected.
2069                     if (DBG) log("setupData: Some calls are disconnecting first.  Wait and retry");
2070                     return false;
2071                 }
2072 
2073                 // No other calls are active, so proceed
2074                 if (DBG) log("setupData: Single pdp. Continue setting up data call.");
2075             }
2076 
2077             dcac = findFreeDataConnection();
2078 
2079             if (dcac == null) {
2080                 dcac = createDataConnection();
2081             }
2082 
2083             if (dcac == null) {
2084                 if (DBG) log("setupData: No free DataConnection and couldn't create one, WEIRD");
2085                 return false;
2086             }
2087         }
2088         final int generation = apnContext.incAndGetConnectionGeneration();
2089         if (DBG) {
2090             log("setupData: dcac=" + dcac + " apnSetting=" + apnSetting + " gen#=" + generation);
2091         }
2092 
2093         apnContext.setDataConnectionAc(dcac);
2094         apnContext.setApnSetting(apnSetting);
2095         apnContext.setState(DctConstants.State.CONNECTING);
2096         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
2097 
2098         Message msg = obtainMessage();
2099         msg.what = DctConstants.EVENT_DATA_SETUP_COMPLETE;
2100         msg.obj = new Pair<ApnContext, Integer>(apnContext, generation);
2101         dcac.bringUp(apnContext, profileId, radioTech, msg, generation);
2102 
2103         if (DBG) log("setupData: initing!");
2104         return true;
2105     }
2106 
setInitialAttachApn()2107     private void setInitialAttachApn() {
2108         ApnSetting iaApnSetting = null;
2109         ApnSetting defaultApnSetting = null;
2110         ApnSetting firstApnSetting = null;
2111 
2112         log("setInitialApn: E mPreferredApn=" + mPreferredApn);
2113 
2114         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
2115             firstApnSetting = mAllApnSettings.get(0);
2116             log("setInitialApn: firstApnSetting=" + firstApnSetting);
2117 
2118             // Search for Initial APN setting and the first apn that can handle default
2119             for (ApnSetting apn : mAllApnSettings) {
2120                 // Can't use apn.canHandleType(), as that returns true for APNs that have no type.
2121                 if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_IA) &&
2122                         apn.carrierEnabled) {
2123                     // The Initial Attach APN is highest priority so use it if there is one
2124                     log("setInitialApn: iaApnSetting=" + apn);
2125                     iaApnSetting = apn;
2126                     break;
2127                 } else if ((defaultApnSetting == null)
2128                         && (apn.canHandleType(PhoneConstants.APN_TYPE_DEFAULT))) {
2129                     // Use the first default apn if no better choice
2130                     log("setInitialApn: defaultApnSetting=" + apn);
2131                     defaultApnSetting = apn;
2132                 }
2133             }
2134         }
2135 
2136         // The priority of apn candidates from highest to lowest is:
2137         //   1) APN_TYPE_IA (Initial Attach)
2138         //   2) mPreferredApn, i.e. the current preferred apn
2139         //   3) The first apn that than handle APN_TYPE_DEFAULT
2140         //   4) The first APN we can find.
2141 
2142         ApnSetting initialAttachApnSetting = null;
2143         if (iaApnSetting != null) {
2144             if (DBG) log("setInitialAttachApn: using iaApnSetting");
2145             initialAttachApnSetting = iaApnSetting;
2146         } else if (mPreferredApn != null) {
2147             if (DBG) log("setInitialAttachApn: using mPreferredApn");
2148             initialAttachApnSetting = mPreferredApn;
2149         } else if (defaultApnSetting != null) {
2150             if (DBG) log("setInitialAttachApn: using defaultApnSetting");
2151             initialAttachApnSetting = defaultApnSetting;
2152         } else if (firstApnSetting != null) {
2153             if (DBG) log("setInitialAttachApn: using firstApnSetting");
2154             initialAttachApnSetting = firstApnSetting;
2155         }
2156 
2157         if (initialAttachApnSetting == null) {
2158             if (DBG) log("setInitialAttachApn: X There in no available apn");
2159         } else {
2160             if (DBG) log("setInitialAttachApn: X selected Apn=" + initialAttachApnSetting);
2161 
2162             mPhone.mCi.setInitialAttachApn(initialAttachApnSetting.apn,
2163                     initialAttachApnSetting.protocol, initialAttachApnSetting.authType,
2164                     initialAttachApnSetting.user, initialAttachApnSetting.password, null);
2165         }
2166     }
2167 
2168     /**
2169      * Handles changes to the APN database.
2170      */
onApnChanged()2171     private void onApnChanged() {
2172         DctConstants.State overallState = getOverallState();
2173         boolean isDisconnected = (overallState == DctConstants.State.IDLE ||
2174                 overallState == DctConstants.State.FAILED);
2175 
2176         if (mPhone instanceof GsmCdmaPhone) {
2177             // The "current" may no longer be valid.  MMS depends on this to send properly. TBD
2178             ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider();
2179         }
2180 
2181         // TODO: It'd be nice to only do this if the changed entrie(s)
2182         // match the current operator.
2183         if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
2184         createAllApnList();
2185         setInitialAttachApn();
2186         cleanUpConnectionsOnUpdatedApns(!isDisconnected);
2187 
2188         // FIXME: See bug 17426028 maybe no conditional is needed.
2189         if (mPhone.getSubId() == SubscriptionManager.getDefaultDataSubscriptionId()) {
2190             setupDataOnConnectableApns(Phone.REASON_APN_CHANGED);
2191         }
2192     }
2193 
2194     /**
2195      * @param cid Connection id provided from RIL.
2196      * @return DataConnectionAc associated with specified cid.
2197      */
findDataConnectionAcByCid(int cid)2198     private DcAsyncChannel findDataConnectionAcByCid(int cid) {
2199         for (DcAsyncChannel dcac : mDataConnectionAcHashMap.values()) {
2200             if (dcac.getCidSync() == cid) {
2201                 return dcac;
2202             }
2203         }
2204         return null;
2205     }
2206 
2207     // TODO: For multiple Active APNs not exactly sure how to do this.
gotoIdleAndNotifyDataConnection(String reason)2208     private void gotoIdleAndNotifyDataConnection(String reason) {
2209         if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
2210         notifyDataConnection(reason);
2211     }
2212 
2213     /**
2214      * "Active" here means ApnContext isEnabled() and not in FAILED state
2215      * @param apnContext to compare with
2216      * @return true if higher priority active apn found
2217      */
isHigherPriorityApnContextActive(ApnContext apnContext)2218     private boolean isHigherPriorityApnContextActive(ApnContext apnContext) {
2219         for (ApnContext otherContext : mPrioritySortedApnContexts) {
2220             if (apnContext.getApnType().equalsIgnoreCase(otherContext.getApnType())) return false;
2221             if (otherContext.isEnabled() && otherContext.getState() != DctConstants.State.FAILED) {
2222                 return true;
2223             }
2224         }
2225         return false;
2226     }
2227 
2228     /**
2229      * Reports if we support multiple connections or not.
2230      * This is a combination of factors, based on carrier and RAT.
2231      * @param rilRadioTech the RIL Radio Tech currently in use
2232      * @return true if only single DataConnection is allowed
2233      */
isOnlySingleDcAllowed(int rilRadioTech)2234     private boolean isOnlySingleDcAllowed(int rilRadioTech) {
2235         int[] singleDcRats = mPhone.getContext().getResources().getIntArray(
2236                 com.android.internal.R.array.config_onlySingleDcAllowed);
2237         boolean onlySingleDcAllowed = false;
2238         if (Build.IS_DEBUGGABLE &&
2239                 SystemProperties.getBoolean("persist.telephony.test.singleDc", false)) {
2240             onlySingleDcAllowed = true;
2241         }
2242         if (singleDcRats != null) {
2243             for (int i=0; i < singleDcRats.length && onlySingleDcAllowed == false; i++) {
2244                 if (rilRadioTech == singleDcRats[i]) onlySingleDcAllowed = true;
2245             }
2246         }
2247 
2248         if (DBG) log("isOnlySingleDcAllowed(" + rilRadioTech + "): " + onlySingleDcAllowed);
2249         return onlySingleDcAllowed;
2250     }
2251 
sendRestartRadio()2252     void sendRestartRadio() {
2253         if (DBG)log("sendRestartRadio:");
2254         Message msg = obtainMessage(DctConstants.EVENT_RESTART_RADIO);
2255         sendMessage(msg);
2256     }
2257 
restartRadio()2258     private void restartRadio() {
2259         if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
2260         cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
2261         mPhone.getServiceStateTracker().powerOffRadioSafely(this);
2262         /* Note: no need to call setRadioPower(true).  Assuming the desired
2263          * radio power state is still ON (as tracked by ServiceStateTracker),
2264          * ServiceStateTracker will call setRadioPower when it receives the
2265          * RADIO_STATE_CHANGED notification for the power off.  And if the
2266          * desired power state has changed in the interim, we don't want to
2267          * override it with an unconditional power on.
2268          */
2269 
2270         int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
2271         SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset + 1));
2272     }
2273 
2274     /**
2275      * Return true if data connection need to be setup after disconnected due to
2276      * reason.
2277      *
2278      * @param apnContext APN context
2279      * @return true if try setup data connection is need for this reason
2280      */
retryAfterDisconnected(ApnContext apnContext)2281     private boolean retryAfterDisconnected(ApnContext apnContext) {
2282         boolean retry = true;
2283         String reason = apnContext.getReason();
2284 
2285         if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ||
2286                 (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())
2287                  && isHigherPriorityApnContextActive(apnContext))) {
2288             retry = false;
2289         }
2290         return retry;
2291     }
2292 
startAlarmForReconnect(long delay, ApnContext apnContext)2293     private void startAlarmForReconnect(long delay, ApnContext apnContext) {
2294         String apnType = apnContext.getApnType();
2295 
2296         Intent intent = new Intent(INTENT_RECONNECT_ALARM + "." + apnType);
2297         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
2298         intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, apnType);
2299         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
2300 
2301         // Get current sub id.
2302         int subId = SubscriptionManager.getDefaultDataSubscriptionId();
2303         intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId);
2304 
2305         if (DBG) {
2306             log("startAlarmForReconnect: delay=" + delay + " action=" + intent.getAction()
2307                     + " apn=" + apnContext);
2308         }
2309 
2310         PendingIntent alarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0,
2311                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
2312         apnContext.setReconnectIntent(alarmIntent);
2313 
2314         // Use the exact timer instead of the inexact one to provide better user experience.
2315         // In some extreme cases, we saw the retry was delayed for few minutes.
2316         // Note that if the stated trigger time is in the past, the alarm will be triggered
2317         // immediately.
2318         mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
2319                 SystemClock.elapsedRealtime() + delay, alarmIntent);
2320     }
2321 
notifyNoData(DcFailCause lastFailCauseCode, ApnContext apnContext)2322     private void notifyNoData(DcFailCause lastFailCauseCode,
2323                               ApnContext apnContext) {
2324         if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
2325         if (isPermanentFail(lastFailCauseCode)
2326             && (!apnContext.getApnType().equals(PhoneConstants.APN_TYPE_DEFAULT))) {
2327             mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
2328         }
2329     }
2330 
getAutoAttachOnCreation()2331     public boolean getAutoAttachOnCreation() {
2332         return mAutoAttachOnCreation.get();
2333     }
2334 
onRecordsLoadedOrSubIdChanged()2335     private void onRecordsLoadedOrSubIdChanged() {
2336         if (DBG) log("onRecordsLoadedOrSubIdChanged: createAllApnList");
2337         mAutoAttachOnCreationConfig = mPhone.getContext().getResources()
2338                 .getBoolean(com.android.internal.R.bool.config_auto_attach_data_on_creation);
2339 
2340         createAllApnList();
2341         setInitialAttachApn();
2342         if (mPhone.mCi.getRadioState().isOn()) {
2343             if (DBG) log("onRecordsLoadedOrSubIdChanged: notifying data availability");
2344             notifyOffApnsOfAvailability(Phone.REASON_SIM_LOADED);
2345         }
2346         setupDataOnConnectableApns(Phone.REASON_SIM_LOADED);
2347     }
2348 
setApnsEnabledByCarrier(boolean enabled)2349     public void setApnsEnabledByCarrier(boolean enabled) {
2350         Message msg = obtainMessage(DctConstants.EVENT_SET_CARRIER_DATA_ENABLED);
2351         msg.arg1 = (enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
2352         sendMessage(msg);
2353     }
2354 
2355     /**
2356      * Action set from carrier signalling broadcast receivers to enable/disable metered apns.
2357      */
onSetCarrierDataEnabled(boolean enabled)2358     private void onSetCarrierDataEnabled(boolean enabled) {
2359         synchronized (mDataEnabledSettings) {
2360             if (enabled != mDataEnabledSettings.isCarrierDataEnabled()) {
2361                 if (DBG) {
2362                     log("carrier Action: set metered apns enabled: " + enabled);
2363                 }
2364 
2365                 // Disable/enable all metered apns
2366                 mDataEnabledSettings.setCarrierDataEnabled(enabled);
2367 
2368                 if (!enabled) {
2369                     // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
2370                     mPhone.notifyOtaspChanged(ServiceStateTracker.OTASP_SIM_UNPROVISIONED);
2371                     // Tear down all metered apns
2372                     cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
2373                 } else {
2374                     teardownRestrictedMeteredConnections();
2375                     setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
2376                 }
2377             }
2378         }
2379     }
2380 
2381     /**
2382      * Action set from carrier signalling broadcast receivers to enable/disable radio
2383      */
carrierActionSetRadioEnabled(boolean enabled)2384     public void carrierActionSetRadioEnabled(boolean enabled) {
2385         if (DBG) {
2386             log("carrier Action: set radio enabled: " + enabled);
2387         }
2388         final ServiceStateTracker sst = mPhone.getServiceStateTracker();
2389         sst.setRadioPowerFromCarrier(enabled);
2390     }
2391 
onSimNotReady()2392     private void onSimNotReady() {
2393         if (DBG) log("onSimNotReady");
2394 
2395         cleanUpAllConnections(true, Phone.REASON_SIM_NOT_READY);
2396         mAllApnSettings = null;
2397         mAutoAttachOnCreationConfig = false;
2398     }
2399 
onSetDependencyMet(String apnType, boolean met)2400     private void onSetDependencyMet(String apnType, boolean met) {
2401         // don't allow users to tweak hipri to work around default dependency not met
2402         if (PhoneConstants.APN_TYPE_HIPRI.equals(apnType)) return;
2403 
2404         ApnContext apnContext = mApnContexts.get(apnType);
2405         if (apnContext == null) {
2406             loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
2407                     apnType + ", " + met + ")");
2408             return;
2409         }
2410         applyNewState(apnContext, apnContext.isEnabled(), met);
2411         if (PhoneConstants.APN_TYPE_DEFAULT.equals(apnType)) {
2412             // tie actions on default to similar actions on HIPRI regarding dependencyMet
2413             apnContext = mApnContexts.get(PhoneConstants.APN_TYPE_HIPRI);
2414             if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met);
2415         }
2416     }
2417 
setPolicyDataEnabled(boolean enabled)2418     public void setPolicyDataEnabled(boolean enabled) {
2419         if (DBG) log("setPolicyDataEnabled: " + enabled);
2420         Message msg = obtainMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE);
2421         msg.arg1 = (enabled ? DctConstants.ENABLED : DctConstants.DISABLED);
2422         sendMessage(msg);
2423     }
2424 
onSetPolicyDataEnabled(boolean enabled)2425     private void onSetPolicyDataEnabled(boolean enabled) {
2426         synchronized (mDataEnabledSettings) {
2427             final boolean prevEnabled = getAnyDataEnabled();
2428             if (mDataEnabledSettings.isPolicyDataEnabled() != enabled) {
2429                 mDataEnabledSettings.setPolicyDataEnabled(enabled);
2430                 // TODO: We should register for DataEnabledSetting's data enabled/disabled event and
2431                 // handle the rest from there.
2432                 if (prevEnabled != getAnyDataEnabled()) {
2433                     if (!prevEnabled) {
2434                         teardownRestrictedMeteredConnections();
2435                         onTrySetupData(Phone.REASON_DATA_ENABLED);
2436                     } else {
2437                         onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
2438                     }
2439                 }
2440             }
2441         }
2442     }
2443 
applyNewState(ApnContext apnContext, boolean enabled, boolean met)2444     private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
2445         boolean cleanup = false;
2446         boolean trySetup = false;
2447         String str ="applyNewState(" + apnContext.getApnType() + ", " + enabled +
2448                 "(" + apnContext.isEnabled() + "), " + met + "(" +
2449                 apnContext.getDependencyMet() +"))";
2450         if (DBG) log(str);
2451         apnContext.requestLog(str);
2452 
2453         if (apnContext.isReady()) {
2454             cleanup = true;
2455             if (enabled && met) {
2456                 DctConstants.State state = apnContext.getState();
2457                 switch(state) {
2458                     case CONNECTING:
2459                     case SCANNING:
2460                     case CONNECTED:
2461                     case DISCONNECTING:
2462                         // We're "READY" and active so just return
2463                         if (DBG) log("applyNewState: 'ready' so return");
2464                         apnContext.requestLog("applyNewState state=" + state + ", so return");
2465                         return;
2466                     case IDLE:
2467                         // fall through: this is unexpected but if it happens cleanup and try setup
2468                     case FAILED:
2469                     case RETRYING: {
2470                         // We're "READY" but not active so disconnect (cleanup = true) and
2471                         // connect (trySetup = true) to be sure we retry the connection.
2472                         trySetup = true;
2473                         apnContext.setReason(Phone.REASON_DATA_ENABLED);
2474                         break;
2475                     }
2476                 }
2477             } else if (met) {
2478                 apnContext.setReason(Phone.REASON_DATA_DISABLED);
2479                 // If ConnectivityService has disabled this network, stop trying to bring
2480                 // it up, but do not tear it down - ConnectivityService will do that
2481                 // directly by talking with the DataConnection.
2482                 //
2483                 // This doesn't apply to DUN, however.  Those connections have special
2484                 // requirements from carriers and we need stop using them when the dun
2485                 // request goes away.  This applies to both CDMA and GSM because they both
2486                 // can declare the DUN APN sharable by default traffic, thus still satisfying
2487                 // those requests and not torn down organically.
2488                 if (apnContext.getApnType() == PhoneConstants.APN_TYPE_DUN && teardownForDun()) {
2489                     cleanup = true;
2490                 } else {
2491                     cleanup = false;
2492                 }
2493             } else {
2494                 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
2495             }
2496         } else {
2497             if (enabled && met) {
2498                 if (apnContext.isEnabled()) {
2499                     apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
2500                 } else {
2501                     apnContext.setReason(Phone.REASON_DATA_ENABLED);
2502                 }
2503                 if (apnContext.getState() == DctConstants.State.FAILED) {
2504                     apnContext.setState(DctConstants.State.IDLE);
2505                 }
2506                 trySetup = true;
2507             }
2508         }
2509         apnContext.setEnabled(enabled);
2510         apnContext.setDependencyMet(met);
2511         if (cleanup) cleanUpConnection(true, apnContext);
2512         if (trySetup) {
2513             apnContext.resetErrorCodeRetries();
2514             trySetupData(apnContext);
2515         }
2516     }
2517 
checkForCompatibleConnectedApnContext(ApnContext apnContext)2518     private DcAsyncChannel checkForCompatibleConnectedApnContext(ApnContext apnContext) {
2519         String apnType = apnContext.getApnType();
2520         ApnSetting dunSetting = null;
2521 
2522         if (PhoneConstants.APN_TYPE_DUN.equals(apnType)) {
2523             dunSetting = fetchDunApn();
2524         }
2525         if (DBG) {
2526             log("checkForCompatibleConnectedApnContext: apnContext=" + apnContext );
2527         }
2528 
2529         DcAsyncChannel potentialDcac = null;
2530         ApnContext potentialApnCtx = null;
2531         for (ApnContext curApnCtx : mApnContexts.values()) {
2532             DcAsyncChannel curDcac = curApnCtx.getDcAc();
2533             if (curDcac != null) {
2534                 ApnSetting apnSetting = curApnCtx.getApnSetting();
2535                 log("apnSetting: " + apnSetting);
2536                 if (dunSetting != null) {
2537                     if (dunSetting.equals(apnSetting)) {
2538                         switch (curApnCtx.getState()) {
2539                             case CONNECTED:
2540                                 if (DBG) {
2541                                     log("checkForCompatibleConnectedApnContext:"
2542                                             + " found dun conn=" + curDcac
2543                                             + " curApnCtx=" + curApnCtx);
2544                                 }
2545                                 return curDcac;
2546                             case RETRYING:
2547                             case CONNECTING:
2548                                 potentialDcac = curDcac;
2549                                 potentialApnCtx = curApnCtx;
2550                             default:
2551                                 // Not connected, potential unchanged
2552                                 break;
2553                         }
2554                     }
2555                 } else if (apnSetting != null && apnSetting.canHandleType(apnType)) {
2556                     switch (curApnCtx.getState()) {
2557                         case CONNECTED:
2558                             if (DBG) {
2559                                 log("checkForCompatibleConnectedApnContext:"
2560                                         + " found canHandle conn=" + curDcac
2561                                         + " curApnCtx=" + curApnCtx);
2562                             }
2563                             return curDcac;
2564                         case RETRYING:
2565                         case CONNECTING:
2566                             potentialDcac = curDcac;
2567                             potentialApnCtx = curApnCtx;
2568                         default:
2569                             // Not connected, potential unchanged
2570                             break;
2571                     }
2572                 }
2573             } else {
2574                 if (VDBG) {
2575                     log("checkForCompatibleConnectedApnContext: not conn curApnCtx=" + curApnCtx);
2576                 }
2577             }
2578         }
2579         if (potentialDcac != null) {
2580             if (DBG) {
2581                 log("checkForCompatibleConnectedApnContext: found potential conn=" + potentialDcac
2582                         + " curApnCtx=" + potentialApnCtx);
2583             }
2584             return potentialDcac;
2585         }
2586 
2587         if (DBG) log("checkForCompatibleConnectedApnContext: NO conn apnContext=" + apnContext);
2588         return null;
2589     }
2590 
setEnabled(int id, boolean enable)2591     public void setEnabled(int id, boolean enable) {
2592         Message msg = obtainMessage(DctConstants.EVENT_ENABLE_NEW_APN);
2593         msg.arg1 = id;
2594         msg.arg2 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
2595         sendMessage(msg);
2596     }
2597 
onEnableApn(int apnId, int enabled)2598     private void onEnableApn(int apnId, int enabled) {
2599         ApnContext apnContext = mApnContextsById.get(apnId);
2600         if (apnContext == null) {
2601             loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
2602             return;
2603         }
2604         // TODO change our retry manager to use the appropriate numbers for the new APN
2605         if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
2606         applyNewState(apnContext, enabled == DctConstants.ENABLED, apnContext.getDependencyMet());
2607     }
2608 
2609     // TODO: We shouldnt need this.
onTrySetupData(String reason)2610     private boolean onTrySetupData(String reason) {
2611         if (DBG) log("onTrySetupData: reason=" + reason);
2612         setupDataOnConnectableApns(reason);
2613         return true;
2614     }
2615 
onTrySetupData(ApnContext apnContext)2616     private boolean onTrySetupData(ApnContext apnContext) {
2617         if (DBG) log("onTrySetupData: apnContext=" + apnContext);
2618         return trySetupData(apnContext);
2619     }
2620 
2621     /**
2622      * Return current {@link android.provider.Settings.Global#MOBILE_DATA} value.
2623      */
2624     //TODO: Merge this into DataSettings. And probably should rename to getUserDataEnabled().
getDataEnabled()2625     public boolean getDataEnabled() {
2626         final int device_provisioned =
2627                 Settings.Global.getInt(mResolver, Settings.Global.DEVICE_PROVISIONED, 0);
2628 
2629         boolean retVal = "true".equalsIgnoreCase(SystemProperties.get(
2630                 "ro.com.android.mobiledata", "true"));
2631         if (TelephonyManager.getDefault().getSimCount() == 1) {
2632             retVal = Settings.Global.getInt(mResolver, Settings.Global.MOBILE_DATA,
2633                     retVal ? 1 : 0) != 0;
2634         } else {
2635             int phoneSubId = mPhone.getSubId();
2636             try {
2637                 retVal = TelephonyManager.getIntWithSubId(mResolver,
2638                         Settings.Global.MOBILE_DATA, phoneSubId) != 0;
2639             } catch (SettingNotFoundException e) {
2640                 // use existing retVal
2641             }
2642         }
2643         if (VDBG) log("getDataEnabled: retVal=" + retVal);
2644         if (device_provisioned == 0) {
2645             // device is still getting provisioned - use whatever setting they
2646             // want during this process
2647             //
2648             // use the normal data_enabled setting (retVal, determined above)
2649             // as the default if nothing else is set
2650             final String prov_property = SystemProperties.get("ro.com.android.prov_mobiledata",
2651                   retVal ? "true" : "false");
2652             retVal = "true".equalsIgnoreCase(prov_property);
2653 
2654             final int prov_mobile_data = Settings.Global.getInt(mResolver,
2655                     Settings.Global.DEVICE_PROVISIONING_MOBILE_DATA_ENABLED,
2656                     retVal ? 1 : 0);
2657             retVal = prov_mobile_data != 0;
2658             log("getDataEnabled during provisioning retVal=" + retVal + " - (" + prov_property +
2659                     ", " + prov_mobile_data + ")");
2660         }
2661 
2662         return retVal;
2663     }
2664 
2665     /**
2666      * Modify {@link android.provider.Settings.Global#DATA_ROAMING} value.
2667      */
setDataOnRoamingEnabled(boolean enabled)2668     public void setDataOnRoamingEnabled(boolean enabled) {
2669         final int phoneSubId = mPhone.getSubId();
2670         if (getDataOnRoamingEnabled() != enabled) {
2671             int roaming = enabled ? 1 : 0;
2672 
2673             // For single SIM phones, this is a per phone property.
2674             if (TelephonyManager.getDefault().getSimCount() == 1) {
2675                 Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING, roaming);
2676             } else {
2677                 Settings.Global.putInt(mResolver, Settings.Global.DATA_ROAMING +
2678                          phoneSubId, roaming);
2679             }
2680 
2681             mSubscriptionManager.setDataRoaming(roaming, phoneSubId);
2682             // will trigger handleDataOnRoamingChange() through observer
2683             if (DBG) {
2684                log("setDataOnRoamingEnabled: set phoneSubId=" + phoneSubId
2685                        + " isRoaming=" + enabled);
2686             }
2687         } else {
2688             if (DBG) {
2689                 log("setDataOnRoamingEnabled: unchanged phoneSubId=" + phoneSubId
2690                         + " isRoaming=" + enabled);
2691              }
2692         }
2693     }
2694 
2695     /**
2696      * Return current {@link android.provider.Settings.Global#DATA_ROAMING} value.
2697      */
getDataOnRoamingEnabled()2698     public boolean getDataOnRoamingEnabled() {
2699         boolean isDataRoamingEnabled = "true".equalsIgnoreCase(SystemProperties.get(
2700                 "ro.com.android.dataroaming", "false"));
2701         final int phoneSubId = mPhone.getSubId();
2702 
2703         try {
2704             // For single SIM phones, this is a per phone property.
2705             if (TelephonyManager.getDefault().getSimCount() == 1) {
2706                 isDataRoamingEnabled = Settings.Global.getInt(mResolver,
2707                         Settings.Global.DATA_ROAMING, isDataRoamingEnabled ? 1 : 0) != 0;
2708             } else {
2709                 isDataRoamingEnabled = TelephonyManager.getIntWithSubId(mResolver,
2710                         Settings.Global.DATA_ROAMING, phoneSubId) != 0;
2711             }
2712         } catch (SettingNotFoundException snfe) {
2713             if (DBG) log("getDataOnRoamingEnabled: SettingNofFoundException snfe=" + snfe);
2714         }
2715         if (VDBG) {
2716             log("getDataOnRoamingEnabled: phoneSubId=" + phoneSubId +
2717                     " isDataRoamingEnabled=" + isDataRoamingEnabled);
2718         }
2719         return isDataRoamingEnabled;
2720     }
2721 
onRoamingOff()2722     private void onRoamingOff() {
2723         if (DBG) log("onRoamingOff");
2724 
2725         if (!mDataEnabledSettings.isUserDataEnabled()) return;
2726 
2727         if (getDataOnRoamingEnabled() == false) {
2728             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_OFF);
2729             setupDataOnConnectableApns(Phone.REASON_ROAMING_OFF);
2730         } else {
2731             notifyDataConnection(Phone.REASON_ROAMING_OFF);
2732         }
2733     }
2734 
onRoamingOn()2735     private void onRoamingOn() {
2736         if (DBG) log("onRoamingOn");
2737 
2738         if (!mDataEnabledSettings.isUserDataEnabled()) {
2739             if (DBG) log("data not enabled by user");
2740             return;
2741         }
2742 
2743         // Check if the device is actually data roaming
2744         if (!mPhone.getServiceState().getDataRoaming()) {
2745             if (DBG) log("device is not roaming. ignored the request.");
2746             return;
2747         }
2748 
2749         if (getDataOnRoamingEnabled()) {
2750             if (DBG) log("onRoamingOn: setup data on roaming");
2751             setupDataOnConnectableApns(Phone.REASON_ROAMING_ON);
2752             notifyDataConnection(Phone.REASON_ROAMING_ON);
2753         } else {
2754             if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
2755             cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
2756             notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
2757         }
2758     }
2759 
onRadioAvailable()2760     private void onRadioAvailable() {
2761         if (DBG) log("onRadioAvailable");
2762         if (mPhone.getSimulatedRadioControl() != null) {
2763             // Assume data is connected on the simulator
2764             // FIXME  this can be improved
2765             // setState(DctConstants.State.CONNECTED);
2766             notifyDataConnection(null);
2767 
2768             log("onRadioAvailable: We're on the simulator; assuming data is connected");
2769         }
2770 
2771         IccRecords r = mIccRecords.get();
2772         if (r != null && r.getRecordsLoaded()) {
2773             notifyOffApnsOfAvailability(null);
2774         }
2775 
2776         if (getOverallState() != DctConstants.State.IDLE) {
2777             cleanUpConnection(true, null);
2778         }
2779     }
2780 
onRadioOffOrNotAvailable()2781     private void onRadioOffOrNotAvailable() {
2782         // Make sure our reconnect delay starts at the initial value
2783         // next time the radio comes on
2784 
2785         mReregisterOnReconnectFailure = false;
2786 
2787         if (mPhone.getSimulatedRadioControl() != null) {
2788             // Assume data is connected on the simulator
2789             // FIXME  this can be improved
2790             log("We're on the simulator; assuming radio off is meaningless");
2791         } else {
2792             if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
2793             cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
2794         }
2795         notifyOffApnsOfAvailability(null);
2796     }
2797 
completeConnection(ApnContext apnContext)2798     private void completeConnection(ApnContext apnContext) {
2799 
2800         if (DBG) log("completeConnection: successful, notify the world apnContext=" + apnContext);
2801 
2802         if (mIsProvisioning && !TextUtils.isEmpty(mProvisioningUrl)) {
2803             if (DBG) {
2804                 log("completeConnection: MOBILE_PROVISIONING_ACTION url="
2805                         + mProvisioningUrl);
2806             }
2807             Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN,
2808                     Intent.CATEGORY_APP_BROWSER);
2809             newIntent.setData(Uri.parse(mProvisioningUrl));
2810             newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT |
2811                     Intent.FLAG_ACTIVITY_NEW_TASK);
2812             try {
2813                 mPhone.getContext().startActivity(newIntent);
2814             } catch (ActivityNotFoundException e) {
2815                 loge("completeConnection: startActivityAsUser failed" + e);
2816             }
2817         }
2818         mIsProvisioning = false;
2819         mProvisioningUrl = null;
2820         if (mProvisioningSpinner != null) {
2821             sendMessage(obtainMessage(DctConstants.CMD_CLEAR_PROVISIONING_SPINNER,
2822                     mProvisioningSpinner));
2823         }
2824 
2825         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
2826         startNetStatPoll();
2827         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
2828     }
2829 
2830     /**
2831      * A SETUP (aka bringUp) has completed, possibly with an error. If
2832      * there is an error this method will call {@link #onDataSetupCompleteError}.
2833      */
onDataSetupComplete(AsyncResult ar)2834     private void onDataSetupComplete(AsyncResult ar) {
2835 
2836         DcFailCause cause = DcFailCause.UNKNOWN;
2837         boolean handleError = false;
2838         ApnContext apnContext = getValidApnContext(ar, "onDataSetupComplete");
2839 
2840         if (apnContext == null) return;
2841 
2842         if (ar.exception == null) {
2843             DcAsyncChannel dcac = apnContext.getDcAc();
2844 
2845             if (RADIO_TESTS) {
2846                 // Note: To change radio.test.onDSC.null.dcac from command line you need to
2847                 // adb root and adb remount and from the command line you can only change the
2848                 // value to 1 once. To change it a second time you can reboot or execute
2849                 // adb shell stop and then adb shell start. The command line to set the value is:
2850                 // adb shell sqlite3 /data/data/com.android.providers.settings/databases/settings.db "insert into system (name,value) values ('radio.test.onDSC.null.dcac', '1');"
2851                 ContentResolver cr = mPhone.getContext().getContentResolver();
2852                 String radioTestProperty = "radio.test.onDSC.null.dcac";
2853                 if (Settings.System.getInt(cr, radioTestProperty, 0) == 1) {
2854                     log("onDataSetupComplete: " + radioTestProperty +
2855                             " is true, set dcac to null and reset property to false");
2856                     dcac = null;
2857                     Settings.System.putInt(cr, radioTestProperty, 0);
2858                     log("onDataSetupComplete: " + radioTestProperty + "=" +
2859                             Settings.System.getInt(mPhone.getContext().getContentResolver(),
2860                                     radioTestProperty, -1));
2861                 }
2862             }
2863             if (dcac == null) {
2864                 log("onDataSetupComplete: no connection to DC, handle as error");
2865                 cause = DcFailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
2866                 handleError = true;
2867             } else {
2868                 ApnSetting apn = apnContext.getApnSetting();
2869                 if (DBG) {
2870                     log("onDataSetupComplete: success apn=" + (apn == null ? "unknown" : apn.apn));
2871                 }
2872                 if (apn != null && apn.proxy != null && apn.proxy.length() != 0) {
2873                     try {
2874                         String port = apn.port;
2875                         if (TextUtils.isEmpty(port)) port = "8080";
2876                         ProxyInfo proxy = new ProxyInfo(apn.proxy,
2877                                 Integer.parseInt(port), null);
2878                         dcac.setLinkPropertiesHttpProxySync(proxy);
2879                     } catch (NumberFormatException e) {
2880                         loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
2881                                 apn.port + "): " + e);
2882                     }
2883                 }
2884 
2885                 // everything is setup
2886                 if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {
2887                     try {
2888                         SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "true");
2889                     } catch (RuntimeException ex) {
2890                         log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to true");
2891                     }
2892                     if (mCanSetPreferApn && mPreferredApn == null) {
2893                         if (DBG) log("onDataSetupComplete: PREFERRED APN is null");
2894                         mPreferredApn = apn;
2895                         if (mPreferredApn != null) {
2896                             setPreferredApn(mPreferredApn.id);
2897                         }
2898                     }
2899                 } else {
2900                     try {
2901                         SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
2902                     } catch (RuntimeException ex) {
2903                         log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false");
2904                     }
2905                 }
2906 
2907                 // A connection is setup
2908                 apnContext.setState(DctConstants.State.CONNECTED);
2909 
2910                 boolean isProvApn = apnContext.isProvisioningApn();
2911                 final ConnectivityManager cm = ConnectivityManager.from(mPhone.getContext());
2912                 if (mProvisionBroadcastReceiver != null) {
2913                     mPhone.getContext().unregisterReceiver(mProvisionBroadcastReceiver);
2914                     mProvisionBroadcastReceiver = null;
2915                 }
2916                 if ((!isProvApn) || mIsProvisioning) {
2917                     // Hide any provisioning notification.
2918                     cm.setProvisioningNotificationVisible(false, ConnectivityManager.TYPE_MOBILE,
2919                             mProvisionActionName);
2920                     // Complete the connection normally notifying the world we're connected.
2921                     // We do this if this isn't a special provisioning apn or if we've been
2922                     // told its time to provision.
2923                     completeConnection(apnContext);
2924                 } else {
2925                     // This is a provisioning APN that we're reporting as connected. Later
2926                     // when the user desires to upgrade this to a "default" connection,
2927                     // mIsProvisioning == true, we'll go through the code path above.
2928                     // mIsProvisioning becomes true when CMD_ENABLE_MOBILE_PROVISIONING
2929                     // is sent to the DCT.
2930                     if (DBG) {
2931                         log("onDataSetupComplete: successful, BUT send connected to prov apn as"
2932                                 + " mIsProvisioning:" + mIsProvisioning + " == false"
2933                                 + " && (isProvisioningApn:" + isProvApn + " == true");
2934                     }
2935 
2936                     // While radio is up, grab provisioning URL.  The URL contains ICCID which
2937                     // disappears when radio is off.
2938                     mProvisionBroadcastReceiver = new ProvisionNotificationBroadcastReceiver(
2939                             cm.getMobileProvisioningUrl(),
2940                             TelephonyManager.getDefault().getNetworkOperatorName());
2941                     mPhone.getContext().registerReceiver(mProvisionBroadcastReceiver,
2942                             new IntentFilter(mProvisionActionName));
2943                     // Put up user notification that sign-in is required.
2944                     cm.setProvisioningNotificationVisible(true, ConnectivityManager.TYPE_MOBILE,
2945                             mProvisionActionName);
2946                     // Turn off radio to save battery and avoid wasting carrier resources.
2947                     // The network isn't usable and network validation will just fail anyhow.
2948                     setRadio(false);
2949                 }
2950                 if (DBG) {
2951                     log("onDataSetupComplete: SETUP complete type=" + apnContext.getApnType()
2952                         + ", reason:" + apnContext.getReason());
2953                 }
2954                 if (Build.IS_DEBUGGABLE) {
2955                     // adb shell setprop persist.radio.test.pco [pco_val]
2956                     String radioTestProperty = "persist.radio.test.pco";
2957                     int pcoVal = SystemProperties.getInt(radioTestProperty, -1);
2958                     if (pcoVal != -1) {
2959                         log("PCO testing: read pco value from persist.radio.test.pco " + pcoVal);
2960                         final byte[] value = new byte[1];
2961                         value[0] = (byte) pcoVal;
2962                         final Intent intent =
2963                                 new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE);
2964                         intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, "default");
2965                         intent.putExtra(TelephonyIntents.EXTRA_APN_PROTO_KEY, "IPV4V6");
2966                         intent.putExtra(TelephonyIntents.EXTRA_PCO_ID_KEY, 0xFF00);
2967                         intent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE_KEY, value);
2968                         mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
2969                     }
2970                 }
2971             }
2972         } else {
2973             cause = (DcFailCause) (ar.result);
2974             if (DBG) {
2975                 ApnSetting apn = apnContext.getApnSetting();
2976                 log(String.format("onDataSetupComplete: error apn=%s cause=%s",
2977                         (apn == null ? "unknown" : apn.apn), cause));
2978             }
2979             if (cause.isEventLoggable()) {
2980                 // Log this failure to the Event Logs.
2981                 int cid = getCellLocationId();
2982                 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
2983                         cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType());
2984             }
2985             ApnSetting apn = apnContext.getApnSetting();
2986             mPhone.notifyPreciseDataConnectionFailed(apnContext.getReason(),
2987                     apnContext.getApnType(), apn != null ? apn.apn : "unknown", cause.toString());
2988 
2989             // Compose broadcast intent send to the specific carrier signaling receivers
2990             Intent intent = new Intent(TelephonyIntents
2991                     .ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED);
2992             intent.putExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY, cause.getErrorCode());
2993             intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnContext.getApnType());
2994             mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
2995 
2996             if (cause.isRestartRadioFail() || apnContext.restartOnError(cause.getErrorCode())) {
2997                 if (DBG) log("Modem restarted.");
2998                 sendRestartRadio();
2999             }
3000 
3001             // If the data call failure cause is a permanent failure, we mark the APN as permanent
3002             // failed.
3003             if (isPermanentFail(cause)) {
3004                 log("cause = " + cause + ", mark apn as permanent failed. apn = " + apn);
3005                 apnContext.markApnPermanentFailed(apn);
3006             }
3007 
3008             handleError = true;
3009         }
3010 
3011         if (handleError) {
3012             onDataSetupCompleteError(ar);
3013         }
3014 
3015         /* If flag is set to false after SETUP_DATA_CALL is invoked, we need
3016          * to clean data connections.
3017          */
3018         if (!mDataEnabledSettings.isInternalDataEnabled()) {
3019             cleanUpAllConnections(Phone.REASON_DATA_DISABLED);
3020         }
3021 
3022     }
3023 
3024     /**
3025      * check for obsolete messages.  Return ApnContext if valid, null if not
3026      */
getValidApnContext(AsyncResult ar, String logString)3027     private ApnContext getValidApnContext(AsyncResult ar, String logString) {
3028         if (ar != null && ar.userObj instanceof Pair) {
3029             Pair<ApnContext, Integer>pair = (Pair<ApnContext, Integer>)ar.userObj;
3030             ApnContext apnContext = pair.first;
3031             if (apnContext != null) {
3032                 final int generation = apnContext.getConnectionGeneration();
3033                 if (DBG) {
3034                     log("getValidApnContext (" + logString + ") on " + apnContext + " got " +
3035                             generation + " vs " + pair.second);
3036                 }
3037                 if (generation == pair.second) {
3038                     return apnContext;
3039                 } else {
3040                     log("ignoring obsolete " + logString);
3041                     return null;
3042                 }
3043             }
3044         }
3045         throw new RuntimeException(logString + ": No apnContext");
3046     }
3047 
3048     /**
3049      * Error has occurred during the SETUP {aka bringUP} request and the DCT
3050      * should either try the next waiting APN or start over from the
3051      * beginning if the list is empty. Between each SETUP request there will
3052      * be a delay defined by {@link #getApnDelay()}.
3053      */
onDataSetupCompleteError(AsyncResult ar)3054     private void onDataSetupCompleteError(AsyncResult ar) {
3055 
3056         ApnContext apnContext = getValidApnContext(ar, "onDataSetupCompleteError");
3057 
3058         if (apnContext == null) return;
3059 
3060         long delay = apnContext.getDelayForNextApn(mFailFast);
3061 
3062         // Check if we need to retry or not.
3063         if (delay >= 0) {
3064             if (DBG) log("onDataSetupCompleteError: Try next APN. delay = " + delay);
3065             apnContext.setState(DctConstants.State.SCANNING);
3066             // Wait a bit before trying the next APN, so that
3067             // we're not tying up the RIL command channel
3068             startAlarmForReconnect(delay, apnContext);
3069         } else {
3070             // If we are not going to retry any APN, set this APN context to failed state.
3071             // This would be the final state of a data connection.
3072             apnContext.setState(DctConstants.State.FAILED);
3073             mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
3074             apnContext.setDataConnectionAc(null);
3075             log("onDataSetupCompleteError: Stop retrying APNs.");
3076         }
3077     }
3078 
3079     /**
3080      * Called when EVENT_REDIRECTION_DETECTED is received.
3081      */
onDataConnectionRedirected(String redirectUrl)3082     private void onDataConnectionRedirected(String redirectUrl) {
3083         if (!TextUtils.isEmpty(redirectUrl)) {
3084             Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_REDIRECTED);
3085             intent.putExtra(TelephonyIntents.EXTRA_REDIRECTION_URL_KEY, redirectUrl);
3086             if(mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent)) {
3087                 log("Notify carrier signal receivers with redirectUrl: " + redirectUrl);
3088             }
3089         }
3090     }
3091 
3092     /**
3093      * Called when EVENT_DISCONNECT_DONE is received.
3094      */
onDisconnectDone(AsyncResult ar)3095     private void onDisconnectDone(AsyncResult ar) {
3096         ApnContext apnContext = getValidApnContext(ar, "onDisconnectDone");
3097         if (apnContext == null) return;
3098 
3099         if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE apnContext=" + apnContext);
3100         apnContext.setState(DctConstants.State.IDLE);
3101 
3102         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
3103 
3104         // if all data connection are gone, check whether Airplane mode request was
3105         // pending.
3106         if (isDisconnected()) {
3107             if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
3108                 if (DBG) log("onDisconnectDone: radio will be turned off, no retries");
3109                 // Radio will be turned off. No need to retry data setup
3110                 apnContext.setApnSetting(null);
3111                 apnContext.setDataConnectionAc(null);
3112 
3113                 // Need to notify disconnect as well, in the case of switching Airplane mode.
3114                 // Otherwise, it would cause 30s delayed to turn on Airplane mode.
3115                 if (mDisconnectPendingCount > 0) {
3116                     mDisconnectPendingCount--;
3117                 }
3118 
3119                 if (mDisconnectPendingCount == 0) {
3120                     notifyDataDisconnectComplete();
3121                     notifyAllDataDisconnected();
3122                 }
3123                 return;
3124             }
3125         }
3126         // If APN is still enabled, try to bring it back up automatically
3127         if (mAttached.get() && apnContext.isReady() && retryAfterDisconnected(apnContext)) {
3128             try {
3129                 SystemProperties.set(PUPPET_MASTER_RADIO_STRESS_TEST, "false");
3130             } catch (RuntimeException ex) {
3131                 log("Failed to set PUPPET_MASTER_RADIO_STRESS_TEST to false");
3132             }
3133             // Wait a bit before trying the next APN, so that
3134             // we're not tying up the RIL command channel.
3135             // This also helps in any external dependency to turn off the context.
3136             if (DBG) log("onDisconnectDone: attached, ready and retry after disconnect");
3137             long delay = apnContext.getInterApnDelay(mFailFast);
3138             if (delay > 0) {
3139                 // Data connection is in IDLE state, so when we reconnect later, we'll rebuild
3140                 // the waiting APN list, which will also reset/reconfigure the retry manager.
3141                 startAlarmForReconnect(delay, apnContext);
3142             }
3143         } else {
3144             boolean restartRadioAfterProvisioning = mPhone.getContext().getResources().getBoolean(
3145                     com.android.internal.R.bool.config_restartRadioAfterProvisioning);
3146 
3147             if (apnContext.isProvisioningApn() && restartRadioAfterProvisioning) {
3148                 log("onDisconnectDone: restartRadio after provisioning");
3149                 restartRadio();
3150             }
3151             apnContext.setApnSetting(null);
3152             apnContext.setDataConnectionAc(null);
3153             if (isOnlySingleDcAllowed(mPhone.getServiceState().getRilDataRadioTechnology())) {
3154                 if(DBG) log("onDisconnectDone: isOnlySigneDcAllowed true so setup single apn");
3155                 setupDataOnConnectableApns(Phone.REASON_SINGLE_PDN_ARBITRATION);
3156             } else {
3157                 if(DBG) log("onDisconnectDone: not retrying");
3158             }
3159         }
3160 
3161         if (mDisconnectPendingCount > 0)
3162             mDisconnectPendingCount--;
3163 
3164         if (mDisconnectPendingCount == 0) {
3165             apnContext.setConcurrentVoiceAndDataAllowed(
3166                     mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed());
3167             notifyDataDisconnectComplete();
3168             notifyAllDataDisconnected();
3169         }
3170 
3171     }
3172 
3173     /**
3174      * Called when EVENT_DISCONNECT_DC_RETRYING is received.
3175      */
onDisconnectDcRetrying(AsyncResult ar)3176     private void onDisconnectDcRetrying(AsyncResult ar) {
3177         // We could just do this in DC!!!
3178         ApnContext apnContext = getValidApnContext(ar, "onDisconnectDcRetrying");
3179         if (apnContext == null) return;
3180 
3181         apnContext.setState(DctConstants.State.RETRYING);
3182         if(DBG) log("onDisconnectDcRetrying: apnContext=" + apnContext);
3183 
3184         mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
3185     }
3186 
onVoiceCallStarted()3187     private void onVoiceCallStarted() {
3188         if (DBG) log("onVoiceCallStarted");
3189         mInVoiceCall = true;
3190         if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
3191             if (DBG) log("onVoiceCallStarted stop polling");
3192             stopNetStatPoll();
3193             stopDataStallAlarm();
3194             notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
3195         }
3196     }
3197 
onVoiceCallEnded()3198     private void onVoiceCallEnded() {
3199         if (DBG) log("onVoiceCallEnded");
3200         mInVoiceCall = false;
3201         if (isConnected()) {
3202             if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
3203                 startNetStatPoll();
3204                 startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
3205                 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
3206             } else {
3207                 // clean slate after call end.
3208                 resetPollStats();
3209             }
3210         }
3211         // reset reconnect timer
3212         setupDataOnConnectableApns(Phone.REASON_VOICE_CALL_ENDED);
3213     }
3214 
onCleanUpConnection(boolean tearDown, int apnId, String reason)3215     private void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
3216         if (DBG) log("onCleanUpConnection");
3217         ApnContext apnContext = mApnContextsById.get(apnId);
3218         if (apnContext != null) {
3219             apnContext.setReason(reason);
3220             cleanUpConnection(tearDown, apnContext);
3221         }
3222     }
3223 
isConnected()3224     private boolean isConnected() {
3225         for (ApnContext apnContext : mApnContexts.values()) {
3226             if (apnContext.getState() == DctConstants.State.CONNECTED) {
3227                 // At least one context is connected, return true
3228                 return true;
3229             }
3230         }
3231         // There are not any contexts connected, return false
3232         return false;
3233     }
3234 
isDisconnected()3235     public boolean isDisconnected() {
3236         for (ApnContext apnContext : mApnContexts.values()) {
3237             if (!apnContext.isDisconnected()) {
3238                 // At least one context was not disconnected return false
3239                 return false;
3240             }
3241         }
3242         // All contexts were disconnected so return true
3243         return true;
3244     }
3245 
notifyDataConnection(String reason)3246     private void notifyDataConnection(String reason) {
3247         if (DBG) log("notifyDataConnection: reason=" + reason);
3248         for (ApnContext apnContext : mApnContexts.values()) {
3249             if (mAttached.get() && apnContext.isReady()) {
3250                 if (DBG) log("notifyDataConnection: type:" + apnContext.getApnType());
3251                 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
3252                         apnContext.getApnType());
3253             }
3254         }
3255         notifyOffApnsOfAvailability(reason);
3256     }
3257 
setDataProfilesAsNeeded()3258     private void setDataProfilesAsNeeded() {
3259         if (DBG) log("setDataProfilesAsNeeded");
3260         if (mAllApnSettings != null && !mAllApnSettings.isEmpty()) {
3261             ArrayList<DataProfile> dps = new ArrayList<DataProfile>();
3262             for (ApnSetting apn : mAllApnSettings) {
3263                 if (apn.modemCognitive) {
3264                     DataProfile dp = new DataProfile(apn,
3265                             mPhone.getServiceState().getDataRoaming());
3266                     boolean isDup = false;
3267                     for(DataProfile dpIn : dps) {
3268                         if (dp.equals(dpIn)) {
3269                             isDup = true;
3270                             break;
3271                         }
3272                     }
3273                     if (!isDup) {
3274                         dps.add(dp);
3275                     }
3276                 }
3277             }
3278             if(dps.size() > 0) {
3279                 mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[0]), null);
3280             }
3281         }
3282     }
3283 
3284     /**
3285      * Based on the sim operator numeric, create a list for all possible
3286      * Data Connections and setup the preferredApn.
3287      */
createAllApnList()3288     private void createAllApnList() {
3289         mMvnoMatched = false;
3290         mAllApnSettings = new ArrayList<ApnSetting>();
3291         IccRecords r = mIccRecords.get();
3292         String operator = (r != null) ? r.getOperatorNumeric() : "";
3293         if (operator != null) {
3294             String selection = "numeric = '" + operator + "'";
3295             String orderBy = "_id";
3296             // query only enabled apn.
3297             // carrier_enabled : 1 means enabled apn, 0 disabled apn.
3298             // selection += " and carrier_enabled = 1";
3299             if (DBG) log("createAllApnList: selection=" + selection);
3300 
3301             Cursor cursor = mPhone.getContext().getContentResolver().query(
3302                     Telephony.Carriers.CONTENT_URI, null, selection, null, orderBy);
3303 
3304             if (cursor != null) {
3305                 if (cursor.getCount() > 0) {
3306                     mAllApnSettings = createApnList(cursor);
3307                 }
3308                 cursor.close();
3309             }
3310         }
3311 
3312         addEmergencyApnSetting();
3313 
3314         dedupeApnSettings();
3315 
3316         if (mAllApnSettings.isEmpty()) {
3317             if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
3318             mPreferredApn = null;
3319             // TODO: What is the right behavior?
3320             //notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
3321         } else {
3322             mPreferredApn = getPreferredApn();
3323             if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
3324                 mPreferredApn = null;
3325                 setPreferredApn(-1);
3326             }
3327             if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
3328         }
3329         if (DBG) log("createAllApnList: X mAllApnSettings=" + mAllApnSettings);
3330 
3331         setDataProfilesAsNeeded();
3332     }
3333 
dedupeApnSettings()3334     private void dedupeApnSettings() {
3335         ArrayList<ApnSetting> resultApns = new ArrayList<ApnSetting>();
3336 
3337         // coalesce APNs if they are similar enough to prevent
3338         // us from bringing up two data calls with the same interface
3339         int i = 0;
3340         while (i < mAllApnSettings.size() - 1) {
3341             ApnSetting first = mAllApnSettings.get(i);
3342             ApnSetting second = null;
3343             int j = i + 1;
3344             while (j < mAllApnSettings.size()) {
3345                 second = mAllApnSettings.get(j);
3346                 if (apnsSimilar(first, second)) {
3347                     ApnSetting newApn = mergeApns(first, second);
3348                     mAllApnSettings.set(i, newApn);
3349                     first = newApn;
3350                     mAllApnSettings.remove(j);
3351                 } else {
3352                     j++;
3353                 }
3354             }
3355             i++;
3356         }
3357     }
3358 
3359     //check whether the types of two APN same (even only one type of each APN is same)
apnTypeSameAny(ApnSetting first, ApnSetting second)3360     private boolean apnTypeSameAny(ApnSetting first, ApnSetting second) {
3361         if(VDBG) {
3362             StringBuilder apnType1 = new StringBuilder(first.apn + ": ");
3363             for(int index1 = 0; index1 < first.types.length; index1++) {
3364                 apnType1.append(first.types[index1]);
3365                 apnType1.append(",");
3366             }
3367 
3368             StringBuilder apnType2 = new StringBuilder(second.apn + ": ");
3369             for(int index1 = 0; index1 < second.types.length; index1++) {
3370                 apnType2.append(second.types[index1]);
3371                 apnType2.append(",");
3372             }
3373             log("APN1: is " + apnType1);
3374             log("APN2: is " + apnType2);
3375         }
3376 
3377         for(int index1 = 0; index1 < first.types.length; index1++) {
3378             for(int index2 = 0; index2 < second.types.length; index2++) {
3379                 if(first.types[index1].equals(PhoneConstants.APN_TYPE_ALL) ||
3380                         second.types[index2].equals(PhoneConstants.APN_TYPE_ALL) ||
3381                         first.types[index1].equals(second.types[index2])) {
3382                     if(VDBG)log("apnTypeSameAny: return true");
3383                     return true;
3384                 }
3385             }
3386         }
3387 
3388         if(VDBG)log("apnTypeSameAny: return false");
3389         return false;
3390     }
3391 
3392     // Check if neither mention DUN and are substantially similar
apnsSimilar(ApnSetting first, ApnSetting second)3393     private boolean apnsSimilar(ApnSetting first, ApnSetting second) {
3394         return (first.canHandleType(PhoneConstants.APN_TYPE_DUN) == false &&
3395                 second.canHandleType(PhoneConstants.APN_TYPE_DUN) == false &&
3396                 Objects.equals(first.apn, second.apn) &&
3397                 !apnTypeSameAny(first, second) &&
3398                 xorEquals(first.proxy, second.proxy) &&
3399                 xorEquals(first.port, second.port) &&
3400                 first.carrierEnabled == second.carrierEnabled &&
3401                 first.bearerBitmask == second.bearerBitmask &&
3402                 first.profileId == second.profileId &&
3403                 Objects.equals(first.mvnoType, second.mvnoType) &&
3404                 Objects.equals(first.mvnoMatchData, second.mvnoMatchData) &&
3405                 xorEquals(first.mmsc, second.mmsc) &&
3406                 xorEquals(first.mmsProxy, second.mmsProxy) &&
3407                 xorEquals(first.mmsPort, second.mmsPort));
3408     }
3409 
3410     // equal or one is not specified
xorEquals(String first, String second)3411     private boolean xorEquals(String first, String second) {
3412         return (Objects.equals(first, second) ||
3413                 TextUtils.isEmpty(first) ||
3414                 TextUtils.isEmpty(second));
3415     }
3416 
mergeApns(ApnSetting dest, ApnSetting src)3417     private ApnSetting mergeApns(ApnSetting dest, ApnSetting src) {
3418         int id = dest.id;
3419         ArrayList<String> resultTypes = new ArrayList<String>();
3420         resultTypes.addAll(Arrays.asList(dest.types));
3421         for (String srcType : src.types) {
3422             if (resultTypes.contains(srcType) == false) resultTypes.add(srcType);
3423             if (srcType.equals(PhoneConstants.APN_TYPE_DEFAULT)) id = src.id;
3424         }
3425         String mmsc = (TextUtils.isEmpty(dest.mmsc) ? src.mmsc : dest.mmsc);
3426         String mmsProxy = (TextUtils.isEmpty(dest.mmsProxy) ? src.mmsProxy : dest.mmsProxy);
3427         String mmsPort = (TextUtils.isEmpty(dest.mmsPort) ? src.mmsPort : dest.mmsPort);
3428         String proxy = (TextUtils.isEmpty(dest.proxy) ? src.proxy : dest.proxy);
3429         String port = (TextUtils.isEmpty(dest.port) ? src.port : dest.port);
3430         String protocol = src.protocol.equals("IPV4V6") ? src.protocol : dest.protocol;
3431         String roamingProtocol = src.roamingProtocol.equals("IPV4V6") ? src.roamingProtocol :
3432                 dest.roamingProtocol;
3433         int bearerBitmask = (dest.bearerBitmask == 0 || src.bearerBitmask == 0) ?
3434                 0 : (dest.bearerBitmask | src.bearerBitmask);
3435 
3436         return new ApnSetting(id, dest.numeric, dest.carrier, dest.apn,
3437                 proxy, port, mmsc, mmsProxy, mmsPort, dest.user, dest.password,
3438                 dest.authType, resultTypes.toArray(new String[0]), protocol,
3439                 roamingProtocol, dest.carrierEnabled, 0, bearerBitmask, dest.profileId,
3440                 (dest.modemCognitive || src.modemCognitive), dest.maxConns, dest.waitTime,
3441                 dest.maxConnsTime, dest.mtu, dest.mvnoType, dest.mvnoMatchData);
3442     }
3443 
3444     /** Return the DC AsyncChannel for the new data connection */
createDataConnection()3445     private DcAsyncChannel createDataConnection() {
3446         if (DBG) log("createDataConnection E");
3447 
3448         int id = mUniqueIdGenerator.getAndIncrement();
3449         DataConnection conn = DataConnection.makeDataConnection(mPhone, id,
3450                                                 this, mDcTesterFailBringUpAll, mDcc);
3451         mDataConnections.put(id, conn);
3452         DcAsyncChannel dcac = new DcAsyncChannel(conn, LOG_TAG);
3453         int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
3454         if (status == AsyncChannel.STATUS_SUCCESSFUL) {
3455             mDataConnectionAcHashMap.put(dcac.getDataConnectionIdSync(), dcac);
3456         } else {
3457             loge("createDataConnection: Could not connect to dcac=" + dcac + " status=" + status);
3458         }
3459 
3460         if (DBG) log("createDataConnection() X id=" + id + " dc=" + conn);
3461         return dcac;
3462     }
3463 
destroyDataConnections()3464     private void destroyDataConnections() {
3465         if(mDataConnections != null) {
3466             if (DBG) log("destroyDataConnections: clear mDataConnectionList");
3467             mDataConnections.clear();
3468         } else {
3469             if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore");
3470         }
3471     }
3472 
3473     /**
3474      * Build a list of APNs to be used to create PDP's.
3475      *
3476      * @param requestedApnType
3477      * @return waitingApns list to be used to create PDP
3478      *          error when waitingApns.isEmpty()
3479      */
buildWaitingApns(String requestedApnType, int radioTech)3480     private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType, int radioTech) {
3481         if (DBG) log("buildWaitingApns: E requestedApnType=" + requestedApnType);
3482         ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
3483 
3484         if (requestedApnType.equals(PhoneConstants.APN_TYPE_DUN)) {
3485             ApnSetting dun = fetchDunApn();
3486             if (dun != null) {
3487                 apnList.add(dun);
3488                 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
3489                 return apnList;
3490             }
3491         }
3492 
3493         IccRecords r = mIccRecords.get();
3494         String operator = (r != null) ? r.getOperatorNumeric() : "";
3495 
3496         // This is a workaround for a bug (7305641) where we don't failover to other
3497         // suitable APNs if our preferred APN fails.  On prepaid ATT sims we need to
3498         // failover to a provisioning APN, but once we've used their default data
3499         // connection we are locked to it for life.  This change allows ATT devices
3500         // to say they don't want to use preferred at all.
3501         boolean usePreferred = true;
3502         try {
3503             usePreferred = ! mPhone.getContext().getResources().getBoolean(com.android.
3504                     internal.R.bool.config_dontPreferApn);
3505         } catch (Resources.NotFoundException e) {
3506             if (DBG) log("buildWaitingApns: usePreferred NotFoundException set to true");
3507             usePreferred = true;
3508         }
3509         if (usePreferred) {
3510             mPreferredApn = getPreferredApn();
3511         }
3512         if (DBG) {
3513             log("buildWaitingApns: usePreferred=" + usePreferred
3514                     + " canSetPreferApn=" + mCanSetPreferApn
3515                     + " mPreferredApn=" + mPreferredApn
3516                     + " operator=" + operator + " radioTech=" + radioTech
3517                     + " IccRecords r=" + r);
3518         }
3519 
3520         if (usePreferred && mCanSetPreferApn && mPreferredApn != null &&
3521                 mPreferredApn.canHandleType(requestedApnType)) {
3522             if (DBG) {
3523                 log("buildWaitingApns: Preferred APN:" + operator + ":"
3524                         + mPreferredApn.numeric + ":" + mPreferredApn);
3525             }
3526             if (mPreferredApn.numeric.equals(operator)) {
3527                 if (ServiceState.bitmaskHasTech(mPreferredApn.bearerBitmask, radioTech)) {
3528                     apnList.add(mPreferredApn);
3529                     if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
3530                     return apnList;
3531                 } else {
3532                     if (DBG) log("buildWaitingApns: no preferred APN");
3533                     setPreferredApn(-1);
3534                     mPreferredApn = null;
3535                 }
3536             } else {
3537                 if (DBG) log("buildWaitingApns: no preferred APN");
3538                 setPreferredApn(-1);
3539                 mPreferredApn = null;
3540             }
3541         }
3542         if (mAllApnSettings != null) {
3543             if (DBG) log("buildWaitingApns: mAllApnSettings=" + mAllApnSettings);
3544             for (ApnSetting apn : mAllApnSettings) {
3545                 if (apn.canHandleType(requestedApnType)) {
3546                     if (ServiceState.bitmaskHasTech(apn.bearerBitmask, radioTech)) {
3547                         if (DBG) log("buildWaitingApns: adding apn=" + apn);
3548                         apnList.add(apn);
3549                     } else {
3550                         if (DBG) {
3551                             log("buildWaitingApns: bearerBitmask:" + apn.bearerBitmask + " does " +
3552                                     "not include radioTech:" + radioTech);
3553                         }
3554                     }
3555                 } else if (DBG) {
3556                     log("buildWaitingApns: couldn't handle requested ApnType="
3557                             + requestedApnType);
3558                 }
3559             }
3560         } else {
3561             loge("mAllApnSettings is null!");
3562         }
3563         if (DBG) log("buildWaitingApns: " + apnList.size() + " APNs in the list: " + apnList);
3564         return apnList;
3565     }
3566 
apnListToString(ArrayList<ApnSetting> apns)3567     private String apnListToString (ArrayList<ApnSetting> apns) {
3568         StringBuilder result = new StringBuilder();
3569         for (int i = 0, size = apns.size(); i < size; i++) {
3570             result.append('[')
3571                   .append(apns.get(i).toString())
3572                   .append(']');
3573         }
3574         return result.toString();
3575     }
3576 
setPreferredApn(int pos)3577     private void setPreferredApn(int pos) {
3578         if (!mCanSetPreferApn) {
3579             log("setPreferredApn: X !canSEtPreferApn");
3580             return;
3581         }
3582 
3583         String subId = Long.toString(mPhone.getSubId());
3584         Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
3585         log("setPreferredApn: delete");
3586         ContentResolver resolver = mPhone.getContext().getContentResolver();
3587         resolver.delete(uri, null, null);
3588 
3589         if (pos >= 0) {
3590             log("setPreferredApn: insert");
3591             ContentValues values = new ContentValues();
3592             values.put(APN_ID, pos);
3593             resolver.insert(uri, values);
3594         }
3595     }
3596 
getPreferredApn()3597     private ApnSetting getPreferredApn() {
3598         if (mAllApnSettings == null || mAllApnSettings.isEmpty()) {
3599             log("getPreferredApn: mAllApnSettings is " + ((mAllApnSettings == null)?"null":"empty"));
3600             return null;
3601         }
3602 
3603         String subId = Long.toString(mPhone.getSubId());
3604         Uri uri = Uri.withAppendedPath(PREFERAPN_NO_UPDATE_URI_USING_SUBID, subId);
3605         Cursor cursor = mPhone.getContext().getContentResolver().query(
3606                 uri, new String[] { "_id", "name", "apn" },
3607                 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
3608 
3609         if (cursor != null) {
3610             mCanSetPreferApn = true;
3611         } else {
3612             mCanSetPreferApn = false;
3613         }
3614         log("getPreferredApn: mRequestedApnType=" + mRequestedApnType + " cursor=" + cursor
3615                 + " cursor.count=" + ((cursor != null) ? cursor.getCount() : 0));
3616 
3617         if (mCanSetPreferApn && cursor.getCount() > 0) {
3618             int pos;
3619             cursor.moveToFirst();
3620             pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
3621             for(ApnSetting p : mAllApnSettings) {
3622                 log("getPreferredApn: apnSetting=" + p);
3623                 if (p.id == pos && p.canHandleType(mRequestedApnType)) {
3624                     log("getPreferredApn: X found apnSetting" + p);
3625                     cursor.close();
3626                     return p;
3627                 }
3628             }
3629         }
3630 
3631         if (cursor != null) {
3632             cursor.close();
3633         }
3634 
3635         log("getPreferredApn: X not found");
3636         return null;
3637     }
3638 
3639     @Override
handleMessage(Message msg)3640     public void handleMessage (Message msg) {
3641         if (VDBG) log("handleMessage msg=" + msg);
3642 
3643         switch (msg.what) {
3644             case DctConstants.EVENT_RECORDS_LOADED:
3645                 // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on
3646                 // onSubscriptionsChanged() when a valid subId is available.
3647                 int subId = mPhone.getSubId();
3648                 if (SubscriptionManager.isValidSubscriptionId(subId)) {
3649                     onRecordsLoadedOrSubIdChanged();
3650                 } else {
3651                     log("Ignoring EVENT_RECORDS_LOADED as subId is not valid: " + subId);
3652                 }
3653                 break;
3654 
3655             case DctConstants.EVENT_DATA_CONNECTION_DETACHED:
3656                 onDataConnectionDetached();
3657                 break;
3658 
3659             case DctConstants.EVENT_DATA_CONNECTION_ATTACHED:
3660                 onDataConnectionAttached();
3661                 break;
3662 
3663             case DctConstants.EVENT_DO_RECOVERY:
3664                 doRecovery();
3665                 break;
3666 
3667             case DctConstants.EVENT_APN_CHANGED:
3668                 onApnChanged();
3669                 break;
3670 
3671             case DctConstants.EVENT_PS_RESTRICT_ENABLED:
3672                 /**
3673                  * We don't need to explicitly to tear down the PDP context
3674                  * when PS restricted is enabled. The base band will deactive
3675                  * PDP context and notify us with PDP_CONTEXT_CHANGED.
3676                  * But we should stop the network polling and prevent reset PDP.
3677                  */
3678                 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
3679                 stopNetStatPoll();
3680                 stopDataStallAlarm();
3681                 mIsPsRestricted = true;
3682                 break;
3683 
3684             case DctConstants.EVENT_PS_RESTRICT_DISABLED:
3685                 /**
3686                  * When PS restrict is removed, we need setup PDP connection if
3687                  * PDP connection is down.
3688                  */
3689                 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
3690                 mIsPsRestricted  = false;
3691                 if (isConnected()) {
3692                     startNetStatPoll();
3693                     startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
3694                 } else {
3695                     // TODO: Should all PDN states be checked to fail?
3696                     if (mState == DctConstants.State.FAILED) {
3697                         cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
3698                         mReregisterOnReconnectFailure = false;
3699                     }
3700                     ApnContext apnContext = mApnContextsById.get(DctConstants.APN_DEFAULT_ID);
3701                     if (apnContext != null) {
3702                         apnContext.setReason(Phone.REASON_PS_RESTRICT_ENABLED);
3703                         trySetupData(apnContext);
3704                     } else {
3705                         loge("**** Default ApnContext not found ****");
3706                         if (Build.IS_DEBUGGABLE) {
3707                             throw new RuntimeException("Default ApnContext not found");
3708                         }
3709                     }
3710                 }
3711                 break;
3712 
3713             case DctConstants.EVENT_TRY_SETUP_DATA:
3714                 if (msg.obj instanceof ApnContext) {
3715                     onTrySetupData((ApnContext)msg.obj);
3716                 } else if (msg.obj instanceof String) {
3717                     onTrySetupData((String)msg.obj);
3718                 } else {
3719                     loge("EVENT_TRY_SETUP request w/o apnContext or String");
3720                 }
3721                 break;
3722 
3723             case DctConstants.EVENT_CLEAN_UP_CONNECTION:
3724                 boolean tearDown = (msg.arg1 == 0) ? false : true;
3725                 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
3726                 if (msg.obj instanceof ApnContext) {
3727                     cleanUpConnection(tearDown, (ApnContext)msg.obj);
3728                 } else {
3729                     onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
3730                 }
3731                 break;
3732             case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: {
3733                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
3734                 onSetInternalDataEnabled(enabled, (Message) msg.obj);
3735                 break;
3736             }
3737             case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS:
3738                 if ((msg.obj != null) && (msg.obj instanceof String == false)) {
3739                     msg.obj = null;
3740                 }
3741                 onCleanUpAllConnections((String) msg.obj);
3742                 break;
3743 
3744             case DctConstants.EVENT_DATA_RAT_CHANGED:
3745                 //May new Network allow setupData, so try it here
3746                 setupDataOnConnectableApns(Phone.REASON_NW_TYPE_CHANGED,
3747                         RetryFailures.ONLY_ON_CHANGE);
3748                 break;
3749 
3750             case DctConstants.CMD_CLEAR_PROVISIONING_SPINNER:
3751                 // Check message sender intended to clear the current spinner.
3752                 if (mProvisioningSpinner == msg.obj) {
3753                     mProvisioningSpinner.dismiss();
3754                     mProvisioningSpinner = null;
3755                 }
3756                 break;
3757             case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
3758                 log("DISCONNECTED_CONNECTED: msg=" + msg);
3759                 DcAsyncChannel dcac = (DcAsyncChannel) msg.obj;
3760                 mDataConnectionAcHashMap.remove(dcac.getDataConnectionIdSync());
3761                 dcac.disconnected();
3762                 break;
3763             }
3764             case DctConstants.EVENT_ENABLE_NEW_APN:
3765                 onEnableApn(msg.arg1, msg.arg2);
3766                 break;
3767 
3768             case DctConstants.EVENT_DATA_STALL_ALARM:
3769                 onDataStallAlarm(msg.arg1);
3770                 break;
3771 
3772             case DctConstants.EVENT_ROAMING_OFF:
3773                 onRoamingOff();
3774                 break;
3775 
3776             case DctConstants.EVENT_ROAMING_ON:
3777                 onRoamingOn();
3778                 break;
3779 
3780             case DctConstants.EVENT_DEVICE_PROVISIONED_CHANGE:
3781                 onDeviceProvisionedChange();
3782                 break;
3783 
3784             case DctConstants.EVENT_REDIRECTION_DETECTED:
3785                 String url = (String) msg.obj;
3786                 log("dataConnectionTracker.handleMessage: EVENT_REDIRECTION_DETECTED=" + url);
3787                 onDataConnectionRedirected(url);
3788 
3789             case DctConstants.EVENT_RADIO_AVAILABLE:
3790                 onRadioAvailable();
3791                 break;
3792 
3793             case DctConstants.EVENT_RADIO_OFF_OR_NOT_AVAILABLE:
3794                 onRadioOffOrNotAvailable();
3795                 break;
3796 
3797             case DctConstants.EVENT_DATA_SETUP_COMPLETE:
3798                 onDataSetupComplete((AsyncResult) msg.obj);
3799                 break;
3800 
3801             case DctConstants.EVENT_DATA_SETUP_COMPLETE_ERROR:
3802                 onDataSetupCompleteError((AsyncResult) msg.obj);
3803                 break;
3804 
3805             case DctConstants.EVENT_DISCONNECT_DONE:
3806                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DONE msg=" + msg);
3807                 onDisconnectDone((AsyncResult) msg.obj);
3808                 break;
3809 
3810             case DctConstants.EVENT_DISCONNECT_DC_RETRYING:
3811                 log("DataConnectionTracker.handleMessage: EVENT_DISCONNECT_DC_RETRYING msg=" + msg);
3812                 onDisconnectDcRetrying((AsyncResult) msg.obj);
3813                 break;
3814 
3815             case DctConstants.EVENT_VOICE_CALL_STARTED:
3816                 onVoiceCallStarted();
3817                 break;
3818 
3819             case DctConstants.EVENT_VOICE_CALL_ENDED:
3820                 onVoiceCallEnded();
3821                 break;
3822 
3823             case DctConstants.EVENT_RESET_DONE: {
3824                 if (DBG) log("EVENT_RESET_DONE");
3825                 onResetDone((AsyncResult) msg.obj);
3826                 break;
3827             }
3828             case DctConstants.CMD_SET_USER_DATA_ENABLE: {
3829                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
3830                 if (DBG) log("CMD_SET_USER_DATA_ENABLE enabled=" + enabled);
3831                 onSetUserDataEnabled(enabled);
3832                 break;
3833             }
3834             // TODO - remove
3835             case DctConstants.CMD_SET_DEPENDENCY_MET: {
3836                 boolean met = (msg.arg1 == DctConstants.ENABLED) ? true : false;
3837                 if (DBG) log("CMD_SET_DEPENDENCY_MET met=" + met);
3838                 Bundle bundle = msg.getData();
3839                 if (bundle != null) {
3840                     String apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
3841                     if (apnType != null) {
3842                         onSetDependencyMet(apnType, met);
3843                     }
3844                 }
3845                 break;
3846             }
3847             case DctConstants.CMD_SET_POLICY_DATA_ENABLE: {
3848                 final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
3849                 onSetPolicyDataEnabled(enabled);
3850                 break;
3851             }
3852             case DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: {
3853                 sEnableFailFastRefCounter += (msg.arg1 == DctConstants.ENABLED) ? 1 : -1;
3854                 if (DBG) {
3855                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
3856                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
3857                 }
3858                 if (sEnableFailFastRefCounter < 0) {
3859                     final String s = "CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: "
3860                             + "sEnableFailFastRefCounter:" + sEnableFailFastRefCounter + " < 0";
3861                     loge(s);
3862                     sEnableFailFastRefCounter = 0;
3863                 }
3864                 final boolean enabled = sEnableFailFastRefCounter > 0;
3865                 if (DBG) {
3866                     log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: enabled=" + enabled
3867                             + " sEnableFailFastRefCounter=" + sEnableFailFastRefCounter);
3868                 }
3869                 if (mFailFast != enabled) {
3870                     mFailFast = enabled;
3871 
3872                     mDataStallDetectionEnabled = !enabled;
3873                     if (mDataStallDetectionEnabled
3874                             && (getOverallState() == DctConstants.State.CONNECTED)
3875                             && (!mInVoiceCall ||
3876                                     mPhone.getServiceStateTracker()
3877                                         .isConcurrentVoiceAndDataAllowed())) {
3878                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: start data stall");
3879                         stopDataStallAlarm();
3880                         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
3881                     } else {
3882                         if (DBG) log("CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA: stop data stall");
3883                         stopDataStallAlarm();
3884                     }
3885                 }
3886 
3887                 break;
3888             }
3889             case DctConstants.CMD_ENABLE_MOBILE_PROVISIONING: {
3890                 Bundle bundle = msg.getData();
3891                 if (bundle != null) {
3892                     try {
3893                         mProvisioningUrl = (String)bundle.get(DctConstants.PROVISIONING_URL_KEY);
3894                     } catch(ClassCastException e) {
3895                         loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url not a string" + e);
3896                         mProvisioningUrl = null;
3897                     }
3898                 }
3899                 if (TextUtils.isEmpty(mProvisioningUrl)) {
3900                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioning url is empty, ignoring");
3901                     mIsProvisioning = false;
3902                     mProvisioningUrl = null;
3903                 } else {
3904                     loge("CMD_ENABLE_MOBILE_PROVISIONING: provisioningUrl=" + mProvisioningUrl);
3905                     mIsProvisioning = true;
3906                     startProvisioningApnAlarm();
3907                 }
3908                 break;
3909             }
3910             case DctConstants.EVENT_PROVISIONING_APN_ALARM: {
3911                 if (DBG) log("EVENT_PROVISIONING_APN_ALARM");
3912                 ApnContext apnCtx = mApnContextsById.get(DctConstants.APN_DEFAULT_ID);
3913                 if (apnCtx.isProvisioningApn() && apnCtx.isConnectedOrConnecting()) {
3914                     if (mProvisioningApnAlarmTag == msg.arg1) {
3915                         if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Disconnecting");
3916                         mIsProvisioning = false;
3917                         mProvisioningUrl = null;
3918                         stopProvisioningApnAlarm();
3919                         sendCleanUpConnection(true, apnCtx);
3920                     } else {
3921                         if (DBG) {
3922                             log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
3923                                     + " mProvisioningApnAlarmTag:" + mProvisioningApnAlarmTag
3924                                     + " != arg1:" + msg.arg1);
3925                         }
3926                     }
3927                 } else {
3928                     if (DBG) log("EVENT_PROVISIONING_APN_ALARM: Not connected ignore");
3929                 }
3930                 break;
3931             }
3932             case DctConstants.CMD_IS_PROVISIONING_APN: {
3933                 if (DBG) log("CMD_IS_PROVISIONING_APN");
3934                 boolean isProvApn;
3935                 try {
3936                     String apnType = null;
3937                     Bundle bundle = msg.getData();
3938                     if (bundle != null) {
3939                         apnType = (String)bundle.get(DctConstants.APN_TYPE_KEY);
3940                     }
3941                     if (TextUtils.isEmpty(apnType)) {
3942                         loge("CMD_IS_PROVISIONING_APN: apnType is empty");
3943                         isProvApn = false;
3944                     } else {
3945                         isProvApn = isProvisioningApn(apnType);
3946                     }
3947                 } catch (ClassCastException e) {
3948                     loge("CMD_IS_PROVISIONING_APN: NO provisioning url ignoring");
3949                     isProvApn = false;
3950                 }
3951                 if (DBG) log("CMD_IS_PROVISIONING_APN: ret=" + isProvApn);
3952                 mReplyAc.replyToMessage(msg, DctConstants.CMD_IS_PROVISIONING_APN,
3953                         isProvApn ? DctConstants.ENABLED : DctConstants.DISABLED);
3954                 break;
3955             }
3956             case DctConstants.EVENT_ICC_CHANGED: {
3957                 onUpdateIcc();
3958                 break;
3959             }
3960             case DctConstants.EVENT_RESTART_RADIO: {
3961                 restartRadio();
3962                 break;
3963             }
3964             case DctConstants.CMD_NET_STAT_POLL: {
3965                 if (msg.arg1 == DctConstants.ENABLED) {
3966                     handleStartNetStatPoll((DctConstants.Activity)msg.obj);
3967                 } else if (msg.arg1 == DctConstants.DISABLED) {
3968                     handleStopNetStatPoll((DctConstants.Activity)msg.obj);
3969                 }
3970                 break;
3971             }
3972             case DctConstants.EVENT_DATA_STATE_CHANGED: {
3973                 // no longer do anything, but still registered - clean up log
3974                 // TODO - why are we still registering?
3975                 break;
3976             }
3977             case DctConstants.EVENT_PCO_DATA_RECEIVED: {
3978                 handlePcoData((AsyncResult)msg.obj);
3979                 break;
3980             }
3981             case DctConstants.EVENT_SET_CARRIER_DATA_ENABLED:
3982                 onSetCarrierDataEnabled(msg.arg1 == DctConstants.ENABLED);
3983                 break;
3984             default:
3985                 Rlog.e("DcTracker", "Unhandled event=" + msg);
3986                 break;
3987 
3988         }
3989     }
3990 
getApnProfileID(String apnType)3991     private int getApnProfileID(String apnType) {
3992         if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) {
3993             return RILConstants.DATA_PROFILE_IMS;
3994         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_FOTA)) {
3995             return RILConstants.DATA_PROFILE_FOTA;
3996         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_CBS)) {
3997             return RILConstants.DATA_PROFILE_CBS;
3998         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IA)) {
3999             return RILConstants.DATA_PROFILE_DEFAULT; // DEFAULT for now
4000         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_DUN)) {
4001             return RILConstants.DATA_PROFILE_TETHERED;
4002         } else {
4003             return RILConstants.DATA_PROFILE_DEFAULT;
4004         }
4005     }
4006 
getCellLocationId()4007     private int getCellLocationId() {
4008         int cid = -1;
4009         CellLocation loc = mPhone.getCellLocation();
4010 
4011         if (loc != null) {
4012             if (loc instanceof GsmCellLocation) {
4013                 cid = ((GsmCellLocation)loc).getCid();
4014             } else if (loc instanceof CdmaCellLocation) {
4015                 cid = ((CdmaCellLocation)loc).getBaseStationId();
4016             }
4017         }
4018         return cid;
4019     }
4020 
getUiccRecords(int appFamily)4021     private IccRecords getUiccRecords(int appFamily) {
4022         return mUiccController.getIccRecords(mPhone.getPhoneId(), appFamily);
4023     }
4024 
4025 
onUpdateIcc()4026     private void onUpdateIcc() {
4027         if (mUiccController == null ) {
4028             return;
4029         }
4030 
4031         IccRecords newIccRecords = getUiccRecords(UiccController.APP_FAM_3GPP);
4032 
4033         IccRecords r = mIccRecords.get();
4034         if (r != newIccRecords) {
4035             if (r != null) {
4036                 log("Removing stale icc objects.");
4037                 r.unregisterForRecordsLoaded(this);
4038                 mIccRecords.set(null);
4039             }
4040             if (newIccRecords != null) {
4041                 if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) {
4042                     log("New records found.");
4043                     mIccRecords.set(newIccRecords);
4044                     newIccRecords.registerForRecordsLoaded(
4045                             this, DctConstants.EVENT_RECORDS_LOADED, null);
4046                     // reset carrier actions on sim loaded
4047                     final ServiceStateTracker sst = mPhone.getServiceStateTracker();
4048                     sst.setRadioPowerFromCarrier(true);
4049                     mDataEnabledSettings.setCarrierDataEnabled(true);
4050                     mPhone.getCarrierSignalAgent().reset();
4051                 }
4052             } else {
4053                 onSimNotReady();
4054             }
4055         }
4056     }
4057 
update()4058     public void update() {
4059         log("update sub = " + mPhone.getSubId());
4060         log("update(): Active DDS, register for all events now!");
4061         onUpdateIcc();
4062 
4063         mDataEnabledSettings.setUserDataEnabled(getDataEnabled());
4064         mAutoAttachOnCreation.set(false);
4065 
4066         ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider();
4067     }
4068 
cleanUpAllConnections(String cause)4069     public void cleanUpAllConnections(String cause) {
4070         cleanUpAllConnections(cause, null);
4071     }
4072 
updateRecords()4073     public void updateRecords() {
4074         onUpdateIcc();
4075     }
4076 
cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg)4077     public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) {
4078         log("cleanUpAllConnections");
4079         if (disconnectAllCompleteMsg != null) {
4080             mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg);
4081         }
4082 
4083         Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
4084         msg.obj = cause;
4085         sendMessage(msg);
4086     }
4087 
notifyDataDisconnectComplete()4088     private void notifyDataDisconnectComplete() {
4089         log("notifyDataDisconnectComplete");
4090         for (Message m: mDisconnectAllCompleteMsgList) {
4091             m.sendToTarget();
4092         }
4093         mDisconnectAllCompleteMsgList.clear();
4094     }
4095 
4096 
notifyAllDataDisconnected()4097     private void notifyAllDataDisconnected() {
4098         sEnableFailFastRefCounter = 0;
4099         mFailFast = false;
4100         mAllDataDisconnectedRegistrants.notifyRegistrants();
4101     }
4102 
registerForAllDataDisconnected(Handler h, int what, Object obj)4103     public void registerForAllDataDisconnected(Handler h, int what, Object obj) {
4104         mAllDataDisconnectedRegistrants.addUnique(h, what, obj);
4105 
4106         if (isDisconnected()) {
4107             log("notify All Data Disconnected");
4108             notifyAllDataDisconnected();
4109         }
4110     }
4111 
unregisterForAllDataDisconnected(Handler h)4112     public void unregisterForAllDataDisconnected(Handler h) {
4113         mAllDataDisconnectedRegistrants.remove(h);
4114     }
4115 
registerForDataEnabledChanged(Handler h, int what, Object obj)4116     public void registerForDataEnabledChanged(Handler h, int what, Object obj) {
4117         mDataEnabledSettings.registerForDataEnabledChanged(h, what, obj);
4118     }
4119 
unregisterForDataEnabledChanged(Handler h)4120     public void unregisterForDataEnabledChanged(Handler h) {
4121         mDataEnabledSettings.unregisterForDataEnabledChanged(h);
4122     }
4123 
onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg)4124     private void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) {
4125         synchronized (mDataEnabledSettings) {
4126             if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled);
4127             boolean sendOnComplete = true;
4128 
4129             mDataEnabledSettings.setInternalDataEnabled(enabled);
4130             if (enabled) {
4131                 log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
4132                 onTrySetupData(Phone.REASON_DATA_ENABLED);
4133             } else {
4134                 sendOnComplete = false;
4135                 log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
4136                 cleanUpAllConnections(Phone.REASON_DATA_DISABLED, onCompleteMsg);
4137             }
4138 
4139             if (sendOnComplete) {
4140                 if (onCompleteMsg != null) {
4141                     onCompleteMsg.sendToTarget();
4142                 }
4143             }
4144         }
4145     }
4146 
setInternalDataEnabled(boolean enable)4147     public boolean setInternalDataEnabled(boolean enable) {
4148         return setInternalDataEnabled(enable, null);
4149     }
4150 
setInternalDataEnabled(boolean enable, Message onCompleteMsg)4151     public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
4152         if (DBG) log("setInternalDataEnabled(" + enable + ")");
4153 
4154         Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg);
4155         msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
4156         sendMessage(msg);
4157         return true;
4158     }
4159 
log(String s)4160     private void log(String s) {
4161         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
4162     }
4163 
loge(String s)4164     private void loge(String s) {
4165         Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
4166     }
4167 
dump(FileDescriptor fd, PrintWriter pw, String[] args)4168     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4169         pw.println("DcTracker:");
4170         pw.println(" RADIO_TESTS=" + RADIO_TESTS);
4171         pw.println(" isInternalDataEnabled=" + mDataEnabledSettings.isInternalDataEnabled());
4172         pw.println(" isUserDataEnabled=" + mDataEnabledSettings.isUserDataEnabled());
4173         pw.println(" isPolicyDataEnabled=" + mDataEnabledSettings.isPolicyDataEnabled());
4174         pw.flush();
4175         pw.println(" mRequestedApnType=" + mRequestedApnType);
4176         pw.println(" mPhone=" + mPhone.getPhoneName());
4177         pw.println(" mActivity=" + mActivity);
4178         pw.println(" mState=" + mState);
4179         pw.println(" mTxPkts=" + mTxPkts);
4180         pw.println(" mRxPkts=" + mRxPkts);
4181         pw.println(" mNetStatPollPeriod=" + mNetStatPollPeriod);
4182         pw.println(" mNetStatPollEnabled=" + mNetStatPollEnabled);
4183         pw.println(" mDataStallTxRxSum=" + mDataStallTxRxSum);
4184         pw.println(" mDataStallAlarmTag=" + mDataStallAlarmTag);
4185         pw.println(" mDataStallDetectionEnabled=" + mDataStallDetectionEnabled);
4186         pw.println(" mSentSinceLastRecv=" + mSentSinceLastRecv);
4187         pw.println(" mNoRecvPollCount=" + mNoRecvPollCount);
4188         pw.println(" mResolver=" + mResolver);
4189         pw.println(" mIsWifiConnected=" + mIsWifiConnected);
4190         pw.println(" mReconnectIntent=" + mReconnectIntent);
4191         pw.println(" mAutoAttachOnCreation=" + mAutoAttachOnCreation.get());
4192         pw.println(" mIsScreenOn=" + mIsScreenOn);
4193         pw.println(" mUniqueIdGenerator=" + mUniqueIdGenerator);
4194         pw.flush();
4195         pw.println(" ***************************************");
4196         DcController dcc = mDcc;
4197         if (dcc != null) {
4198             dcc.dump(fd, pw, args);
4199         } else {
4200             pw.println(" mDcc=null");
4201         }
4202         pw.println(" ***************************************");
4203         HashMap<Integer, DataConnection> dcs = mDataConnections;
4204         if (dcs != null) {
4205             Set<Entry<Integer, DataConnection> > mDcSet = mDataConnections.entrySet();
4206             pw.println(" mDataConnections: count=" + mDcSet.size());
4207             for (Entry<Integer, DataConnection> entry : mDcSet) {
4208                 pw.printf(" *** mDataConnection[%d] \n", entry.getKey());
4209                 entry.getValue().dump(fd, pw, args);
4210             }
4211         } else {
4212             pw.println("mDataConnections=null");
4213         }
4214         pw.println(" ***************************************");
4215         pw.flush();
4216         HashMap<String, Integer> apnToDcId = mApnToDataConnectionId;
4217         if (apnToDcId != null) {
4218             Set<Entry<String, Integer>> apnToDcIdSet = apnToDcId.entrySet();
4219             pw.println(" mApnToDataConnectonId size=" + apnToDcIdSet.size());
4220             for (Entry<String, Integer> entry : apnToDcIdSet) {
4221                 pw.printf(" mApnToDataConnectonId[%s]=%d\n", entry.getKey(), entry.getValue());
4222             }
4223         } else {
4224             pw.println("mApnToDataConnectionId=null");
4225         }
4226         pw.println(" ***************************************");
4227         pw.flush();
4228         ConcurrentHashMap<String, ApnContext> apnCtxs = mApnContexts;
4229         if (apnCtxs != null) {
4230             Set<Entry<String, ApnContext>> apnCtxsSet = apnCtxs.entrySet();
4231             pw.println(" mApnContexts size=" + apnCtxsSet.size());
4232             for (Entry<String, ApnContext> entry : apnCtxsSet) {
4233                 entry.getValue().dump(fd, pw, args);
4234             }
4235             pw.println(" ***************************************");
4236         } else {
4237             pw.println(" mApnContexts=null");
4238         }
4239         pw.flush();
4240         ArrayList<ApnSetting> apnSettings = mAllApnSettings;
4241         if (apnSettings != null) {
4242             pw.println(" mAllApnSettings size=" + apnSettings.size());
4243             for (int i=0; i < apnSettings.size(); i++) {
4244                 pw.printf(" mAllApnSettings[%d]: %s\n", i, apnSettings.get(i));
4245             }
4246             pw.flush();
4247         } else {
4248             pw.println(" mAllApnSettings=null");
4249         }
4250         pw.println(" mPreferredApn=" + mPreferredApn);
4251         pw.println(" mIsPsRestricted=" + mIsPsRestricted);
4252         pw.println(" mIsDisposed=" + mIsDisposed);
4253         pw.println(" mIntentReceiver=" + mIntentReceiver);
4254         pw.println(" mReregisterOnReconnectFailure=" + mReregisterOnReconnectFailure);
4255         pw.println(" canSetPreferApn=" + mCanSetPreferApn);
4256         pw.println(" mApnObserver=" + mApnObserver);
4257         pw.println(" getOverallState=" + getOverallState());
4258         pw.println(" mDataConnectionAsyncChannels=%s\n" + mDataConnectionAcHashMap);
4259         pw.println(" mAttached=" + mAttached.get());
4260         pw.flush();
4261     }
4262 
getPcscfAddress(String apnType)4263     public String[] getPcscfAddress(String apnType) {
4264         log("getPcscfAddress()");
4265         ApnContext apnContext = null;
4266 
4267         if(apnType == null){
4268             log("apnType is null, return null");
4269             return null;
4270         }
4271 
4272         if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_EMERGENCY)) {
4273             apnContext = mApnContextsById.get(DctConstants.APN_EMERGENCY_ID);
4274         } else if (TextUtils.equals(apnType, PhoneConstants.APN_TYPE_IMS)) {
4275             apnContext = mApnContextsById.get(DctConstants.APN_IMS_ID);
4276         } else {
4277             log("apnType is invalid, return null");
4278             return null;
4279         }
4280 
4281         if (apnContext == null) {
4282             log("apnContext is null, return null");
4283             return null;
4284         }
4285 
4286         DcAsyncChannel dcac = apnContext.getDcAc();
4287         String[] result = null;
4288 
4289         if (dcac != null) {
4290             result = dcac.getPcscfAddr();
4291 
4292             for (int i = 0; i < result.length; i++) {
4293                 log("Pcscf[" + i + "]: " + result[i]);
4294             }
4295             return result;
4296         }
4297         return null;
4298     }
4299 
4300     /**
4301      * Read APN configuration from Telephony.db for Emergency APN
4302      * All opertors recognize the connection request for EPDN based on APN type
4303      * PLMN name,APN name are not mandatory parameters
4304      */
initEmergencyApnSetting()4305     private void initEmergencyApnSetting() {
4306         // Operator Numeric is not available when sim records are not loaded.
4307         // Query Telephony.db with APN type as EPDN request does not
4308         // require APN name, plmn and all operators support same APN config.
4309         // DB will contain only one entry for Emergency APN
4310         String selection = "type=\"emergency\"";
4311         Cursor cursor = mPhone.getContext().getContentResolver().query(
4312                 Telephony.Carriers.CONTENT_URI, null, selection, null, null);
4313 
4314         if (cursor != null) {
4315             if (cursor.getCount() > 0) {
4316                 if (cursor.moveToFirst()) {
4317                     mEmergencyApn = makeApnSetting(cursor);
4318                 }
4319             }
4320             cursor.close();
4321         }
4322     }
4323 
4324     /**
4325      * Add the Emergency APN settings to APN settings list
4326      */
addEmergencyApnSetting()4327     private void addEmergencyApnSetting() {
4328         if(mEmergencyApn != null) {
4329             if(mAllApnSettings == null) {
4330                 mAllApnSettings = new ArrayList<ApnSetting>();
4331             } else {
4332                 boolean hasEmergencyApn = false;
4333                 for (ApnSetting apn : mAllApnSettings) {
4334                     if (ArrayUtils.contains(apn.types, PhoneConstants.APN_TYPE_EMERGENCY)) {
4335                         hasEmergencyApn = true;
4336                         break;
4337                     }
4338                 }
4339 
4340                 if(hasEmergencyApn == false) {
4341                     mAllApnSettings.add(mEmergencyApn);
4342                 } else {
4343                     log("addEmergencyApnSetting - E-APN setting is already present");
4344                 }
4345             }
4346         }
4347     }
4348 
cleanUpConnectionsOnUpdatedApns(boolean tearDown)4349     private void cleanUpConnectionsOnUpdatedApns(boolean tearDown) {
4350         if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
4351         if (mAllApnSettings.isEmpty()) {
4352             cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED);
4353         } else {
4354             for (ApnContext apnContext : mApnContexts.values()) {
4355                 if (VDBG) log("cleanUpConnectionsOnUpdatedApns for "+ apnContext);
4356 
4357                 boolean cleanUpApn = true;
4358                 ArrayList<ApnSetting> currentWaitingApns = apnContext.getWaitingApns();
4359 
4360                 if ((currentWaitingApns != null) && (!apnContext.isDisconnected())) {
4361                     int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
4362                     ArrayList<ApnSetting> waitingApns = buildWaitingApns(
4363                             apnContext.getApnType(), radioTech);
4364                     if (VDBG) log("new waitingApns:" + waitingApns);
4365                     if (waitingApns.size() == currentWaitingApns.size()) {
4366                         cleanUpApn = false;
4367                         for (int i = 0; i < waitingApns.size(); i++) {
4368                             if (!currentWaitingApns.get(i).equals(waitingApns.get(i))) {
4369                                 if (VDBG) log("new waiting apn is different at " + i);
4370                                 cleanUpApn = true;
4371                                 apnContext.setWaitingApns(waitingApns);
4372                                 break;
4373                             }
4374                         }
4375                     }
4376                 }
4377 
4378                 if (cleanUpApn) {
4379                     apnContext.setReason(Phone.REASON_APN_CHANGED);
4380                     cleanUpConnection(true, apnContext);
4381                 }
4382             }
4383         }
4384 
4385         if (!isConnected()) {
4386             stopNetStatPoll();
4387             stopDataStallAlarm();
4388         }
4389 
4390         mRequestedApnType = PhoneConstants.APN_TYPE_DEFAULT;
4391 
4392         if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount);
4393         if (tearDown && mDisconnectPendingCount == 0) {
4394             notifyDataDisconnectComplete();
4395             notifyAllDataDisconnected();
4396         }
4397     }
4398 
4399     /**
4400      * Polling stuff
4401      */
resetPollStats()4402     private void resetPollStats() {
4403         mTxPkts = -1;
4404         mRxPkts = -1;
4405         mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
4406     }
4407 
startNetStatPoll()4408     private void startNetStatPoll() {
4409         if (getOverallState() == DctConstants.State.CONNECTED
4410                 && mNetStatPollEnabled == false) {
4411             if (DBG) {
4412                 log("startNetStatPoll");
4413             }
4414             resetPollStats();
4415             mNetStatPollEnabled = true;
4416             mPollNetStat.run();
4417         }
4418         if (mPhone != null) {
4419             mPhone.notifyDataActivity();
4420         }
4421     }
4422 
stopNetStatPoll()4423     private void stopNetStatPoll() {
4424         mNetStatPollEnabled = false;
4425         removeCallbacks(mPollNetStat);
4426         if (DBG) {
4427             log("stopNetStatPoll");
4428         }
4429 
4430         // To sync data activity icon in the case of switching data connection to send MMS.
4431         if (mPhone != null) {
4432             mPhone.notifyDataActivity();
4433         }
4434     }
4435 
sendStartNetStatPoll(DctConstants.Activity activity)4436     public void sendStartNetStatPoll(DctConstants.Activity activity) {
4437         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
4438         msg.arg1 = DctConstants.ENABLED;
4439         msg.obj = activity;
4440         sendMessage(msg);
4441     }
4442 
handleStartNetStatPoll(DctConstants.Activity activity)4443     private void handleStartNetStatPoll(DctConstants.Activity activity) {
4444         startNetStatPoll();
4445         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
4446         setActivity(activity);
4447     }
4448 
sendStopNetStatPoll(DctConstants.Activity activity)4449     public void sendStopNetStatPoll(DctConstants.Activity activity) {
4450         Message msg = obtainMessage(DctConstants.CMD_NET_STAT_POLL);
4451         msg.arg1 = DctConstants.DISABLED;
4452         msg.obj = activity;
4453         sendMessage(msg);
4454     }
4455 
handleStopNetStatPoll(DctConstants.Activity activity)4456     private void handleStopNetStatPoll(DctConstants.Activity activity) {
4457         stopNetStatPoll();
4458         stopDataStallAlarm();
4459         setActivity(activity);
4460     }
4461 
updateDataActivity()4462     private void updateDataActivity() {
4463         long sent, received;
4464 
4465         DctConstants.Activity newActivity;
4466 
4467         TxRxSum preTxRxSum = new TxRxSum(mTxPkts, mRxPkts);
4468         TxRxSum curTxRxSum = new TxRxSum();
4469         curTxRxSum.updateTxRxSum();
4470         mTxPkts = curTxRxSum.txPkts;
4471         mRxPkts = curTxRxSum.rxPkts;
4472 
4473         if (VDBG) {
4474             log("updateDataActivity: curTxRxSum=" + curTxRxSum + " preTxRxSum=" + preTxRxSum);
4475         }
4476 
4477         if (mNetStatPollEnabled && (preTxRxSum.txPkts > 0 || preTxRxSum.rxPkts > 0)) {
4478             sent = mTxPkts - preTxRxSum.txPkts;
4479             received = mRxPkts - preTxRxSum.rxPkts;
4480 
4481             if (VDBG)
4482                 log("updateDataActivity: sent=" + sent + " received=" + received);
4483             if (sent > 0 && received > 0) {
4484                 newActivity = DctConstants.Activity.DATAINANDOUT;
4485             } else if (sent > 0 && received == 0) {
4486                 newActivity = DctConstants.Activity.DATAOUT;
4487             } else if (sent == 0 && received > 0) {
4488                 newActivity = DctConstants.Activity.DATAIN;
4489             } else {
4490                 newActivity = (mActivity == DctConstants.Activity.DORMANT) ?
4491                         mActivity : DctConstants.Activity.NONE;
4492             }
4493 
4494             if (mActivity != newActivity && mIsScreenOn) {
4495                 if (VDBG)
4496                     log("updateDataActivity: newActivity=" + newActivity);
4497                 mActivity = newActivity;
4498                 mPhone.notifyDataActivity();
4499             }
4500         }
4501     }
4502 
handlePcoData(AsyncResult ar)4503     private void handlePcoData(AsyncResult ar) {
4504         if (ar.exception != null) {
4505             Rlog.e(LOG_TAG, "PCO_DATA exception: " + ar.exception);
4506             return;
4507         }
4508         PcoData pcoData = (PcoData)(ar.result);
4509         ArrayList<DataConnection> dcList = new ArrayList<>();
4510         DataConnection temp = mDcc.getActiveDcByCid(pcoData.cid);
4511         if (temp != null) {
4512             dcList.add(temp);
4513         }
4514         if (dcList.size() == 0) {
4515             Rlog.e(LOG_TAG, "PCO_DATA for unknown cid: " + pcoData.cid + ", inferring");
4516             for (DataConnection dc : mDataConnections.values()) {
4517                 final int cid = dc.getCid();
4518                 if (cid == pcoData.cid) {
4519                     if (VDBG) Rlog.d(LOG_TAG, "  found " + dc);
4520                     dcList.clear();
4521                     dcList.add(dc);
4522                     break;
4523                 }
4524                 // check if this dc is still connecting
4525                 if (cid == -1) {
4526                     for (ApnContext apnContext : dc.mApnContexts.keySet()) {
4527                         if (apnContext.getState() == DctConstants.State.CONNECTING) {
4528                             if (VDBG) Rlog.d(LOG_TAG, "  found potential " + dc);
4529                             dcList.add(dc);
4530                             break;
4531                         }
4532                     }
4533                 }
4534             }
4535         }
4536         if (dcList.size() == 0) {
4537             Rlog.e(LOG_TAG, "PCO_DATA - couldn't infer cid");
4538             return;
4539         }
4540         for (DataConnection dc : dcList) {
4541             if (dc.mApnContexts.size() == 0) {
4542                 break;
4543             }
4544             // send one out for each apn type in play
4545             for (ApnContext apnContext : dc.mApnContexts.keySet()) {
4546                 String apnType = apnContext.getApnType();
4547 
4548                 final Intent intent = new Intent(TelephonyIntents.ACTION_CARRIER_SIGNAL_PCO_VALUE);
4549                 intent.putExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY, apnType);
4550                 intent.putExtra(TelephonyIntents.EXTRA_APN_PROTO_KEY, pcoData.bearerProto);
4551                 intent.putExtra(TelephonyIntents.EXTRA_PCO_ID_KEY, pcoData.pcoId);
4552                 intent.putExtra(TelephonyIntents.EXTRA_PCO_VALUE_KEY, pcoData.contents);
4553                 mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(intent);
4554             }
4555         }
4556     }
4557 
4558     /**
4559      * Data-Stall
4560      */
4561     // Recovery action taken in case of data stall
4562     private static class RecoveryAction {
4563         public static final int GET_DATA_CALL_LIST      = 0;
4564         public static final int CLEANUP                 = 1;
4565         public static final int REREGISTER              = 2;
4566         public static final int RADIO_RESTART           = 3;
4567         public static final int RADIO_RESTART_WITH_PROP = 4;
4568 
isAggressiveRecovery(int value)4569         private static boolean isAggressiveRecovery(int value) {
4570             return ((value == RecoveryAction.CLEANUP) ||
4571                     (value == RecoveryAction.REREGISTER) ||
4572                     (value == RecoveryAction.RADIO_RESTART) ||
4573                     (value == RecoveryAction.RADIO_RESTART_WITH_PROP));
4574         }
4575     }
4576 
getRecoveryAction()4577     private int getRecoveryAction() {
4578         int action = Settings.System.getInt(mResolver,
4579                 "radio.data.stall.recovery.action", RecoveryAction.GET_DATA_CALL_LIST);
4580         if (VDBG_STALL) log("getRecoveryAction: " + action);
4581         return action;
4582     }
4583 
putRecoveryAction(int action)4584     private void putRecoveryAction(int action) {
4585         Settings.System.putInt(mResolver, "radio.data.stall.recovery.action", action);
4586         if (VDBG_STALL) log("putRecoveryAction: " + action);
4587     }
4588 
doRecovery()4589     private void doRecovery() {
4590         if (getOverallState() == DctConstants.State.CONNECTED) {
4591             // Go through a series of recovery steps, each action transitions to the next action
4592             int recoveryAction = getRecoveryAction();
4593             switch (recoveryAction) {
4594             case RecoveryAction.GET_DATA_CALL_LIST:
4595                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_GET_DATA_CALL_LIST,
4596                         mSentSinceLastRecv);
4597                 if (DBG) log("doRecovery() get data call list");
4598                 mPhone.mCi.getDataCallList(obtainMessage(DctConstants.EVENT_DATA_STATE_CHANGED));
4599                 putRecoveryAction(RecoveryAction.CLEANUP);
4600                 break;
4601             case RecoveryAction.CLEANUP:
4602                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP, mSentSinceLastRecv);
4603                 if (DBG) log("doRecovery() cleanup all connections");
4604                 cleanUpAllConnections(Phone.REASON_PDP_RESET);
4605                 putRecoveryAction(RecoveryAction.REREGISTER);
4606                 break;
4607             case RecoveryAction.REREGISTER:
4608                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_REREGISTER,
4609                         mSentSinceLastRecv);
4610                 if (DBG) log("doRecovery() re-register");
4611                 mPhone.getServiceStateTracker().reRegisterNetwork(null);
4612                 putRecoveryAction(RecoveryAction.RADIO_RESTART);
4613                 break;
4614             case RecoveryAction.RADIO_RESTART:
4615                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART,
4616                         mSentSinceLastRecv);
4617                 if (DBG) log("restarting radio");
4618                 putRecoveryAction(RecoveryAction.RADIO_RESTART_WITH_PROP);
4619                 restartRadio();
4620                 break;
4621             case RecoveryAction.RADIO_RESTART_WITH_PROP:
4622                 // This is in case radio restart has not recovered the data.
4623                 // It will set an additional "gsm.radioreset" property to tell
4624                 // RIL or system to take further action.
4625                 // The implementation of hard reset recovery action is up to OEM product.
4626                 // Once RADIO_RESET property is consumed, it is expected to set back
4627                 // to false by RIL.
4628                 EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_RADIO_RESTART_WITH_PROP, -1);
4629                 if (DBG) log("restarting radio with gsm.radioreset to true");
4630                 SystemProperties.set(RADIO_RESET_PROPERTY, "true");
4631                 // give 1 sec so property change can be notified.
4632                 try {
4633                     Thread.sleep(1000);
4634                 } catch (InterruptedException e) {}
4635                 restartRadio();
4636                 putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
4637                 break;
4638             default:
4639                 throw new RuntimeException("doRecovery: Invalid recoveryAction=" +
4640                     recoveryAction);
4641             }
4642             mSentSinceLastRecv = 0;
4643         }
4644     }
4645 
updateDataStallInfo()4646     private void updateDataStallInfo() {
4647         long sent, received;
4648 
4649         TxRxSum preTxRxSum = new TxRxSum(mDataStallTxRxSum);
4650         mDataStallTxRxSum.updateTxRxSum();
4651 
4652         if (VDBG_STALL) {
4653             log("updateDataStallInfo: mDataStallTxRxSum=" + mDataStallTxRxSum +
4654                     " preTxRxSum=" + preTxRxSum);
4655         }
4656 
4657         sent = mDataStallTxRxSum.txPkts - preTxRxSum.txPkts;
4658         received = mDataStallTxRxSum.rxPkts - preTxRxSum.rxPkts;
4659 
4660         if (RADIO_TESTS) {
4661             if (SystemProperties.getBoolean("radio.test.data.stall", false)) {
4662                 log("updateDataStallInfo: radio.test.data.stall true received = 0;");
4663                 received = 0;
4664             }
4665         }
4666         if ( sent > 0 && received > 0 ) {
4667             if (VDBG_STALL) log("updateDataStallInfo: IN/OUT");
4668             mSentSinceLastRecv = 0;
4669             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
4670         } else if (sent > 0 && received == 0) {
4671             if (mPhone.getState() == PhoneConstants.State.IDLE) {
4672                 mSentSinceLastRecv += sent;
4673             } else {
4674                 mSentSinceLastRecv = 0;
4675             }
4676             if (DBG) {
4677                 log("updateDataStallInfo: OUT sent=" + sent +
4678                         " mSentSinceLastRecv=" + mSentSinceLastRecv);
4679             }
4680         } else if (sent == 0 && received > 0) {
4681             if (VDBG_STALL) log("updateDataStallInfo: IN");
4682             mSentSinceLastRecv = 0;
4683             putRecoveryAction(RecoveryAction.GET_DATA_CALL_LIST);
4684         } else {
4685             if (VDBG_STALL) log("updateDataStallInfo: NONE");
4686         }
4687     }
4688 
onDataStallAlarm(int tag)4689     private void onDataStallAlarm(int tag) {
4690         if (mDataStallAlarmTag != tag) {
4691             if (DBG) {
4692                 log("onDataStallAlarm: ignore, tag=" + tag + " expecting " + mDataStallAlarmTag);
4693             }
4694             return;
4695         }
4696         updateDataStallInfo();
4697 
4698         int hangWatchdogTrigger = Settings.Global.getInt(mResolver,
4699                 Settings.Global.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
4700                 NUMBER_SENT_PACKETS_OF_HANG);
4701 
4702         boolean suspectedStall = DATA_STALL_NOT_SUSPECTED;
4703         if (mSentSinceLastRecv >= hangWatchdogTrigger) {
4704             if (DBG) {
4705                 log("onDataStallAlarm: tag=" + tag + " do recovery action=" + getRecoveryAction());
4706             }
4707             suspectedStall = DATA_STALL_SUSPECTED;
4708             sendMessage(obtainMessage(DctConstants.EVENT_DO_RECOVERY));
4709         } else {
4710             if (VDBG_STALL) {
4711                 log("onDataStallAlarm: tag=" + tag + " Sent " + String.valueOf(mSentSinceLastRecv) +
4712                     " pkts since last received, < watchdogTrigger=" + hangWatchdogTrigger);
4713             }
4714         }
4715         startDataStallAlarm(suspectedStall);
4716     }
4717 
startDataStallAlarm(boolean suspectedStall)4718     private void startDataStallAlarm(boolean suspectedStall) {
4719         int nextAction = getRecoveryAction();
4720         int delayInMs;
4721 
4722         if (mDataStallDetectionEnabled && getOverallState() == DctConstants.State.CONNECTED) {
4723             // If screen is on or data stall is currently suspected, set the alarm
4724             // with an aggressive timeout.
4725             if (mIsScreenOn || suspectedStall || RecoveryAction.isAggressiveRecovery(nextAction)) {
4726                 delayInMs = Settings.Global.getInt(mResolver,
4727                         Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
4728                         DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
4729             } else {
4730                 delayInMs = Settings.Global.getInt(mResolver,
4731                         Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
4732                         DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT);
4733             }
4734 
4735             mDataStallAlarmTag += 1;
4736             if (VDBG_STALL) {
4737                 log("startDataStallAlarm: tag=" + mDataStallAlarmTag +
4738                         " delay=" + (delayInMs / 1000) + "s");
4739             }
4740             Intent intent = new Intent(INTENT_DATA_STALL_ALARM);
4741             intent.putExtra(DATA_STALL_ALARM_TAG_EXTRA, mDataStallAlarmTag);
4742             mDataStallAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
4743                     PendingIntent.FLAG_UPDATE_CURRENT);
4744             mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4745                     SystemClock.elapsedRealtime() + delayInMs, mDataStallAlarmIntent);
4746         } else {
4747             if (VDBG_STALL) {
4748                 log("startDataStallAlarm: NOT started, no connection tag=" + mDataStallAlarmTag);
4749             }
4750         }
4751     }
4752 
stopDataStallAlarm()4753     private void stopDataStallAlarm() {
4754         if (VDBG_STALL) {
4755             log("stopDataStallAlarm: current tag=" + mDataStallAlarmTag +
4756                     " mDataStallAlarmIntent=" + mDataStallAlarmIntent);
4757         }
4758         mDataStallAlarmTag += 1;
4759         if (mDataStallAlarmIntent != null) {
4760             mAlarmManager.cancel(mDataStallAlarmIntent);
4761             mDataStallAlarmIntent = null;
4762         }
4763     }
4764 
restartDataStallAlarm()4765     private void restartDataStallAlarm() {
4766         if (isConnected() == false) return;
4767         // To be called on screen status change.
4768         // Do not cancel the alarm if it is set with aggressive timeout.
4769         int nextAction = getRecoveryAction();
4770 
4771         if (RecoveryAction.isAggressiveRecovery(nextAction)) {
4772             if (DBG) log("restartDataStallAlarm: action is pending. not resetting the alarm.");
4773             return;
4774         }
4775         if (VDBG_STALL) log("restartDataStallAlarm: stop then start.");
4776         stopDataStallAlarm();
4777         startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);
4778     }
4779 
4780     /**
4781      * Provisioning APN
4782      */
onActionIntentProvisioningApnAlarm(Intent intent)4783     private void onActionIntentProvisioningApnAlarm(Intent intent) {
4784         if (DBG) log("onActionIntentProvisioningApnAlarm: action=" + intent.getAction());
4785         Message msg = obtainMessage(DctConstants.EVENT_PROVISIONING_APN_ALARM,
4786                 intent.getAction());
4787         msg.arg1 = intent.getIntExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, 0);
4788         sendMessage(msg);
4789     }
4790 
startProvisioningApnAlarm()4791     private void startProvisioningApnAlarm() {
4792         int delayInMs = Settings.Global.getInt(mResolver,
4793                                 Settings.Global.PROVISIONING_APN_ALARM_DELAY_IN_MS,
4794                                 PROVISIONING_APN_ALARM_DELAY_IN_MS_DEFAULT);
4795         if (Build.IS_DEBUGGABLE) {
4796             // Allow debug code to use a system property to provide another value
4797             String delayInMsStrg = Integer.toString(delayInMs);
4798             delayInMsStrg = System.getProperty(DEBUG_PROV_APN_ALARM, delayInMsStrg);
4799             try {
4800                 delayInMs = Integer.parseInt(delayInMsStrg);
4801             } catch (NumberFormatException e) {
4802                 loge("startProvisioningApnAlarm: e=" + e);
4803             }
4804         }
4805         mProvisioningApnAlarmTag += 1;
4806         if (DBG) {
4807             log("startProvisioningApnAlarm: tag=" + mProvisioningApnAlarmTag +
4808                     " delay=" + (delayInMs / 1000) + "s");
4809         }
4810         Intent intent = new Intent(INTENT_PROVISIONING_APN_ALARM);
4811         intent.putExtra(PROVISIONING_APN_ALARM_TAG_EXTRA, mProvisioningApnAlarmTag);
4812         mProvisioningApnAlarmIntent = PendingIntent.getBroadcast(mPhone.getContext(), 0, intent,
4813                 PendingIntent.FLAG_UPDATE_CURRENT);
4814         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
4815                 SystemClock.elapsedRealtime() + delayInMs, mProvisioningApnAlarmIntent);
4816     }
4817 
stopProvisioningApnAlarm()4818     private void stopProvisioningApnAlarm() {
4819         if (DBG) {
4820             log("stopProvisioningApnAlarm: current tag=" + mProvisioningApnAlarmTag +
4821                     " mProvsioningApnAlarmIntent=" + mProvisioningApnAlarmIntent);
4822         }
4823         mProvisioningApnAlarmTag += 1;
4824         if (mProvisioningApnAlarmIntent != null) {
4825             mAlarmManager.cancel(mProvisioningApnAlarmIntent);
4826             mProvisioningApnAlarmIntent = null;
4827         }
4828     }
4829 
4830 }
4831