diff options
Diffstat (limited to 'telephony')
9 files changed, 249 insertions, 83 deletions
diff --git a/telephony/java/com/android/internal/telephony/ApnContext.java b/telephony/java/com/android/internal/telephony/ApnContext.java index 496c43c..5ec00e8 100644 --- a/telephony/java/com/android/internal/telephony/ApnContext.java +++ b/telephony/java/com/android/internal/telephony/ApnContext.java @@ -89,6 +89,11 @@ public class ApnContext { } public synchronized void setDataConnectionAc(DataConnectionAc dcac) { + if (dcac != null) { + dcac.addApnContext(this); + } else { + if (mDataConnectionAc != null) mDataConnectionAc.removeApnContext(this); + } mDataConnectionAc = dcac; } diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 76b8b65..ab93e2a 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -526,8 +526,20 @@ public class CallerInfo { + countryIso); } + // Temp workaround: The current libphonenumber library requires + // the countryIso to be uppercase (e.g. "US") but the + // detector.detectCountry().getCountryIso() call currently returns + // "us". Passing "us" to util.parse() will just result in a + // NumberParseException. + // So force the countryIso to uppercase for now. + // TODO: remove this once getCountryIso() is fixed to always + // return uppercase. + countryIso = countryIso.toUpperCase(); + PhoneNumber pn = null; try { + if (VDBG) Log.v(TAG, "parsing '" + number + + "' for countryIso '" + countryIso + "'..."); pn = util.parse(number, countryIso); if (VDBG) Log.v(TAG, "- parsed number: " + pn); } catch (NumberParseException e) { diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 1bd9b0c..2e8a742 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -55,7 +55,7 @@ public class CallerInfoAsyncQuery { // PhoneNumberOfflineGeocoder to look up a "geo description"? // (TODO: This could become a flag in config.xml if it ever needs to be // configured on a per-product basis.) - private static final boolean ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION = false; + private static final boolean ENABLE_UNKNOWN_NUMBER_GEO_DESCRIPTION = true; /** * Interface for a CallerInfoAsyncQueryHandler result return. diff --git a/telephony/java/com/android/internal/telephony/DataCallState.java b/telephony/java/com/android/internal/telephony/DataCallState.java index f5651e0..fba3184 100644 --- a/telephony/java/com/android/internal/telephony/DataCallState.java +++ b/telephony/java/com/android/internal/telephony/DataCallState.java @@ -47,6 +47,7 @@ public class DataCallState { public String [] addresses = new String[0]; public String [] dnses = new String[0]; public String[] gateways = new String[0]; + public int suggestedRetryTime = -1; /** * Class returned by onSetupConnectionCompleted. @@ -77,6 +78,7 @@ public class DataCallState { sb.append("DataCallState: {") .append("version=").append(version) .append(" status=").append(status) + .append(" retry=").append(suggestedRetryTime) .append(" cid=").append(cid) .append(" active=").append(active) .append(" type=").append(type) diff --git a/telephony/java/com/android/internal/telephony/DataConnection.java b/telephony/java/com/android/internal/telephony/DataConnection.java index 5c030fd..cb8b0e5 100644 --- a/telephony/java/com/android/internal/telephony/DataConnection.java +++ b/telephony/java/com/android/internal/telephony/DataConnection.java @@ -182,6 +182,18 @@ public abstract class DataConnection extends StateMachine { } } + public static class CallSetupException extends Exception { + private int mRetryOverride = -1; + + CallSetupException (int retryOverride) { + mRetryOverride = retryOverride; + } + + public int getRetryOverride() { + return mRetryOverride; + } + } + // ***** Event codes for driving the state machine protected static final int BASE = Protocol.BASE_DATA_CONNECTION; protected static final int EVENT_CONNECT = BASE + 0; @@ -205,6 +217,7 @@ public abstract class DataConnection extends StateMachine { protected long createTime; protected long lastFailTime; protected FailCause lastFailCause; + protected int mRetryOverride = -1; protected static final String NULL_IP = "0.0.0.0"; private int mRefCount; Object userData; @@ -288,7 +301,8 @@ public abstract class DataConnection extends StateMachine { } else { lastFailCause = cause; lastFailTime = timeStamp; - AsyncResult.forMessage(connectionCompletedMsg, cause, new Exception()); + AsyncResult.forMessage(connectionCompletedMsg, cause, + new CallSetupException(mRetryOverride)); } if (DBG) log("notifyConnectionCompleted at " + timeStamp + " cause=" + cause); @@ -430,6 +444,7 @@ public abstract class DataConnection extends StateMachine { createTime = -1; lastFailTime = -1; lastFailCause = FailCause.NONE; + mRetryOverride = -1; mRefCount = 0; mLinkProperties = new LinkProperties(); @@ -482,6 +497,15 @@ public abstract class DataConnection extends StateMachine { return result; } + private int getSuggestedRetryTime(AsyncResult ar) { + int retry = -1; + if (ar.exception == null) { + DataCallState response = (DataCallState) ar.result; + retry = response.suggestedRetryTime; + } + return retry; + } + private DataCallState.SetupResult setLinkProperties(DataCallState response, LinkProperties lp) { // Check if system property dns usable @@ -685,10 +709,12 @@ public abstract class DataConnection extends StateMachine { private FailCause mFailCause = null; private DisconnectParams mDisconnectParams = null; - public void setEnterNotificationParams(ConnectionParams cp, FailCause cause) { + public void setEnterNotificationParams(ConnectionParams cp, FailCause cause, + int retryOverride) { if (VDBG) log("DcInactiveState: setEnterNoticationParams cp,cause"); mConnectionParams = cp; mFailCause = cause; + mRetryOverride = retryOverride; } public void setEnterNotificationParams(DisconnectParams dp) { @@ -808,7 +834,7 @@ public abstract class DataConnection extends StateMachine { // Vendor ril rejected the command and didn't connect. // Transition to inactive but send notifications after // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(cp, result.mFailCause); + mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1); transitionTo(mInactiveState); break; case ERR_UnacceptableParameter: @@ -823,7 +849,8 @@ public abstract class DataConnection extends StateMachine { break; case ERR_RilError: // Request failed and mFailCause has the reason - mInactiveState.setEnterNotificationParams(cp, result.mFailCause); + mInactiveState.setEnterNotificationParams(cp, result.mFailCause, + getSuggestedRetryTime(ar)); transitionTo(mInactiveState); break; case ERR_Stale: @@ -848,8 +875,8 @@ public abstract class DataConnection extends StateMachine { } // Transition to inactive but send notifications after // we've entered the mInactive state. - mInactiveState.setEnterNotificationParams(cp, cause); - transitionTo(mInactiveState); + mInactiveState.setEnterNotificationParams(cp, cause, -1); + transitionTo(mInactiveState); } else { if (DBG) { log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag=" @@ -1016,7 +1043,7 @@ public abstract class DataConnection extends StateMachine { // Transition to inactive but send notifications after // we've entered the mInactive state. mInactiveState.setEnterNotificationParams(cp, - FailCause.UNACCEPTABLE_NETWORK_PARAMETER); + FailCause.UNACCEPTABLE_NETWORK_PARAMETER, -1); transitionTo(mInactiveState); } else { if (DBG) { diff --git a/telephony/java/com/android/internal/telephony/DataConnectionAc.java b/telephony/java/com/android/internal/telephony/DataConnectionAc.java index 62b90ae..e23f1cc 100644 --- a/telephony/java/com/android/internal/telephony/DataConnectionAc.java +++ b/telephony/java/com/android/internal/telephony/DataConnectionAc.java @@ -24,12 +24,18 @@ import android.net.LinkProperties; import android.net.ProxyProperties; import android.os.Message; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + /** * AsyncChannel to a DataConnection */ public class DataConnectionAc extends AsyncChannel { private static final boolean DBG = false; private String mLogTag; + private List<ApnContext> mApnList = null; public DataConnection dataConnection; @@ -85,6 +91,7 @@ public class DataConnectionAc extends AsyncChannel { public DataConnectionAc(DataConnection dc, String logTag) { dataConnection = dc; mLogTag = logTag; + mApnList = Collections.synchronizedList(new ArrayList<ApnContext>()); } /** @@ -371,6 +378,35 @@ public class DataConnectionAc extends AsyncChannel { } } + /** + * Add ApnContext association. + * + * @param ApnContext to associate + */ + public void addApnContext(ApnContext apnContext) { + if (!mApnList.contains(apnContext)) { + mApnList.add(apnContext); + } + } + + /** + * Remove ApnContext associateion. + * + * @param ApnContext to dissociate + */ + public void removeApnContext(ApnContext apnContext) { + mApnList.remove(apnContext); + } + + /** + * Retrieve collection of ApnContext currently associated with the DataConnectionAc. + * + * @return Collection of ApnContext + */ + public Collection<ApnContext> getApnList() { + return mApnList; + } + private void log(String s) { android.util.Log.d(mLogTag, "DataConnectionAc " + s); } diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java index 76f1ab7..c6ed405 100644 --- a/telephony/java/com/android/internal/telephony/RIL.java +++ b/telephony/java/com/android/internal/telephony/RIL.java @@ -3009,6 +3009,7 @@ public final class RIL extends BaseCommands implements CommandsInterface { } } else { dataCall.status = p.readInt(); + dataCall.suggestedRetryTime = p.readInt(); dataCall.cid = p.readInt(); dataCall.active = p.readInt(); dataCall.type = p.readString(); diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java index 6a95b67..a31b704 100644 --- a/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java +++ b/telephony/java/com/android/internal/telephony/cdma/CDMALTEPhone.java @@ -129,6 +129,12 @@ public class CDMALTEPhone extends CDMAPhone { super.setSystemLocale(language, country, false); } + // return IMSI from USIM as subscriber ID. + @Override + public String getSubscriberId() { + return mIccRecords.getIMSI(); + } + @Override protected void log(String s) { if (DBG) diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 19c06f6..1ac012f 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -68,7 +68,9 @@ import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; +import java.util.List; import java.util.Map; import java.util.HashMap; @@ -844,9 +846,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } + private boolean dataConnectionNotInUse(DataConnectionAc dcac) { + for (ApnContext apnContext : mApnContexts.values()) { + if (apnContext.getDataConnectionAc() == dcac) return false; + } + return true; + } + private GsmDataConnection findFreeDataConnection() { for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { - if (dcac.isInactiveSync()) { + if (dcac.isInactiveSync() && dataConnectionNotInUse(dcac)) { log("findFreeDataConnection: found free GsmDataConnection"); return (GsmDataConnection) dcac.dataConnection; } @@ -926,7 +935,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (refCount == 0) { configureRetry(dc, apnContext.getApnType()); } - apnContext.setDataConnectionAc(mDataConnectionAsyncChannels.get(dc.getDataConnectionId())); + apnContext.setDataConnectionAc(dcac); apnContext.setApnSetting(apn); apnContext.setDataConnection(dc); } @@ -969,6 +978,49 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } /** + * @param cid Connection id provided from RIL. + * @return DataConnectionAc associated with specified cid. + */ + private DataConnectionAc findDataConnectionAcByCid(int cid) { + for (DataConnectionAc dcac : mDataConnectionAsyncChannels.values()) { + if (dcac.getCidSync() == cid) { + return dcac; + } + } + return null; + } + + /** + * @param dcacs Collection of DataConnectionAc reported from RIL. + * @return List of ApnContext whihc is connected, but does not present in + * data connection list reported from RIL. + */ + private List<ApnContext> findApnContextToClean(Collection<DataConnectionAc> dcacs) { + if (dcacs == null) return null; + + ArrayList<ApnContext> list = new ArrayList<ApnContext>(); + for (ApnContext apnContext : mApnContexts.values()) { + if (apnContext.getState() == State.CONNECTED) { + boolean found = false; + for (DataConnectionAc dcac : dcacs) { + if (dcac == apnContext.getDataConnectionAc()) { + // ApnContext holds the ref to dcac present in data call list. + found = true; + break; + } + } + if (!found) { + // ApnContext does not have dcan reorted in data call list. + if (DBG) log("onDataStateChanged(ar): Connected apn not found in the list (" + + apnContext.toString() + ")"); + list.add(apnContext); + } + } + } + return list; + } + + /** * @param ar is the result of RIL_REQUEST_DATA_CALL_LIST * or RIL_UNSOL_DATA_CALL_LIST_CHANGED */ @@ -985,91 +1037,103 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (DBG) log("onDataStateChanged(ar): exception; likely radio not available, ignore"); return; } + if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); - // Create a hash map to store the dataCallState of each call id + // Create a hash map to store the dataCallState of each DataConnectionAc // TODO: Depends on how frequent the DATA_CALL_LIST got updated, // may cache response to reduce comparison. - HashMap<Integer, DataCallState> response; - response = new HashMap<Integer, DataCallState>(); - if (DBG) log("onDataStateChanged(ar): DataCallState size=" + dataCallStates.size()); - for (DataCallState dc : dataCallStates) { - response.put(dc.cid, dc); - if (DBG) log("onDataStateChanged(ar): " + dc.cid + ": " + dc.toString()); + HashMap<DataCallState, DataConnectionAc> response; + response = new HashMap<DataCallState, DataConnectionAc>(); + for (DataCallState dataCallState : dataCallStates) { + DataConnectionAc dcac = findDataConnectionAcByCid(dataCallState.cid); + + if (dcac != null) response.put(dataCallState, dcac); } - // For each connected apn, check if there is a matched active - // data call state, which has the same link properties. - if (DBG) log(" ApnContext size=" + mApnContexts.values().size()); - for (ApnContext apnContext : mApnContexts.values()) { - if (DBG){ - log("onDataStateChanged(ar): " + apnContext.toString()); - if (apnContext.getDataConnection() != null) { - log("onDataStateChanged(ar): " + apnContext.getDataConnection().toString()); + // step1: Find a list of "connected" APN which does not have reference to + // calls listed in the Data Call List. + List<ApnContext> apnsToClear = findApnContextToClean(response.values()); + + // step2: Check status of each calls in Data Call List. + // Collect list of ApnContext associated with the data call if the link + // has to be cleared. + for (DataCallState newState : dataCallStates) { + DataConnectionAc dcac = response.get(newState); + + // no associated DataConnection found. Ignore. + if (dcac == null) continue; + + Collection<ApnContext> apns = dcac.getApnList(); + + // filter out ApnContext with "Connected" state. + ArrayList<ApnContext> connectedApns = new ArrayList<ApnContext>(); + for (ApnContext apnContext : apns) { + if ((apnContext != null) && + (apnContext.getState() == State.CONNECTED)) { + connectedApns.add(apnContext); } } - DataConnectionAc dcac = apnContext.getDataConnectionAc(); - if (dcac == null) { + + // No "Connected" ApnContext associated with this CID. Ignore. + if (connectedApns.isEmpty()) { continue; } - int connectionId = dcac.getCidSync(); - if (apnContext.getState() == State.CONNECTED) { - // The way things are supposed to work, the PDP list - // should not contain the CID after it disconnects. - // However, the way things really work, sometimes the PDP - // context is still listed with active = false, which - // makes it hard to distinguish an activating context from - // an activated-and-then de-activated one. - if (response.containsKey(connectionId)) { - DataCallState newState = response.get(connectionId); - if (DBG) log("onDataStateChanged(ar): Found ConnId=" + connectionId + if (DBG) log("onDataStateChanged(ar): Found ConnId=" + newState.cid + " newState=" + newState.toString()); - if (newState.active != 0) { - boolean resetConnection; - switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) { - case NONE: - if (DBG) log("onDataStateChanged(ar): Found but no change, skip"); - resetConnection = false; - break; - case CHANGED: - if (DBG) log("onDataStateChanged(ar): Found and changed, notify"); - mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED, - apnContext.getApnType()); - // Temporary hack, at this time a transition from CDMA -> Global - // fails so we'll hope for the best and not reset the connection. - // @see bug/4455071 - if (SystemProperties.getBoolean("telephony.ignore-state-changes", - true)) { - log("onDataStateChanged(ar): STOPSHIP don't reset, continue"); - resetConnection = false; - } else { - // Things changed so reset connection, when hack is removed - // this is the normal path. - log("onDataStateChanged(ar): changed so resetting connection"); - resetConnection = true; - } - break; - case RESET: - default: - if (DBG) log("onDataStateChanged(ar): an error, reset connection"); - resetConnection = true; - break; - } - if (resetConnection == false) continue; + if (newState.active != 0) { + boolean resetConnection; + switch (dcac.updateLinkPropertiesDataCallStateSync(newState)) { + case NONE: + if (DBG) log("onDataStateChanged(ar): Found but no change, skip"); + resetConnection = false; + break; + case CHANGED: + for (ApnContext apnContext : connectedApns) { + if (DBG) log("onDataStateChanged(ar): Found and changed, notify (" + + apnContext.toString() + ")"); + mPhone.notifyDataConnection(Phone.REASON_LINK_PROPERTIES_CHANGED, + apnContext.getApnType()); } + // Temporary hack, at this time a transition from CDMA -> Global + // fails so we'll hope for the best and not reset the connection. + // @see bug/4455071 + if (SystemProperties.getBoolean("telephony.ignore-state-changes", + true)) { + log("onDataStateChanged(ar): STOPSHIP don't reset, continue"); + resetConnection = false; + } else { + // Things changed so reset connection, when hack is removed + // this is the normal path. + log("onDataStateChanged(ar): changed so resetting connection"); + resetConnection = true; + } + break; + case RESET: + default: + if (DBG) log("onDataStateChanged(ar): an error, reset connection"); + resetConnection = true; + break; } + if (resetConnection == false) continue; + } - if (DBG) log("onDataStateChanged(ar): reset connection."); + if (DBG) log("onDataStateChanged(ar): reset connection."); - // Add an event log when the network drops PDP - int cid = getCellLocationId(); - EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid, - TelephonyManager.getDefault().getNetworkType()); + apnsToClear.addAll(connectedApns); + } - cleanUpConnection(true, apnContext); - } + // step3: Clear apn connection if applicable. + if (!apnsToClear.isEmpty()) { + // Add an event log when the network drops PDP + int cid = getCellLocationId(); + EventLog.writeEvent(EventLogTags.PDP_NETWORK_DROP, cid, + TelephonyManager.getDefault().getNetworkType()); } + for (ApnContext apnContext : apnsToClear) { + cleanUpConnection(true, apnContext); + } if (DBG) log("onDataStateChanged(ar): X"); } @@ -1332,7 +1396,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return retry; } - private void reconnectAfterFail(FailCause lastFailCauseCode, ApnContext apnContext) { + private void reconnectAfterFail(FailCause lastFailCauseCode, + ApnContext apnContext, int retryOverride) { if (apnContext == null) { loge("reconnectAfterFail: apnContext == null, impossible"); return; @@ -1357,9 +1422,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } - int nextReconnectDelay = apnContext.getDataConnection().getRetryTimer(); + // If retry needs to be backed off for specific case (determined by RIL/Modem) + // use the specified timer instead of pre-configured retry pattern. + int nextReconnectDelay = retryOverride; + if (nextReconnectDelay < 0) { + nextReconnectDelay = apnContext.getDataConnection().getRetryTimer(); + apnContext.getDataConnection().increaseRetryCount(); + } startAlarmForReconnect(nextReconnectDelay, apnContext); - apnContext.getDataConnection().increaseRetryCount(); if (!shouldPostNotification(lastFailCauseCode)) { if (DBG) { @@ -1664,7 +1734,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } } else { if (DBG) log("onDataSetupComplete: Not all permanent failures, retry"); - startDelayedRetry(cause, apnContext); + // check to see if retry should be overridden for this failure. + int retryOverride = -1; + if (ar.exception instanceof DataConnection.CallSetupException) { + retryOverride = + ((DataConnection.CallSetupException)ar.exception).getRetryOverride(); + } + startDelayedRetry(cause, apnContext, retryOverride); } } else { if (DBG) log("onDataSetupComplete: Try next APN"); @@ -1936,9 +2012,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result.toString(); } - private void startDelayedRetry(GsmDataConnection.FailCause cause, ApnContext apnContext) { + private void startDelayedRetry(GsmDataConnection.FailCause cause, + ApnContext apnContext, int retryOverride) { notifyNoData(cause, apnContext); - reconnectAfterFail(cause, apnContext); + reconnectAfterFail(cause, apnContext, retryOverride); } private void setPreferredApn(int pos) { |