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