2 * Copyright (C) 2006 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony.gsm;
19 import android.app.AlarmManager;
20 import android.app.PendingIntent;
21 import android.content.ContentResolver;
22 import android.content.ContentValues;
23 import android.content.Context;
24 import android.content.Intent;
25 import android.content.IntentFilter;
26 import android.database.ContentObserver;
27 import android.database.Cursor;
28 import android.net.ConnectivityManager;
29 import android.net.ProxyProperties;
30 import android.net.TrafficStats;
31 import android.net.Uri;
32 import android.net.LinkCapabilities;
33 import android.net.LinkProperties;
34 import android.net.NetworkConfig;
35 import android.os.AsyncResult;
36 import android.os.Message;
37 import android.os.SystemClock;
38 import android.os.SystemProperties;
39 import android.provider.Settings;
40 import android.provider.Telephony;
41 import android.telephony.CellLocation;
42 import android.telephony.ServiceState;
43 import android.telephony.TelephonyManager;
44 import android.telephony.cdma.CdmaCellLocation;
45 import android.telephony.gsm.GsmCellLocation;
46 import android.text.TextUtils;
47 import android.util.EventLog;
48 import android.util.Log;
49 import android.preference.PreferenceManager;
51 import com.android.internal.R;
52 import com.android.internal.telephony.ApnContext;
53 import com.android.internal.telephony.ApnSetting;
54 import com.android.internal.telephony.DataCallState;
55 import com.android.internal.telephony.DataConnection;
56 import com.android.internal.telephony.DataConnectionAc;
57 import com.android.internal.telephony.DataConnectionTracker;
58 import com.android.internal.telephony.Phone;
59 import com.android.internal.telephony.PhoneBase;
60 import com.android.internal.telephony.RetryManager;
61 import com.android.internal.telephony.EventLogTags;
62 import com.android.internal.telephony.DataConnection.FailCause;
63 import com.android.internal.telephony.RILConstants;
64 import com.android.internal.util.AsyncChannel;
66 import java.io.IOException;
67 import java.net.InetAddress;
68 import java.net.InetSocketAddress;
69 import java.net.UnknownHostException;
70 import java.util.ArrayList;
71 import java.util.Collection;
72 import java.util.concurrent.ConcurrentHashMap;
73 import java.util.List;
75 import java.util.HashMap;
80 public final class GsmDataConnectionTracker extends DataConnectionTracker {
81 protected final String LOG_TAG = "GSM";
84 * Handles changes to the APN db.
86 private class ApnChangeObserver extends ContentObserver {
87 public ApnChangeObserver () {
88 super(mDataConnectionTracker);
92 public void onChange(boolean selfChange) {
93 sendMessage(obtainMessage(EVENT_APN_CHANGED));
97 //***** Instance Variables
99 private boolean mReregisterOnReconnectFailure = false;
100 private ContentResolver mResolver;
102 // Count of PDP reset attempts; reset when we see incoming,
103 // call reRegisterNetwork, or pingTest succeeds.
104 private int mPdpResetCount = 0;
106 // Recovery action taken in case of data stall
107 enum RecoveryAction {REREGISTER, RADIO_RESTART, RADIO_RESET};
108 private RecoveryAction mRecoveryAction = RecoveryAction.REREGISTER;
113 private static final int POLL_PDP_MILLIS = 5 * 1000;
115 private static final String INTENT_RECONNECT_ALARM = "com.android.internal.telephony.gprs-reconnect";
116 private static final String INTENT_RECONNECT_ALARM_EXTRA_TYPE = "type";
118 static final Uri PREFERAPN_URI = Uri.parse("content://telephony/carriers/preferapn");
119 static final String APN_ID = "apn_id";
120 private boolean canSetPreferApn = false;
121 private boolean mRadioAvailable = false;
124 protected void onActionIntentReconnectAlarm(Intent intent) {
125 if (DBG) log("GPRS reconnect alarm. Previous state was " + mState);
127 String reason = intent.getStringExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON);
128 int connectionId = intent.getIntExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE, -1);
130 DataConnectionAc dcac= mDataConnectionAsyncChannels.get(connectionId);
133 for (ApnContext apnContext : dcac.getApnListSync()) {
134 apnContext.setReason(reason);
135 if (apnContext.getState() == State.FAILED) {
136 apnContext.setState(State.IDLE);
138 sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA, apnContext));
140 // Alram had expired. Clear pending intent recorded on the DataConnection.
141 dcac.setReconnectIntentSync(null);
145 /** Watches for changes to the APN db. */
146 private ApnChangeObserver mApnObserver;
150 public GsmDataConnectionTracker(PhoneBase p) {
153 p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null);
154 p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
155 p.mIccRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null);
156 p.mCM.registerForDataNetworkStateChanged (this, EVENT_DATA_STATE_CHANGED, null);
157 p.getCallTracker().registerForVoiceCallEnded (this, EVENT_VOICE_CALL_ENDED, null);
158 p.getCallTracker().registerForVoiceCallStarted (this, EVENT_VOICE_CALL_STARTED, null);
159 p.getServiceStateTracker().registerForDataConnectionAttached(this,
160 EVENT_DATA_CONNECTION_ATTACHED, null);
161 p.getServiceStateTracker().registerForDataConnectionDetached(this,
162 EVENT_DATA_CONNECTION_DETACHED, null);
163 p.getServiceStateTracker().registerForRoamingOn(this, EVENT_ROAMING_ON, null);
164 p.getServiceStateTracker().registerForRoamingOff(this, EVENT_ROAMING_OFF, null);
165 p.getServiceStateTracker().registerForPsRestrictedEnabled(this,
166 EVENT_PS_RESTRICT_ENABLED, null);
167 p.getServiceStateTracker().registerForPsRestrictedDisabled(this,
168 EVENT_PS_RESTRICT_DISABLED, null);
170 mDataConnectionTracker = this;
171 mResolver = mPhone.getContext().getContentResolver();
173 mApnObserver = new ApnChangeObserver();
174 p.getContext().getContentResolver().registerContentObserver(
175 Telephony.Carriers.CONTENT_URI, true, mApnObserver);
177 mApnContexts = new ConcurrentHashMap<String, ApnContext>();
178 initApnContextsAndDataConnection();
179 broadcastMessenger();
183 public void dispose() {
184 cleanUpAllConnections(false, null);
188 //Unregister for all events
189 mPhone.mCM.unregisterForAvailable(this);
190 mPhone.mCM.unregisterForOffOrNotAvailable(this);
191 mPhone.mIccRecords.unregisterForRecordsLoaded(this);
192 mPhone.mCM.unregisterForDataNetworkStateChanged(this);
193 mPhone.getCallTracker().unregisterForVoiceCallEnded(this);
194 mPhone.getCallTracker().unregisterForVoiceCallStarted(this);
195 mPhone.getServiceStateTracker().unregisterForDataConnectionAttached(this);
196 mPhone.getServiceStateTracker().unregisterForDataConnectionDetached(this);
197 mPhone.getServiceStateTracker().unregisterForRoamingOn(this);
198 mPhone.getServiceStateTracker().unregisterForRoamingOff(this);
199 mPhone.getServiceStateTracker().unregisterForPsRestrictedEnabled(this);
200 mPhone.getServiceStateTracker().unregisterForPsRestrictedDisabled(this);
202 mPhone.getContext().getContentResolver().unregisterContentObserver(this.mApnObserver);
203 mApnContexts.clear();
205 destroyDataConnections();
209 public boolean isApnTypeActive(String type) {
210 ApnContext apnContext = mApnContexts.get(type);
211 if (apnContext == null) return false;
213 return (apnContext.getDataConnection() != null);
217 protected boolean isDataPossible(String apnType) {
218 ApnContext apnContext = mApnContexts.get(apnType);
219 if (apnContext == null) {
222 boolean apnContextIsEnabled = apnContext.isEnabled();
223 State apnContextState = apnContext.getState();
224 boolean apnTypePossible = !(apnContextIsEnabled &&
225 (apnContextState == State.FAILED));
226 boolean dataAllowed = isDataAllowed();
227 boolean possible = dataAllowed && apnTypePossible;
230 log(String.format("isDataPossible(%s): possible=%b isDataAllowed=%b " +
231 "apnTypePossible=%b apnContextisEnabled=%b apnContextState()=%s",
232 apnType, possible, dataAllowed, apnTypePossible,
233 apnContextIsEnabled, apnContextState));
239 protected void finalize() {
240 if(DBG) log("finalize");
244 protected String getActionIntentReconnectAlarm() {
245 return INTENT_RECONNECT_ALARM;
248 private ApnContext addApnContext(String type) {
249 ApnContext apnContext = new ApnContext(type, LOG_TAG);
250 apnContext.setDependencyMet(false);
251 mApnContexts.put(type, apnContext);
255 protected void initApnContextsAndDataConnection() {
256 boolean defaultEnabled = SystemProperties.getBoolean(DEFALUT_DATA_ON_BOOT_PROP, true);
257 // Load device network attributes from resources
258 String[] networkConfigStrings = mPhone.getContext().getResources().getStringArray(
259 com.android.internal.R.array.networkAttributes);
260 for (String networkConfigString : networkConfigStrings) {
261 NetworkConfig networkConfig = new NetworkConfig(networkConfigString);
262 ApnContext apnContext = null;
264 switch (networkConfig.type) {
265 case ConnectivityManager.TYPE_MOBILE:
266 apnContext = addApnContext(Phone.APN_TYPE_DEFAULT);
267 apnContext.setEnabled(defaultEnabled);
269 case ConnectivityManager.TYPE_MOBILE_MMS:
270 apnContext = addApnContext(Phone.APN_TYPE_MMS);
272 case ConnectivityManager.TYPE_MOBILE_SUPL:
273 apnContext = addApnContext(Phone.APN_TYPE_SUPL);
275 case ConnectivityManager.TYPE_MOBILE_DUN:
276 apnContext = addApnContext(Phone.APN_TYPE_DUN);
278 case ConnectivityManager.TYPE_MOBILE_HIPRI:
279 apnContext = addApnContext(Phone.APN_TYPE_HIPRI);
281 case ConnectivityManager.TYPE_MOBILE_FOTA:
282 apnContext = addApnContext(Phone.APN_TYPE_FOTA);
284 case ConnectivityManager.TYPE_MOBILE_IMS:
285 apnContext = addApnContext(Phone.APN_TYPE_IMS);
287 case ConnectivityManager.TYPE_MOBILE_CBS:
288 apnContext = addApnContext(Phone.APN_TYPE_CBS);
291 // skip unknown types
294 if (apnContext != null) {
295 // set the prop, but also apply the newly set enabled and dependency values
296 onSetDependencyMet(apnContext.getApnType(), networkConfig.dependencyMet);
302 protected LinkProperties getLinkProperties(String apnType) {
303 ApnContext apnContext = mApnContexts.get(apnType);
304 if (apnContext != null) {
305 DataConnectionAc dcac = apnContext.getDataConnectionAc();
307 if (DBG) log("return link properites for " + apnType);
308 return dcac.getLinkPropertiesSync();
311 if (DBG) log("return new LinkProperties");
312 return new LinkProperties();
316 protected LinkCapabilities getLinkCapabilities(String apnType) {
317 ApnContext apnContext = mApnContexts.get(apnType);
318 if (apnContext!=null) {
319 DataConnectionAc dataConnectionAc = apnContext.getDataConnectionAc();
320 if (dataConnectionAc != null) {
321 if (DBG) log("get active pdp is not null, return link Capabilities for " + apnType);
322 return dataConnectionAc.getLinkCapabilitiesSync();
325 if (DBG) log("return new LinkCapabilities");
326 return new LinkCapabilities();
330 // Return all active apn types
331 public String[] getActiveApnTypes() {
332 if (DBG) log("get all active apn types");
333 ArrayList<String> result = new ArrayList<String>();
335 for (ApnContext apnContext : mApnContexts.values()) {
336 if (apnContext.isReady()) {
337 result.add(apnContext.getApnType());
341 return (String[])result.toArray(new String[0]);
345 // Return active apn of specific apn type
346 public String getActiveApnString(String apnType) {
347 if (DBG) log( "get active apn string for type:" + apnType);
348 ApnContext apnContext = mApnContexts.get(apnType);
349 if (apnContext != null) {
350 ApnSetting apnSetting = apnContext.getApnSetting();
351 if (apnSetting != null) {
352 return apnSetting.apn;
359 public boolean isApnTypeEnabled(String apnType) {
360 ApnContext apnContext = mApnContexts.get(apnType);
361 if (apnContext == null) {
364 return apnContext.isEnabled();
368 protected void setState(State s) {
369 if (DBG) log("setState should not be used in GSM" + s);
372 // Return state of specific apn type
374 public State getState(String apnType) {
375 ApnContext apnContext = mApnContexts.get(apnType);
376 if (apnContext != null) {
377 return apnContext.getState();
382 // Return state of overall
383 public State getOverallState() {
384 boolean isConnecting = false;
385 boolean isFailed = true; // All enabled Apns should be FAILED.
386 boolean isAnyEnabled = false;
388 for (ApnContext apnContext : mApnContexts.values()) {
389 if (apnContext.isEnabled()) {
391 switch (apnContext.getState()) {
394 if (DBG) log("overall state is CONNECTED");
395 return State.CONNECTED;
409 if (!isAnyEnabled) { // Nothing enabled. return IDLE.
410 if (DBG) log( "overall state is IDLE");
415 if (DBG) log( "overall state is CONNECTING");
416 return State.CONNECTING;
417 } else if (!isFailed) {
418 if (DBG) log( "overall state is IDLE");
421 if (DBG) log( "overall state is FAILED");
427 * Ensure that we are connected to an APN of the specified type.
429 * @param type the APN type
430 * @return Success is indicated by {@code Phone.APN_ALREADY_ACTIVE} or
431 * {@code Phone.APN_REQUEST_STARTED}. In the latter case, a
432 * broadcast will be sent by the ConnectivityManager when a
433 * connection to the APN has been established.
436 public synchronized int enableApnType(String apnType) {
437 ApnContext apnContext = mApnContexts.get(apnType);
438 if (apnContext == null || !isApnTypeAvailable(apnType)) {
439 if (DBG) log("enableApnType: " + apnType + " is type not available");
440 return Phone.APN_TYPE_NOT_AVAILABLE;
443 // If already active, return
444 if (DBG) log("enableApnType: " + apnType + " mState(" + apnContext.getState() + ")");
446 if (apnContext.getState() == State.CONNECTED) {
447 if (DBG) log("enableApnType: return APN_ALREADY_ACTIVE");
448 return Phone.APN_ALREADY_ACTIVE;
450 setEnabled(apnTypeToId(apnType), true);
452 log("enableApnType: new apn request for type " + apnType +
453 " return APN_REQUEST_STARTED");
455 return Phone.APN_REQUEST_STARTED;
458 // A new APN has gone active and needs to send events to catch up with the
460 private void notifyApnIdUpToCurrent(String reason, ApnContext apnContext, String type) {
461 switch (apnContext.getState()) {
467 mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTING);
471 mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTING);
472 mPhone.notifyDataConnection(reason, type, Phone.DataState.CONNECTED);
478 public synchronized int disableApnType(String type) {
479 if (DBG) log("disableApnType:" + type);
480 ApnContext apnContext = mApnContexts.get(type);
482 if (apnContext != null) {
483 setEnabled(apnTypeToId(type), false);
484 if (apnContext.getState() != State.IDLE && apnContext.getState() != State.FAILED) {
485 if (DBG) log("diableApnType: return APN_REQUEST_STARTED");
486 return Phone.APN_REQUEST_STARTED;
488 if (DBG) log("disableApnType: return APN_ALREADY_INACTIVE");
489 return Phone.APN_ALREADY_INACTIVE;
494 log("disableApnType: no apn context was found, return APN_REQUEST_FAILED");
496 return Phone.APN_REQUEST_FAILED;
501 protected boolean isApnTypeAvailable(String type) {
502 if (type.equals(Phone.APN_TYPE_DUN) && fetchDunApn() != null) {
506 if (mAllApns != null) {
507 for (ApnSetting apn : mAllApns) {
508 if (apn.canHandleType(type)) {
517 * Report on whether data connectivity is enabled for any APN.
518 * @return {@code false} if data connectivity has been explicitly disabled,
519 * {@code true} otherwise.
522 public synchronized boolean getAnyDataEnabled() {
523 if (!(mInternalDataEnabled && mDataEnabled)) return false;
524 for (ApnContext apnContext : mApnContexts.values()) {
525 // Make sure we dont have a context that going down
526 // and is explicitly disabled.
527 if (isDataAllowed(apnContext)) {
534 private boolean isDataAllowed(ApnContext apnContext) {
535 return apnContext.isReady() && isDataAllowed();
538 //****** Called from ServiceStateTracker
540 * Invoked when ServiceStateTracker observes a transition from GPRS
543 protected void onDataConnectionDetached() {
545 * We presently believe it is unnecessary to tear down the PDP context
546 * when GPRS detaches, but we should stop the network polling.
548 if (DBG) log ("onDataConnectionDetached: stop polling and notify detached");
550 notifyDataConnection(Phone.REASON_DATA_DETACHED);
553 private void onDataConnectionAttached() {
554 if (DBG) log("onDataConnectionAttached");
555 if (getOverallState() == State.CONNECTED) {
556 if (DBG) log("onDataConnectionAttached: start polling notify attached");
558 notifyDataConnection(Phone.REASON_DATA_ATTACHED);
561 setupDataOnReadyApns(Phone.REASON_DATA_ATTACHED);
565 protected boolean isDataAllowed() {
566 int gprsState = mPhone.getServiceStateTracker().getCurrentDataConnectionState();
567 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
570 (gprsState == ServiceState.STATE_IN_SERVICE || mAutoAttachOnCreation) &&
571 mPhone.mIccRecords.getRecordsLoaded() &&
572 mPhone.mIccRecords.isProvisioned() &&
573 mPhone.getState() == Phone.State.IDLE &&
574 mInternalDataEnabled &&
575 (!mPhone.getServiceState().getRoaming() || getDataOnRoamingEnabled()) &&
578 if (!allowed && DBG) {
580 if (!((gprsState == ServiceState.STATE_IN_SERVICE) || mAutoAttachOnCreation)) {
581 reason += " - gprs= " + gprsState;
583 if (!mPhone.mIccRecords.getRecordsLoaded()) reason += " - SIM not loaded";
584 if (!mPhone.mIccRecords.isProvisioned()) reason += " - SIM not provisioned";
585 if (mPhone.getState() != Phone.State.IDLE) {
586 reason += " - PhoneState= " + mPhone.getState();
588 if (!mInternalDataEnabled) reason += " - mInternalDataEnabled= false";
589 if (mPhone.getServiceState().getRoaming() && !getDataOnRoamingEnabled()) {
590 reason += " - Roaming and data roaming not enabled";
592 if (mIsPsRestricted) reason += " - mIsPsRestricted= true";
593 if (!desiredPowerState) reason += " - desiredPowerState= false";
594 if (DBG) log("isDataAllowed: not allowed due to" + reason);
599 private void setupDataOnReadyApns(String reason) {
600 // Stop reconnect alarms on all data connections pending
601 // retry. Reset ApnContext state to IDLE.
602 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
603 if (dcac.getReconnectIntentSync() != null) {
604 cancelReconnectAlarm(dcac);
605 if (dcac.dataConnection != null) {
606 dcac.dataConnection.resetRetryCount();
609 Collection<ApnContext> apnList = dcac.getApnListSync();
610 for (ApnContext apnContext : apnList) {
611 apnContext.setState(State.IDLE);
616 // Only check for default APN state
617 for (ApnContext apnContext : mApnContexts.values()) {
618 if (apnContext.isReady()) {
619 if (apnContext.getState() == State.IDLE) {
620 apnContext.setReason(reason);
621 trySetupData(apnContext);
627 private boolean trySetupData(String reason, String type) {
629 log("trySetupData: " + type + " due to " + (reason == null ? "(unspecified)" : reason)
630 + " isPsRestricted=" + mIsPsRestricted);
634 type = Phone.APN_TYPE_DEFAULT;
637 ApnContext apnContext = mApnContexts.get(type);
639 if (apnContext == null ){
640 if (DBG) log("trySetupData new apn context for type:" + type);
641 apnContext = new ApnContext(type, LOG_TAG);
642 mApnContexts.put(type, apnContext);
644 apnContext.setReason(reason);
646 return trySetupData(apnContext);
649 private boolean trySetupData(ApnContext apnContext) {
651 log("trySetupData for type:" + apnContext.getApnType() +
652 " due to " + apnContext.getReason());
653 log("trySetupData with mIsPsRestricted=" + mIsPsRestricted);
656 if (mPhone.getSimulatedRadioControl() != null) {
657 // Assume data is connected on the simulator
658 // FIXME this can be improved
659 apnContext.setState(State.CONNECTED);
660 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
662 log("trySetupData: (fix?) We're on the simulator; assuming data is connected");
666 boolean desiredPowerState = mPhone.getServiceStateTracker().getDesiredPowerState();
668 if ((apnContext.getState() == State.IDLE || apnContext.getState() == State.SCANNING) &&
669 isDataAllowed(apnContext) && getAnyDataEnabled()) {
671 if (apnContext.getState() == State.IDLE) {
672 ArrayList<ApnSetting> waitingApns = buildWaitingApns(apnContext.getApnType());
673 if (waitingApns.isEmpty()) {
674 if (DBG) log("trySetupData: No APN found");
675 notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN, apnContext);
676 notifyOffApnsOfAvailability(apnContext.getReason(), false);
679 apnContext.setWaitingApns(waitingApns);
681 log ("trySetupData: Create from mAllApns : " + apnListToString(mAllApns));
687 log ("Setup watingApns : " + apnListToString(apnContext.getWaitingApns()));
689 // apnContext.setReason(apnContext.getReason());
690 boolean retValue = setupData(apnContext);
691 notifyOffApnsOfAvailability(apnContext.getReason(), retValue);
694 // TODO: check the condition.
695 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)
696 && (apnContext.getState() == State.IDLE
697 || apnContext.getState() == State.SCANNING))
698 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
699 notifyOffApnsOfAvailability(apnContext.getReason(), false);
705 // Disabled apn's still need avail/unavail notificiations - send them out
706 protected void notifyOffApnsOfAvailability(String reason, boolean availability) {
707 if (mAvailability == availability) return;
708 mAvailability = availability;
710 for (ApnContext apnContext : mApnContexts.values()) {
711 if (!apnContext.isReady()) {
712 if (DBG) log("notifyOffApnOfAvailability type:" + apnContext.getApnType());
713 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
714 apnContext.getApnType(),
715 Phone.DataState.DISCONNECTED);
721 * If tearDown is true, this only tears down a CONNECTED session. Presently,
722 * there is no mechanism for abandoning an INITING/CONNECTING session,
723 * but would likely involve cancelling pending async requests or
724 * setting a flag or new state to ignore them when they came in
725 * @param tearDown true if the underlying GsmDataConnection should be
727 * @param reason reason for the clean up.
729 protected void cleanUpAllConnections(boolean tearDown, String reason) {
730 if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
732 for (ApnContext apnContext : mApnContexts.values()) {
733 apnContext.setReason(reason);
734 cleanUpConnection(tearDown, apnContext);
738 // TODO: Do we need mRequestedApnType?
739 mRequestedApnType = Phone.APN_TYPE_DEFAULT;
743 * Cleanup all connections.
745 * TODO: Cleanup only a specified connection passed as a parameter.
746 * Also, make sure when you clean up a conn, if it is last apply
747 * logic as though it is cleanupAllConnections
749 * @param tearDown true if the underlying DataConnection should be disconnected.
750 * @param reason for the clean up.
754 protected void onCleanUpAllConnections(String cause) {
755 cleanUpAllConnections(true, cause);
758 private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
760 if (apnContext == null) {
761 if (DBG) log("cleanUpConnection: apn context is null");
766 log("cleanUpConnection: tearDown=" + tearDown + " reason=" + apnContext.getReason());
768 DataConnectionAc dcac = apnContext.getDataConnectionAc();
770 boolean isConnected = (apnContext.getState() != State.IDLE
771 && apnContext.getState() != State.FAILED);
773 // The request is tearDown and but ApnContext is not connected.
774 // If apnContext is not enabled anymore, break the linkage to the DCAC/DC.
775 apnContext.setState(State.IDLE);
776 if (!apnContext.isReady()) {
777 apnContext.setDataConnection(null);
778 apnContext.setDataConnectionAc(null);
781 // Connection is still there. Try to clean up.
783 if (apnContext.getState() != State.DISCONNECTING) {
784 if (DBG) log("cleanUpConnection: tearing down");
785 Message msg = obtainMessage(EVENT_DISCONNECT_DONE, apnContext);
786 apnContext.getDataConnection().tearDown(apnContext.getReason(), msg);
787 apnContext.setState(State.DISCONNECTING);
789 // apn is connected but no reference to dcac.
790 // Should not be happen, but reset the state in case.
791 apnContext.setState(State.IDLE);
792 mPhone.notifyDataConnection(apnContext.getReason(),
793 apnContext.getApnType());
798 // force clean up the data connection.
799 if (dcac != null) dcac.resetSync();
800 apnContext.setState(State.IDLE);
801 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
802 apnContext.setDataConnection(null);
803 apnContext.setDataConnectionAc(null);
806 // make sure reconnection alarm is cleaned up if there is no ApnContext
807 // associated to the connection.
809 Collection<ApnContext> apnList = dcac.getApnListSync();
810 if (apnList.isEmpty()) {
811 cancelReconnectAlarm(dcac);
817 * Cancels the alarm associated with DCAC.
819 * @param DataConnectionAc on which the alarm should be stopped.
821 private void cancelReconnectAlarm(DataConnectionAc dcac) {
822 if (dcac == null) return;
824 PendingIntent intent = dcac.getReconnectIntentSync();
826 if (intent != null) {
828 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
830 dcac.setReconnectIntentSync(null);
835 * @param types comma delimited list of APN types
836 * @return array of APN types
838 private String[] parseTypes(String types) {
840 // If unset, set to DEFAULT.
841 if (types == null || types.equals("")) {
842 result = new String[1];
843 result[0] = Phone.APN_TYPE_ALL;
845 result = types.split(",");
850 private ArrayList<ApnSetting> createApnList(Cursor cursor) {
851 ArrayList<ApnSetting> result = new ArrayList<ApnSetting>();
852 if (cursor.moveToFirst()) {
854 String[] types = parseTypes(
855 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.TYPE)));
856 ApnSetting apn = new ApnSetting(
857 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)),
858 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NUMERIC)),
859 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.NAME)),
860 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.APN)),
861 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROXY)),
862 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PORT)),
863 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSC)),
864 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPROXY)),
865 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.MMSPORT)),
866 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
867 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
868 cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
870 cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
871 cursor.getString(cursor.getColumnIndexOrThrow(
872 Telephony.Carriers.ROAMING_PROTOCOL)));
874 } while (cursor.moveToNext());
876 if (DBG) log("createApnList: X result=" + result);
880 private boolean dataConnectionNotInUse(DataConnectionAc dcac) {
881 for (ApnContext apnContext : mApnContexts.values()) {
882 if (apnContext.getDataConnectionAc() == dcac) return false;
887 private GsmDataConnection findFreeDataConnection() {
888 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
889 if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) {
890 log("findFreeDataConnection: found free GsmDataConnection");
891 return (GsmDataConnection) dcac.dataConnection;
894 log("findFreeDataConnection: NO free GsmDataConnection");
898 protected GsmDataConnection findReadyDataConnection(ApnSetting apn) {
900 log("findReadyDataConnection: apn string <" +
901 (apn!=null?(apn.toString()):"null") +">");
905 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
906 ApnSetting apnSetting = dcac.getApnSettingSync();
908 log("findReadyDataConnection: dc apn string <" +
909 (apnSetting != null ? (apnSetting.toString()) : "null") + ">");
911 if ((apnSetting != null) && TextUtils.equals(apnSetting.toString(), apn.toString())) {
912 return (GsmDataConnection) dcac.dataConnection;
919 private boolean setupData(ApnContext apnContext) {
920 if (DBG) log("setupData: apnContext=" + apnContext);
922 GsmDataConnection dc;
924 int profileId = getApnProfileID(apnContext.getApnType());
925 apn = apnContext.getNextWaitingApn();
927 if (DBG) log("setupData: return for no apn found!");
931 // First, check to see if ApnContext already has DC.
932 // This could happen if the retries are currently engaged.
933 dc = (GsmDataConnection)apnContext.getDataConnection();
937 dc = (GsmDataConnection) checkForConnectionForApnContext(apnContext);
940 dc = findReadyDataConnection(apn);
944 if (DBG) log("setupData: No ready GsmDataConnection found!");
945 // TODO: When allocating you are mapping type to id. If more than 1 free,
946 // then could findFreeDataConnection get the wrong one??
947 dc = findFreeDataConnection();
951 dc = createDataConnection();
955 if (DBG) log("setupData: No free GsmDataConnection found!");
959 DataConnectionAc dcac = mDataConnectionAsyncChannels.get(dc.getDataConnectionId());
960 dc.setProfileId( profileId );
961 dc.setActiveApnType(apnContext.getApnType());
962 int refCount = dcac.getRefCountSync();
963 if (DBG) log("setupData: init dc and apnContext refCount=" + refCount);
965 // configure retry count if no other Apn is using the same connection.
967 configureRetry(dc, apnContext.getApnType());
969 apnContext.setDataConnectionAc(dcac);
970 apnContext.setDataConnection(dc);
973 apnContext.setApnSetting(apn);
974 apnContext.setState(State.INITING);
975 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
976 // If reconnect alarm is active on this DataConnection, wait for the alarm being
977 // fired so that we don't disruppt data retry pattern engaged.
978 if (apnContext.getDataConnectionAc().getReconnectIntentSync() != null) {
979 if (DBG) log("setupData: data reconnection pending");
980 apnContext.setState(State.FAILED);
981 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
985 Message msg = obtainMessage();
986 msg.what = EVENT_DATA_SETUP_COMPLETE;
987 msg.obj = apnContext;
988 dc.bringUp(msg, apn);
990 if (DBG) log("setupData: initing!");
995 * Handles changes to the APN database.
997 private void onApnChanged() {
998 // TODO: How to handle when multiple APNs are active?
1001 ApnContext defaultApnContext = mApnContexts.get(Phone.APN_TYPE_DEFAULT);
1002 isConnected = (defaultApnContext.getState() != State.IDLE
1003 && defaultApnContext.getState() != State.FAILED);
1005 if (mPhone instanceof GSMPhone) {
1006 // The "current" may no longer be valid. MMS depends on this to send properly. TBD
1007 ((GSMPhone)mPhone).updateCurrentCarrierInProvider();
1010 // TODO: It'd be nice to only do this if the changed entrie(s)
1011 // match the current operator.
1012 if (DBG) log("onApnChanged: createAllApnList and cleanUpAllConnections");
1014 cleanUpAllConnections(isConnected, Phone.REASON_APN_CHANGED);
1016 setupDataOnReadyApns(Phone.REASON_APN_CHANGED);
1021 * @param cid Connection id provided from RIL.
1022 * @return DataConnectionAc associated with specified cid.
1024 private DataConnectionAc findDataConnectionAcByCid(int cid) {
1025 for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) {
1026 if (dcac.getCidSync() == cid) {
1034 * @param dcacs Collection of DataConnectionAc reported from RIL.
1035 * @return List of ApnContext whihc is connected, but does not present in
1036 * data connection list reported from RIL.
1038 private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) {
1039 if (dcacs == null) return null;
1041 ArrayList<ApnContext> list = new ArrayList<ApnContext>();
1042 for (ApnContext apnContext : mApnContexts.values()) {
1043 if (apnContext.getState() == State.CONNECTED) {
1044 boolean found = false;
1045 for (DataConnectionAc dcac : dcacs) {
1046 if (dcac == apnContext.getDataConnectionAc()) {
1047 // ApnContext holds the ref to dcac present in data call list.
1053 // ApnContext does not have dcan reorted in data call list.
1054 if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" +
1055 apnContext.toString() + ")");
1056 list.add(apnContext);
1064 * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST
1065 * or RIL_UNSOL_DATA_CALL_LIST_CHANGED
1067 private void onDataStateChanged (AsyncResult ar) {
1068 ArrayList<DataCallState> dataCallStates;
1070 if (DBG) log("onDataStateChanged(ar): E");
1071 dataCallStates = (ArrayList<DataCallState>)(ar.result);
1073 if (ar.exception != null) {
1074 // This is probably "radio not available" or something
1075 // of that sort. If so, the whole connection is going
1076 // to come down soon anyway
1077 if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore");
1080 if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size());
1082 // Create a hash map to store the dataCallState of each DataConnectionAc
1083 // TODO: Depends on how frequent the DATA_CALL_LIST got updated,
1084 // may cache response to reduce comparison.
1085 HashMap<DataCallState, DataConnectionAc> response;
1086 response = new HashMap<DataCallState, DataConnectionAc>();
1087 for (DataCallState dataCallState : dataCallStates) {
1088 DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid);
1090 if (dcac != null) response.put(dataCallState, dcac);
1093 // step1: Find a list of "connected" APN which does not have reference to
1094 // calls listed in the Data Call List.
1095 List<ApnContext> apnsToClear = findApnContextToClean(response.values());
1097 // step2: Check status of each calls in Data Call List.
1098 // Collect list of ApnContext associated with the data call if the link
1099 // has to be cleared.
1100 for (DataCallState newState : dataCallStates) {
1101 DataConnectionAc dcac = response.get(newState);
1103 // no associated DataConnection found. Ignore.
1104 if (dcac == null) continue;
1106 Collection<ApnContext> apns = dcac.getApnListSync();
1108 // filter out ApnContext with "Connected" state.
1109 ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>();
1110 for (ApnContext apnContext : apns) {
1111 if (apnContext.getState() == State.CONNECTED) {
1112 connectedApns.add(apnContext);
1116 // No "Connected" ApnContext associated with this CID. Ignore.
1117 if (connectedApns.isEmpty()) {
1121 if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid
1122 + " newState=" + newState.toString());
1123 if (newState.active != 0) {
1124 boolean resetConnection;
1125 switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) {
1127 if (DBG) log("onDataStateChanged(ar): Found but no change, skip");
1128 resetConnection = false;
1131 for (ApnContext apnContext : connectedApns) {
1132 if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" +
1133 apnContext.toString() + ")");
1134 mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED,
1135 apnContext.getApnType());
1137 // Temporary hack, at this time a transition from CDMA -> Global
1138 // fails so we'll hope for the best and not reset the connection.
1140 if (SystemProperties.getBoolean("telephony.ignore-state-changes",
1142 log("onDataStateChanged(ar): STOPSHIP don't reset, continue");
1143 resetConnection = false;
1145 // Things changed so reset connection, when hack is removed
1146 // this is the normal path.
1147 log("onDataStateChanged(ar): changed so resetting connection");
1148 resetConnection = true;
1153 if (DBG) log("onDataStateChanged(ar): an error, reset connection");
1154 resetConnection = true;
1157 if (resetConnection == false) continue;
1160 if (DBG) log("onDataStateChanged(ar): reset connection.");
1162 apnsToClear.addAll(connectedApns);
1165 // step3: Clear apn connection if applicable.
1166 if (!apnsToClear.isEmpty()) {
1167 // Add an event log when the network drops PDP
1168 int cid = getCellLocationId();
1169 EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid,
1170 TelephonyManager.getDefault().getNetworkType());
1173 for (ApnContext apnContext : apnsToClear) {
1174 cleanUpConnection(true, apnContext);
1176 if (DBG) log("onDataStateChanged(ar): X");
1179 private void notifyDefaultData(ApnContext apnContext) {
1181 log("notifyDefaultData: type=" + apnContext.getApnType()
1182 + ", reason:" + apnContext.getReason());
1184 apnContext.setState(State.CONNECTED);
1185 // setState(State.CONNECTED);
1186 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1188 // reset reconnect timer
1189 apnContext.getDataConnection().resetRetryCount();
1192 // TODO: For multiple Active APNs not exactly sure how to do this.
1193 protected void gotoIdleAndNotifyDataConnection(String reason) {
1194 if (DBG) log("gotoIdleAndNotifyDataConnection: reason=" + reason);
1195 notifyDataConnection(reason);
1199 private void resetPollStats() {
1202 mSentSinceLastRecv = 0;
1203 mNetStatPollPeriod = POLL_NETSTAT_MILLIS;
1204 mNoRecvPollCount = 0;
1207 private void doRecovery() {
1208 if (getOverallState() == State.CONNECTED) {
1209 int maxPdpReset = Settings.Secure.getInt(mResolver,
1210 Settings.Secure.PDP_WATCHDOG_MAX_PDP_RESET_FAIL_COUNT,
1211 DEFAULT_MAX_PDP_RESET_FAIL);
1212 if (mPdpResetCount < maxPdpReset) {
1214 EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
1215 if (DBG) log("doRecovery() cleanup all connections mPdpResetCount < max");
1216 cleanUpAllConnections(true, Phone.REASON_PDP_RESET);
1219 switch (mRecoveryAction) {
1221 EventLog.writeEvent(EventLogTags.PDP_REREGISTER_NETWORK, mSentSinceLastRecv);
1222 if (DBG) log("doRecovery() re-register getting preferred network type");
1223 mPhone.getServiceStateTracker().reRegisterNetwork(null);
1224 mRecoveryAction = RecoveryAction.RADIO_RESTART;
1227 EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, mSentSinceLastRecv);
1228 if (DBG) log("restarting radio");
1229 mRecoveryAction = RecoveryAction.RADIO_RESET;
1233 // This is in case radio restart has not recovered the data.
1234 // It will set an additional "gsm.radioreset" property to tell
1235 // RIL or system to take further action.
1236 // The implementation of hard reset recovery action is up to OEM product.
1237 // Once gsm.radioreset property is consumed, it is expected to set back
1239 EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET, -1);
1240 if (DBG) log("restarting radio with reset indication");
1241 SystemProperties.set("gsm.radioreset", "true");
1242 // give 1 sec so property change can be notified.
1245 } catch (InterruptedException e) {}
1249 throw new RuntimeException("doRecovery: Invalid mRecoveryAction " +
1254 if (DBG) log("doRecovery(): ignore, we're not connected");
1259 protected void startNetStatPoll() {
1260 if (getOverallState() == State.CONNECTED && mNetStatPollEnabled == false) {
1261 if (DBG) log("startNetStatPoll");
1263 mNetStatPollEnabled = true;
1269 protected void stopNetStatPoll() {
1270 mNetStatPollEnabled = false;
1271 removeCallbacks(mPollNetStat);
1272 if (DBG) log("stopNetStatPoll");
1276 protected void restartRadio() {
1277 if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
1278 cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
1279 mPhone.getServiceStateTracker().powerOffRadioSafely(this);
1280 /* Note: no need to call setRadioPower(true). Assuming the desired
1281 * radio power state is still ON (as tracked by ServiceStateTracker),
1282 * ServiceStateTracker will call setRadioPower when it receives the
1283 * RADIO_STATE_CHANGED notification for the power off. And if the
1284 * desired power state has changed in the interim, we don't want to
1285 * override it with an unconditional power on.
1288 int reset = Integer.parseInt(SystemProperties.get("net.ppp.reset-by-timeout", "0"));
1289 SystemProperties.set("net.ppp.reset-by-timeout", String.valueOf(reset+1));
1292 private Runnable mPollNetStat = new Runnable()
1296 long sent, received;
1297 long preTxPkts = -1, preRxPkts = -1;
1299 Activity newActivity;
1301 preTxPkts = mTxPkts;
1302 preRxPkts = mRxPkts;
1304 long txSum = 0, rxSum = 0;
1305 for (ApnContext apnContext : mApnContexts.values()) {
1306 if (apnContext.getState() == State.CONNECTED) {
1307 DataConnectionAc dcac = apnContext.getDataConnectionAc();
1308 if (dcac == null) continue;
1310 LinkProperties linkProp = dcac.getLinkPropertiesSync();
1311 if (linkProp == null) continue;
1313 String iface = linkProp.getInterfaceName();
1315 if (iface != null) {
1316 long stats = TrafficStats.getTxPackets(iface);
1317 if (stats > 0) txSum += stats;
1318 stats = TrafficStats.getRxPackets(iface);
1319 if (stats > 0) rxSum += stats;
1327 // log("tx " + mTxPkts + " rx " + mRxPkts);
1329 if (mNetStatPollEnabled && (preTxPkts > 0 || preRxPkts > 0)) {
1330 sent = mTxPkts - preTxPkts;
1331 received = mRxPkts - preRxPkts;
1333 if ( sent > 0 && received > 0 ) {
1334 mSentSinceLastRecv = 0;
1335 newActivity = Activity.DATAINANDOUT;
1337 mRecoveryAction = RecoveryAction.REREGISTER;
1338 } else if (sent > 0 && received == 0) {
1339 if (mPhone.getState() == Phone.State.IDLE) {
1340 mSentSinceLastRecv += sent;
1342 mSentSinceLastRecv = 0;
1344 newActivity = Activity.DATAOUT;
1345 } else if (sent == 0 && received > 0) {
1346 mSentSinceLastRecv = 0;
1347 newActivity = Activity.DATAIN;
1349 mRecoveryAction = RecoveryAction.REREGISTER;
1350 } else if (sent == 0 && received == 0) {
1351 newActivity = Activity.NONE;
1353 mSentSinceLastRecv = 0;
1354 newActivity = Activity.NONE;
1357 if (mActivity != newActivity && mIsScreenOn) {
1358 mActivity = newActivity;
1359 mPhone.notifyDataActivity();
1363 int watchdogTrigger = Settings.Secure.getInt(mResolver,
1364 Settings.Secure.PDP_WATCHDOG_TRIGGER_PACKET_COUNT,
1365 NUMBER_SENT_PACKETS_OF_HANG);
1367 if (mSentSinceLastRecv >= watchdogTrigger) {
1368 // we already have NUMBER_SENT_PACKETS sent without ack
1369 if (mNoRecvPollCount == 0) {
1370 EventLog.writeEvent(EventLogTags.PDP_RADIO_RESET_COUNTDOWN_TRIGGERED,
1371 mSentSinceLastRecv);
1374 int noRecvPollLimit = Settings.Secure.getInt(mResolver,
1375 Settings.Secure.PDP_WATCHDOG_ERROR_POLL_COUNT, NO_RECV_POLL_LIMIT);
1377 if (mNoRecvPollCount < noRecvPollLimit) {
1378 // It's possible the PDP context went down and we weren't notified.
1379 // Start polling the context list in an attempt to recover.
1380 if (DBG) log("Polling: no DATAIN in a while; polling PDP");
1381 mPhone.mCM.getDataCallList(obtainMessage(EVENT_DATA_STATE_CHANGED));
1385 // Slow down the poll interval to let things happen
1386 mNetStatPollPeriod = Settings.Secure.getInt(mResolver,
1387 Settings.Secure.PDP_WATCHDOG_ERROR_POLL_INTERVAL_MS,
1388 POLL_NETSTAT_SLOW_MILLIS);
1390 if (DBG) log("Polling: Sent " + String.valueOf(mSentSinceLastRecv) +
1391 " pkts since last received start recovery process");
1392 mNoRecvPollCount = 0;
1393 sendMessage(obtainMessage(EVENT_START_RECOVERY));
1396 mNoRecvPollCount = 0;
1398 mNetStatPollPeriod = Settings.Secure.getInt(mResolver,
1399 Settings.Secure.PDP_WATCHDOG_POLL_INTERVAL_MS, POLL_NETSTAT_MILLIS);
1401 mNetStatPollPeriod = Settings.Secure.getInt(mResolver,
1402 Settings.Secure.PDP_WATCHDOG_LONG_POLL_INTERVAL_MS,
1403 POLL_NETSTAT_SCREEN_OFF_MILLIS);
1407 if (mNetStatPollEnabled) {
1408 mDataConnectionTracker.postDelayed(this, mNetStatPollPeriod);
1414 * Returns true if the last fail cause is something that
1415 * seems like it deserves an error notification.
1416 * Transient errors are ignored
1418 private boolean shouldPostNotification(GsmDataConnection.FailCause cause) {
1419 return (cause != GsmDataConnection.FailCause.UNKNOWN);
1423 * Return true if data connection need to be setup after disconnected due to
1426 * @param reason the reason why data is disconnected
1427 * @return true if try setup data connection is need for this reason
1429 private boolean retryAfterDisconnected(String reason) {
1430 boolean retry = true;
1432 if ( Phone.REASON_RADIO_TURNED_OFF.equals(reason) ) {
1438 private void reconnectAfterFail(FailCause lastFailCauseCode,
1439 ApnContext apnContext, int retryOverride) {
1440 if (apnContext == null) {
1441 loge("reconnectAfterFail: apnContext == null, impossible");
1444 if ((apnContext.getState() == State.FAILED) &&
1445 (apnContext.getDataConnection() != null)) {
1446 if (!apnContext.getDataConnection().isRetryNeeded()) {
1447 if (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT)) {
1448 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
1451 if (mReregisterOnReconnectFailure) {
1452 // We've re-registerd once now just retry forever.
1453 apnContext.getDataConnection().retryForeverUsingLastTimeout();
1455 // Try to Re-register to the network.
1456 if (DBG) log("reconnectAfterFail: activate failed, Reregistering to network");
1457 mReregisterOnReconnectFailure = true;
1458 mPhone.getServiceStateTracker().reRegisterNetwork(null);
1459 apnContext.getDataConnection().resetRetryCount();
1464 // If retry needs to be backed off for specific case (determined by RIL/Modem)
1465 // use the specified timer instead of pre-configured retry pattern.
1466 int nextReconnectDelay = retryOverride;
1467 if (nextReconnectDelay < 0) {
1468 nextReconnectDelay = apnContext.getDataConnection().getRetryTimer();
1469 apnContext.getDataConnection().increaseRetryCount();
1471 startAlarmForReconnect(nextReconnectDelay, apnContext);
1473 if (!shouldPostNotification(lastFailCauseCode)) {
1475 log("reconnectAfterFail: NOT Posting GPRS Unavailable notification "
1476 + "-- likely transient error");
1479 notifyNoData(lastFailCauseCode, apnContext);
1484 private void startAlarmForReconnect(int delay, ApnContext apnContext) {
1487 log("Schedule alarm for reconnect: activate failed. Scheduling next attempt for "
1488 + (delay / 1000) + "s");
1491 DataConnectionAc dcac = apnContext.getDataConnectionAc();
1493 if ((dcac == null) || (dcac.dataConnection == null)) {
1494 // should not happen, but just in case.
1495 loge("null dcac or dc.");
1500 (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
1502 Intent intent = new Intent(INTENT_RECONNECT_ALARM + '.' +
1503 dcac.dataConnection.getDataConnectionId());
1504 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_REASON, apnContext.getReason());
1505 intent.putExtra(INTENT_RECONNECT_ALARM_EXTRA_TYPE,
1506 dcac.dataConnection.getDataConnectionId());
1508 PendingIntent alarmIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
1510 dcac.setReconnectIntentSync(alarmIntent);
1511 am.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
1512 SystemClock.elapsedRealtime() + delay, alarmIntent);
1516 private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode,
1517 ApnContext apnContext) {
1518 if (DBG) log( "notifyNoData: type=" + apnContext.getApnType());
1519 apnContext.setState(State.FAILED);
1520 if (lastFailCauseCode.isPermanentFail()
1521 && (!apnContext.getApnType().equals(Phone.APN_TYPE_DEFAULT))) {
1522 mPhone.notifyDataConnectionFailed(apnContext.getReason(), apnContext.getApnType());
1526 private void onRecordsLoaded() {
1527 if (DBG) log("onRecordsLoaded: createAllApnList");
1529 if (mRadioAvailable) {
1530 if (DBG) log("onRecordsLoaded: notifying data availability");
1531 notifyDataAvailability(null);
1533 setupDataOnReadyApns(Phone.REASON_SIM_LOADED);
1537 protected void onSetDependencyMet(String apnType, boolean met) {
1538 // don't allow users to tweak hipri to work around default dependency not met
1539 if (Phone.APN_TYPE_HIPRI.equals(apnType)) return;
1541 ApnContext apnContext = mApnContexts.get(apnType);
1542 if (apnContext == null) {
1543 loge("onSetDependencyMet: ApnContext not found in onSetDependencyMet(" +
1544 apnType + ", " + met + ")");
1547 applyNewState(apnContext, apnContext.isEnabled(), met);
1548 if (Phone.APN_TYPE_DEFAULT.equals(apnType)) {
1549 // tie actions on default to similar actions on HIPRI regarding dependencyMet
1550 apnContext = mApnContexts.get(Phone.APN_TYPE_HIPRI);
1551 if (apnContext != null) applyNewState(apnContext, apnContext.isEnabled(), met);
1555 private void applyNewState(ApnContext apnContext, boolean enabled, boolean met) {
1556 boolean cleanup = false;
1557 boolean trySetup = false;
1559 log("applyNewState(" + apnContext.getApnType() + ", " + enabled +
1560 "(" + apnContext.isEnabled() + "), " + met + "(" +
1561 apnContext.getDependencyMet() +"))");
1563 if (apnContext.isReady()) {
1564 if (enabled && met) return;
1566 apnContext.setReason(Phone.REASON_DATA_DISABLED);
1568 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_UNMET);
1572 if (enabled && met) {
1573 if (apnContext.isEnabled()) {
1574 apnContext.setReason(Phone.REASON_DATA_DEPENDENCY_MET);
1576 apnContext.setReason(Phone.REASON_DATA_ENABLED);
1578 if (apnContext.getState() == State.FAILED) {
1579 apnContext.setState(State.IDLE);
1584 apnContext.setEnabled(enabled);
1585 apnContext.setDependencyMet(met);
1586 if (cleanup) cleanUpConnection(true, apnContext);
1587 if (trySetup) trySetupData(apnContext);
1590 private DataConnection checkForConnectionForApnContext(ApnContext apnContext) {
1591 // Loop through all apnContexts looking for one with a conn that satisfies this apnType
1592 String apnType = apnContext.getApnType();
1593 for (ApnContext c : mApnContexts.values()) {
1594 DataConnection conn = c.getDataConnection();
1596 ApnSetting apnSetting = c.getApnSetting();
1597 if (apnSetting != null && apnSetting.canHandleType(apnType)) {
1599 log("checkForConnectionForApnContext: apnContext=" + apnContext +
1600 " found conn=" + conn);
1606 if (DBG) log("checkForConnectionForApnContext: apnContext=" + apnContext + " NO conn");
1611 protected void onEnableApn(int apnId, int enabled) {
1612 ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
1613 if (apnContext == null) {
1614 loge("onEnableApn(" + apnId + ", " + enabled + "): NO ApnContext");
1617 // TODO change our retry manager to use the appropriate numbers for the new APN
1618 if (DBG) log("onEnableApn: apnContext=" + apnContext + " call applyNewState");
1619 applyNewState(apnContext, enabled == ENABLED, apnContext.getDependencyMet());
1623 // TODO: We shouldnt need this.
1624 protected boolean onTrySetupData(String reason) {
1625 if (DBG) log("onTrySetupData: reason=" + reason);
1626 setupDataOnReadyApns(reason);
1630 protected boolean onTrySetupData(ApnContext apnContext) {
1631 if (DBG) log("onTrySetupData: apnContext=" + apnContext);
1632 return trySetupData(apnContext);
1636 protected void onRoamingOff() {
1637 if (DBG) log("onRoamingOff");
1638 setupDataOnReadyApns(Phone.REASON_ROAMING_OFF);
1642 protected void onRoamingOn() {
1643 if (getDataOnRoamingEnabled()) {
1644 if (DBG) log("onRoamingOn: setup data on roaming");
1645 setupDataOnReadyApns(Phone.REASON_ROAMING_ON);
1647 if (DBG) log("onRoamingOn: Tear down data connection on roaming.");
1648 cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
1653 protected void onRadioAvailable() {
1654 if (DBG) log("onRadioAvailable");
1655 mRadioAvailable = true;
1656 if (mPhone.getSimulatedRadioControl() != null) {
1657 // Assume data is connected on the simulator
1658 // FIXME this can be improved
1659 // setState(State.CONNECTED);
1660 notifyDataConnection(null);
1662 log("onRadioAvailable: We're on the simulator; assuming data is connected");
1665 if (mPhone.mIccRecords.getRecordsLoaded()) {
1666 notifyDataAvailability(null);
1669 if (getOverallState() != State.IDLE) {
1670 cleanUpConnection(true, null);
1675 protected void onRadioOffOrNotAvailable() {
1676 // Make sure our reconnect delay starts at the initial value
1677 // next time the radio comes on
1679 for (DataConnection dc : mDataConnections.values()) {
1680 dc.resetRetryCount();
1682 mReregisterOnReconnectFailure = false;
1683 mRadioAvailable = false;
1685 if (mPhone.getSimulatedRadioControl() != null) {
1686 // Assume data is connected on the simulator
1687 // FIXME this can be improved
1688 log("We're on the simulator; assuming radio off is meaningless");
1690 if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
1691 cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
1693 notifyDataAvailability(null);
1697 protected void onDataSetupComplete(AsyncResult ar) {
1699 ApnContext apnContext = null;
1701 if(ar.userObj instanceof ApnContext){
1702 apnContext = (ApnContext)ar.userObj;
1704 throw new RuntimeException("onDataSetupComplete: No apnContext");
1707 if (isDataSetupCompleteOk(ar)) {
1708 DataConnectionAc dcac = apnContext.getDataConnectionAc();
1710 throw new RuntimeException("onDataSetupCompete: No dcac");
1712 DataConnection dc = apnContext.getDataConnection();
1715 log(String.format("onDataSetupComplete: success apn=%s",
1716 apnContext.getWaitingApns().get(0).apn));
1718 ApnSetting apn = apnContext.getApnSetting();
1719 if (apn.proxy != null && apn.proxy.length() != 0) {
1721 ProxyProperties proxy = new ProxyProperties(apn.proxy,
1722 Integer.parseInt(apn.port), null);
1723 dcac.setLinkPropertiesHttpProxySync(proxy);
1724 } catch (NumberFormatException e) {
1725 loge("onDataSetupComplete: NumberFormatException making ProxyProperties (" +
1726 apn.port + "): " + e);
1730 // everything is setup
1731 if(TextUtils.equals(apnContext.getApnType(),Phone.APN_TYPE_DEFAULT)) {
1732 SystemProperties.set("gsm.defaultpdpcontext.active", "true");
1733 if (canSetPreferApn && mPreferredApn == null) {
1734 if (DBG) log("onDataSetupComplete: PREFERED APN is null");
1735 mPreferredApn = apnContext.getApnSetting();
1736 if (mPreferredApn != null) {
1737 setPreferredApn(mPreferredApn.id);
1741 SystemProperties.set("gsm.defaultpdpcontext.active", "false");
1743 notifyDefaultData(apnContext);
1746 DataConnection.FailCause cause;
1748 cause = (DataConnection.FailCause) (ar.result);
1751 apnString = apnContext.getWaitingApns().get(0).apn;
1752 } catch (Exception e) {
1753 apnString = "<unknown>";
1755 log(String.format("onDataSetupComplete: error apn=%s cause=%s", apnString, cause));
1757 if (cause.isEventLoggable()) {
1758 // Log this failure to the Event Logs.
1759 int cid = getCellLocationId();
1760 EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
1761 cause.ordinal(), cid, TelephonyManager.getDefault().getNetworkType());
1764 // Count permanent failures and remove the APN we just tried
1765 if (cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();
1767 apnContext.removeNextWaitingApn();
1769 log(String.format("onDataSetupComplete: WaitingApns.size=%d" +
1770 " WaitingApnsPermFailureCountDown=%d",
1771 apnContext.getWaitingApns().size(),
1772 apnContext.getWaitingApnsPermFailCount()));
1775 // See if there are more APN's to try
1776 if (apnContext.getWaitingApns().isEmpty()) {
1777 if (apnContext.getWaitingApnsPermFailCount() == 0) {
1779 log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
1781 apnContext.setState(State.FAILED);
1782 mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
1784 apnContext.setDataConnection(null);
1785 apnContext.setDataConnectionAc(null);
1787 log("onDataSetupComplete: permanent error apn=%s" + apnString );
1790 if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
1791 // check to see if retry should be overridden for this failure.
1792 int retryOverride = -1;
1793 if (ar.exception instanceof DataConnection.CallSetupException) {
1795 ((DataConnection.CallSetupException)ar.exception).getRetryOverride();
1797 startDelayedRetry(cause, apnContext, retryOverride);
1800 if (DBG) log("onDataSetupComplete: Try next APN");
1801 apnContext.setState(State.SCANNING);
1802 // Wait a bit before trying the next APN, so that
1803 // we're not tying up the RIL command channel
1804 startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
1810 * Called when EVENT_DISCONNECT_DONE is received.
1813 protected void onDisconnectDone(int connId, AsyncResult ar) {
1814 ApnContext apnContext = null;
1816 if(DBG) log("onDisconnectDone: EVENT_DISCONNECT_DONE connId=" + connId);
1817 if (ar.userObj instanceof ApnContext) {
1818 apnContext = (ApnContext) ar.userObj;
1820 loge("Invalid ar in onDisconnectDone");
1824 apnContext.setState(State.IDLE);
1826 mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());
1828 // if all data connection are gone, check whether Airplane mode request was
1830 if (!isConnected()) {
1831 if (mPhone.getServiceStateTracker().processPendingRadioPowerOffAfterDataOff()) {
1832 // Radio will be turned off. No need to retry data setup
1833 apnContext.setApnSetting(null);
1834 apnContext.setDataConnection(null);
1835 apnContext.setDataConnectionAc(null);
1840 // If APN is still enabled, try to bring it back up automatically
1841 if (apnContext.isReady() && retryAfterDisconnected(apnContext.getReason())) {
1842 SystemProperties.set("gsm.defaultpdpcontext.active", "false"); // TODO - what the heck? This shoudld go
1843 // Wait a bit before trying the next APN, so that
1844 // we're not tying up the RIL command channel.
1845 // This also helps in any external dependency to turn off the context.
1846 startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
1848 apnContext.setApnSetting(null);
1849 apnContext.setDataConnection(null);
1850 apnContext.setDataConnectionAc(null);
1854 protected void onPollPdp() {
1855 if (getOverallState() == State.CONNECTED) {
1856 // only poll when connected
1857 mPhone.mCM.getDataCallList(this.obtainMessage(EVENT_DATA_STATE_CHANGED));
1858 sendMessageDelayed(obtainMessage(EVENT_POLL_PDP), POLL_PDP_MILLIS);
1863 protected void onVoiceCallStarted() {
1864 if (DBG) log("onVoiceCallStarted");
1865 if (isConnected() && ! mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
1866 if (DBG) log("onVoiceCallStarted stop polling");
1868 notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
1873 protected void onVoiceCallEnded() {
1874 if (DBG) log("onVoiceCallEnded");
1875 if (isConnected()) {
1876 if (!mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
1878 notifyDataConnection(Phone.REASON_VOICE_CALL_ENDED);
1880 // clean slate after call end.
1884 // reset reconnect timer
1885 setupDataOnReadyApns(Phone.REASON_VOICE_CALL_ENDED);
1890 protected void onCleanUpConnection(boolean tearDown, int apnId, String reason) {
1891 if (DBG) log("onCleanUpConnection");
1892 ApnContext apnContext = mApnContexts.get(apnIdToType(apnId));
1893 if (apnContext != null) {
1894 apnContext.setReason(reason);
1895 cleanUpConnection(tearDown, apnContext);
1899 protected boolean isConnected() {
1900 for (ApnContext apnContext : mApnContexts.values()) {
1901 if (apnContext.getState() == State.CONNECTED) {
1909 protected void notifyDataConnection(String reason) {
1910 if (DBG) log("notifyDataConnection: reason=" + reason);
1911 for (ApnContext apnContext : mApnContexts.values()) {
1912 if (apnContext.isReady()) {
1913 if (DBG) log("notifyDataConnection: type:"+apnContext.getApnType());
1914 mPhone.notifyDataConnection(reason != null ? reason : apnContext.getReason(),
1915 apnContext.getApnType());
1918 notifyDataAvailability(reason);
1922 * Based on the sim operator numeric, create a list for all possible
1923 * Data Connections and setup the preferredApn.
1925 private void createAllApnList() {
1926 mAllApns = new ArrayList<ApnSetting>();
1927 String operator = mPhone.mIccRecords.getOperatorNumeric();
1928 if (operator != null) {
1929 String selection = "numeric = '" + operator + "'";
1930 if (DBG) log("createAllApnList: selection=" + selection);
1932 Cursor cursor = mPhone.getContext().getContentResolver().query(
1933 Telephony.Carriers.CONTENT_URI, null, selection, null, null);
1935 if (cursor != null) {
1936 if (cursor.getCount() > 0) {
1937 mAllApns = createApnList(cursor);
1943 if (mAllApns.isEmpty()) {
1944 if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
1945 mPreferredApn = null;
1946 // TODO: What is the right behaviour?
1947 //notifyNoData(GsmDataConnection.FailCause.MISSING_UNKNOWN_APN);
1949 mPreferredApn = getPreferredApn();
1950 if (mPreferredApn != null && !mPreferredApn.numeric.equals(operator)) {
1951 mPreferredApn = null;
1952 setPreferredApn(-1);
1954 if (DBG) log("createAllApnList: mPreferredApn=" + mPreferredApn);
1956 if (DBG) log("createAllApnList: X mAllApns=" + mAllApns);
1959 /** Return the id for a new data connection */
1960 private GsmDataConnection createDataConnection() {
1961 if (DBG) log("createDataConnection E");
1963 RetryManager rm = new RetryManager();
1964 int id = mUniqueIdGenerator.getAndIncrement();
1965 GsmDataConnection conn = GsmDataConnection.makeDataConnection(mPhone, id, rm);
1966 mDataConnections.put(id, conn);
1967 DataConnectionAc dcac = new DataConnectionAc(conn, LOG_TAG);
1968 int status = dcac.fullyConnectSync(mPhone.getContext(), this, conn.getHandler());
1969 if (status == AsyncChannel.STATUS_SUCCESSFUL) {
1970 mDataConnectionAsyncChannels.put(dcac.dataConnection.getDataConnectionId(), dcac);
1972 loge("createDataConnection: Could not connect to dcac.mDc=" + dcac.dataConnection +
1973 " status=" + status);
1976 // install reconnect intent filter for this data connection.
1977 IntentFilter filter = new IntentFilter();
1978 filter.addAction(INTENT_RECONNECT_ALARM + '.' + id);
1979 mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mPhone);
1981 if (DBG) log("createDataConnection() X id=" + id);
1985 private void configureRetry(DataConnection dc, String apnType) {
1986 if ((dc == null) || (apnType == null)) return;
1988 if (apnType.equals(Phone.APN_TYPE_DEFAULT)) {
1989 if (!dc.configureRetry(SystemProperties.get("ro.gsm.data_retry_config"))) {
1990 if (!dc.configureRetry(DEFAULT_DATA_RETRY_CONFIG)) {
1991 // Should never happen, log an error and default to a simple linear sequence.
1992 loge("configureRetry: Could not configure using " +
1993 "DEFAULT_DATA_RETRY_CONFIG=" + DEFAULT_DATA_RETRY_CONFIG);
1994 dc.configureRetry(20, 2000, 1000);
1998 if (!dc.configureRetry(SystemProperties.get("ro.gsm.2nd_data_retry_config"))) {
1999 if (!dc.configureRetry(SECONDARY_DATA_RETRY_CONFIG)) {
2000 // Should never happen, log an error and default to a simple sequence.
2001 loge("configureRetry: Could note configure using " +
2002 "SECONDARY_DATA_RETRY_CONFIG=" + SECONDARY_DATA_RETRY_CONFIG);
2003 dc.configureRetry("max_retries=3, 333, 333, 333");
2009 private void destroyDataConnections() {
2010 if(mDataConnections != null) {
2011 if (DBG) log("destroyDataConnections: clear mDataConnectionList");
2012 mDataConnections.clear();
2014 if (DBG) log("destroyDataConnections: mDataConnecitonList is empty, ignore");
2019 * Build a list of APNs to be used to create PDP's.
2021 * @param requestedApnType
2022 * @return waitingApns list to be used to create PDP
2023 * error when waitingApns.isEmpty()
2025 private ArrayList<ApnSetting> buildWaitingApns(String requestedApnType) {
2026 ArrayList<ApnSetting> apnList = new ArrayList<ApnSetting>();
2028 if (requestedApnType.equals(Phone.APN_TYPE_DUN)) {
2029 ApnSetting dun = fetchDunApn();
2032 if (DBG) log("buildWaitingApns: X added APN_TYPE_DUN apnList=" + apnList);
2037 String operator = mPhone.mIccRecords.getOperatorNumeric();
2038 if (requestedApnType.equals(Phone.APN_TYPE_DEFAULT)) {
2039 if (canSetPreferApn && mPreferredApn != null) {
2041 log("buildWaitingApns: Preferred APN:" + operator + ":"
2042 + mPreferredApn.numeric + ":" + mPreferredApn);
2044 if (mPreferredApn.numeric.equals(operator)) {
2045 apnList.add(mPreferredApn);
2046 if (DBG) log("buildWaitingApns: X added preferred apnList=" + apnList);
2049 if (DBG) log("buildWaitingApns: no preferred APN");
2050 setPreferredApn(-1);
2051 mPreferredApn = null;
2055 if (mAllApns != null) {
2056 for (ApnSetting apn : mAllApns) {
2057 if (apn.canHandleType(requestedApnType)) {
2062 loge("mAllApns is empty!");
2064 if (DBG) log("buildWaitingApns: X apnList=" + apnList);
2068 private String apnListToString (ArrayList<ApnSetting> apns) {
2069 StringBuilder result = new StringBuilder();
2070 for (int i = 0, size = apns.size(); i < size; i++) {
2072 .append(apns.get(i).toString())
2075 return result.toString();
2078 private void startDelayedRetry(GsmDataConnection.FailCause cause,
2079 ApnContext apnContext, int retryOverride) {
2080 notifyNoData(cause, apnContext);
2081 reconnectAfterFail(cause, apnContext, retryOverride);
2084 private void setPreferredApn(int pos) {
2085 if (!canSetPreferApn) {
2089 ContentResolver resolver = mPhone.getContext().getContentResolver();
2090 resolver.delete(PREFERAPN_URI, null, null);
2093 ContentValues values = new ContentValues();
2094 values.put(APN_ID, pos);
2095 resolver.insert(PREFERAPN_URI, values);
2099 private ApnSetting getPreferredApn() {
2100 if (mAllApns.isEmpty()) {
2104 Cursor cursor = mPhone.getContext().getContentResolver().query(
2105 PREFERAPN_URI, new String[] { "_id", "name", "apn" },
2106 null, null, Telephony.Carriers.DEFAULT_SORT_ORDER);
2108 if (cursor != null) {
2109 canSetPreferApn = true;
2111 canSetPreferApn = false;
2114 if (canSetPreferApn && cursor.getCount() > 0) {
2116 cursor.moveToFirst();
2117 pos = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID));
2118 for(ApnSetting p:mAllApns) {
2119 if (p.id == pos && p.canHandleType(mRequestedApnType)) {
2126 if (cursor != null) {
2134 public void handleMessage (Message msg) {
2135 if (DBG) log("handleMessage msg=" + msg);
2137 if (!mPhone.mIsTheCurrentActivePhone || mIsDisposed) {
2138 loge("handleMessage: Ignore GSM msgs since GSM phone is inactive");
2143 case EVENT_RECORDS_LOADED:
2147 case EVENT_DATA_CONNECTION_DETACHED:
2148 onDataConnectionDetached();
2151 case EVENT_DATA_CONNECTION_ATTACHED:
2152 onDataConnectionAttached();
2155 case EVENT_DATA_STATE_CHANGED:
2156 onDataStateChanged((AsyncResult) msg.obj);
2159 case EVENT_POLL_PDP:
2163 case EVENT_START_NETSTAT_POLL:
2167 case EVENT_START_RECOVERY:
2171 case EVENT_APN_CHANGED:
2175 case EVENT_PS_RESTRICT_ENABLED:
2177 * We don't need to explicitly to tear down the PDP context
2178 * when PS restricted is enabled. The base band will deactive
2179 * PDP context and notify us with PDP_CONTEXT_CHANGED.
2180 * But we should stop the network polling and prevent reset PDP.
2182 if (DBG) log("EVENT_PS_RESTRICT_ENABLED " + mIsPsRestricted);
2184 mIsPsRestricted = true;
2187 case EVENT_PS_RESTRICT_DISABLED:
2189 * When PS restrict is removed, we need setup PDP connection if
2190 * PDP connection is down.
2192 if (DBG) log("EVENT_PS_RESTRICT_DISABLED " + mIsPsRestricted);
2193 mIsPsRestricted = false;
2194 if (isConnected()) {
2197 // TODO: Should all PDN states be checked to fail?
2198 if (mState == State.FAILED) {
2199 cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
2200 resetAllRetryCounts();
2201 mReregisterOnReconnectFailure = false;
2203 trySetupData(Phone.REASON_PS_RESTRICT_ENABLED, Phone.APN_TYPE_DEFAULT);
2206 case EVENT_TRY_SETUP_DATA:
2207 if (msg.obj instanceof ApnContext) {
2208 onTrySetupData((ApnContext)msg.obj);
2209 } else if (msg.obj instanceof String) {
2210 onTrySetupData((String)msg.obj);
2212 loge("EVENT_TRY_SETUP request w/o apnContext or String");
2216 case EVENT_CLEAN_UP_CONNECTION:
2217 boolean tearDown = (msg.arg1 == 0) ? false : true;
2218 if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
2219 if (msg.obj instanceof ApnContext) {
2220 cleanUpConnection(tearDown, (ApnContext)msg.obj);
2222 loge("EVENT_CLEAN_UP_CONNECTION request w/o apn context");
2226 // handle the message in the super class DataConnectionTracker
2227 super.handleMessage(msg);
2232 protected int getApnProfileID(String apnType) {
2233 if (TextUtils.equals(apnType, Phone.APN_TYPE_IMS)) {
2234 return RILConstants.DATA_PROFILE_IMS;
2235 } else if (TextUtils.equals(apnType, Phone.APN_TYPE_FOTA)) {
2236 return RILConstants.DATA_PROFILE_FOTA;
2237 } else if (TextUtils.equals(apnType, Phone.APN_TYPE_CBS)) {
2238 return RILConstants.DATA_PROFILE_CBS;
2240 return RILConstants.DATA_PROFILE_DEFAULT;
2244 private int getCellLocationId() {
2246 CellLocation loc = mPhone.getCellLocation();
2249 if (loc instanceof GsmCellLocation) {
2250 cid = ((GsmCellLocation)loc).getCid();
2251 } else if (loc instanceof CdmaCellLocation) {
2252 cid = ((CdmaCellLocation)loc).getBaseStationId();
2259 public boolean isAnyActiveDataConnections() {
2260 return isConnected();
2264 protected void log(String s) {
2265 Log.d(LOG_TAG, "[GsmDCT] "+ s);
2269 protected void loge(String s) {
2270 Log.e(LOG_TAG, "[GsmDCT] " + s);