Merge change Ia834022d

* changes:
  Convert DataConnection to an HSM and rename PdpConnection to GsmDataConnection.
This commit is contained in:
Android (Google) Code Review
2009-12-22 15:43:15 -08:00
13 changed files with 915 additions and 945 deletions

View File

@@ -16,43 +16,137 @@
package com.android.internal.telephony;
import com.android.internal.telephony.gsm.ApnSetting;
import com.android.internal.util.HierarchicalState;
import com.android.internal.util.HierarchicalStateMachine;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.os.SystemProperties;
import android.util.EventLog;
/**
* {@hide}
*
* DataConnection HierarchicalStateMachine.
*
* This is an abstract base class for representing a single data connection.
* Instances of this class such as <code>CdmaDataConnection</code> and
* <code>GsmDataConnection</code>, * represent a connection via the cellular network.
* There may be multiple data connections and all of them are managed by the
* <code>DataConnectionTracker</code>.
*
* Instances are asynchronous state machines and have two primary entry points
* <code>connect()</code> and <code>disconnect</code>. The message a parameter will be returned
* hen the operation completes. The <code>msg.obj</code> will contain an AsyncResult
* object and <code>AsyncResult.userObj</code> is the original <code>msg.obj</code>. if successful
* with the <code>AsyncResult.result == null</code> and <code>AsyncResult.exception == null</code>.
* If an error <code>AsyncResult.result = FailCause</code> and
* <code>AsyncResult.exception = new Exception()</code>.
*
* The other public methods are provided for debugging.
*
* Below is the state machine description for this class.
*
* DataConnection {
* + mDefaultState {
* EVENT_RESET { clearSettings, >mInactiveState }.
* EVENT_CONNECT { notifyConnectCompleted(FailCause.UNKNOWN) }.
* EVENT_DISCONNECT { notifyDisconnectCompleted }.
*
* // Ignored messages
* EVENT_SETUP_DATA_CONNECTION_DONE,
* EVENT_GET_LAST_FAIL_DONE,
* EVENT_DEACTIVATE_DONE.
* }
* ++ # mInactiveState {
* EVENT_RESET.
* EVENT_CONNECT {startConnecting, >mActivatingState }.
* }
* ++ mActivatingState {
* EVENT_DISCONNECT { %EVENT_DISCONNECT }.
* EVENT_SETUP_DATA_CONNECTION_DONE {
* if (SUCCESS) { notifyConnectCompleted(FailCause.NONE), >mActiveState }.
* if (ERR_BadCommand) {
* notifyConnectCompleted(FailCause.UNKNOWN), >mInactiveState }.
* if (ERR_BadDns) { tearDownData($DEACTIVATE_DONE), >mDisconnectingBadDnsState }.
* if (ERR_Other) { getLastDataCallFailCause($EVENT_GET_LAST_FAIL_DONE) }.
* if (ERR_Stale) {}.
* }
* EVENT_GET_LAST_FAIL_DONE { notifyConnectCompleted(result), >mInactive }.
* }
* ++ mActiveState {
* EVENT_DISCONNECT { tearDownData($EVENT_DEACTIVATE_DONE), >mDisconnecting }.
* }
* ++ mDisconnectingState {
* EVENT_DEACTIVATE_DONE { notifyDisconnectCompleted, >mInactiveState }.
* }
* ++ mDisconnectingBadDnsState {
* EVENT_DEACTIVATE_DONE { notifyConnectComplete(FailCause.UNKNOWN), >mInactiveState }.
* }
* }
*/
public abstract class DataConnection extends Handler {
public abstract class DataConnection extends HierarchicalStateMachine {
protected static final boolean DBG = true;
// the inherited class
protected static Object mCountLock = new Object();
protected static int mCount;
public enum State {
ACTIVE, /* has active data connection */
ACTIVATING, /* during connecting process */
INACTIVE; /* has empty data connection */
/**
* Class returned by onSetupConnectionCompleted.
*/
protected enum SetupResult {
ERR_BadCommand,
ERR_BadDns,
ERR_Other,
ERR_Stale,
SUCCESS;
public FailCause mFailCause;
@Override
public String toString() {
switch (this) {
case ACTIVE:
return "active";
case ACTIVATING:
return "setting up";
default:
return "inactive";
case ERR_BadCommand: return "Bad Command";
case ERR_BadDns: return "Bad DNS";
case ERR_Other: return "Other error";
case ERR_Stale: return "Stale command";
case SUCCESS: return "SUCCESS";
default: return "unknown";
}
}
public boolean isActive() {
return this == ACTIVE;
}
public boolean isInactive() {
return this == INACTIVE;
}
}
/**
* Used internally for saving connecting parameters.
*/
protected static class ConnectionParams {
public ConnectionParams(ApnSetting apn, Message onCompletedMsg) {
this.apn = apn;
this.onCompletedMsg = onCompletedMsg;
}
public int tag;
public ApnSetting apn;
public Message onCompletedMsg;
}
/**
* Used internally for saving disconnecting parameters.
*/
protected static class DisconnectParams {
public DisconnectParams(Message onCompletedMsg) {
this.onCompletedMsg = onCompletedMsg;
}
public int tag;
public Message onCompletedMsg;
}
/**
* Returned as the reason for a connection failure.
*/
public enum FailCause {
NONE,
OPERATOR_BARRED,
@@ -71,8 +165,7 @@ public abstract class DataConnection extends Handler {
GPRS_REGISTRATION_FAIL,
UNKNOWN,
RADIO_NOT_AVAILABLE,
RADIO_ERROR_RETRY;
RADIO_NOT_AVAILABLE;
public boolean isPermanentFail() {
return (this == OPERATOR_BARRED) || (this == MISSING_UKNOWN_APN) ||
@@ -128,117 +221,139 @@ public abstract class DataConnection extends Handler {
return "Data Network Registration Failure";
case RADIO_NOT_AVAILABLE:
return "Radio Not Available";
case RADIO_ERROR_RETRY:
return "Transient Radio Rrror";
default:
return "Unknown Data Error";
}
}
}
// ***** Event codes
protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 1;
protected static final int EVENT_GET_LAST_FAIL_DONE = 2;
protected static final int EVENT_LINK_STATE_CHANGED = 3;
protected static final int EVENT_DEACTIVATE_DONE = 4;
protected static final int EVENT_FORCE_RETRY = 5;
// ***** Event codes for driving the state machine
protected static final int EVENT_RESET = 1;
protected static final int EVENT_CONNECT = 2;
protected static final int EVENT_SETUP_DATA_CONNECTION_DONE = 3;
protected static final int EVENT_GET_LAST_FAIL_DONE = 4;
protected static final int EVENT_DEACTIVATE_DONE = 5;
protected static final int EVENT_DISCONNECT = 6;
//***** Tag IDs for EventLog
protected static final int EVENT_LOG_BAD_DNS_ADDRESS = 50100;
//***** Member Variables
protected int mTag;
protected PhoneBase phone;
protected Message onConnectCompleted;
protected Message onDisconnect;
protected int cid;
protected String interfaceName;
protected String ipAddress;
protected String gatewayAddress;
protected String[] dnsServers;
protected State state;
protected long createTime;
protected long lastFailTime;
protected FailCause lastFailCause;
protected static final String NULL_IP = "0.0.0.0";
Object userData;
// receivedDisconnectReq is set when disconnect during activation
protected boolean receivedDisconnectReq;
//***** Abstract methods
public abstract String toString();
/* Instance Methods */
protected abstract void onSetupConnectionCompleted(AsyncResult ar);
protected abstract void onDeactivated(AsyncResult ar);
protected abstract void disconnect(Message msg);
protected abstract void notifyFail(FailCause cause, Message onCompleted);
protected abstract void notifyDisconnect(Message msg);
protected abstract void onLinkStateChanged(DataLink.LinkState linkState);
protected abstract void onConnect(ConnectionParams cp);
protected abstract FailCause getFailCauseFromRequest(int rilCause);
public abstract String toString();
protected abstract boolean isDnsOk(String[] domainNameServers);
protected abstract void log(String s);
//***** Constructor
protected DataConnection(PhoneBase phone) {
super();
protected DataConnection(PhoneBase phone, String name) {
super(name);
if (DBG) log("DataConnection constructor E");
this.phone = phone;
onConnectCompleted = null;
onDisconnect = null;
this.cid = -1;
receivedDisconnectReq = false;
this.dnsServers = new String[2];
clearSettings();
setDbg(true);
addState(mDefaultState);
addState(mInactiveState, mDefaultState);
addState(mActivatingState, mDefaultState);
addState(mActiveState, mDefaultState);
addState(mDisconnectingState, mDefaultState);
addState(mDisconnectingBadDnsState, mDefaultState);
setInitialState(mInactiveState);
if (DBG) log("DataConnection constructor X");
}
/**
* TearDown the data connection.
*
* @param o will be returned in AsyncResult.userObj
* and is either a DisconnectParams or ConnectionParams.
*/
private void tearDownData(Object o) {
if (phone.mCM.getRadioState().isOn()) {
if (DBG) log("tearDownData radio is on, call deactivateDataCall");
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, o));
} else {
if (DBG) log("tearDownData radio is off sendMessage EVENT_DEACTIVATE_DONE immediately");
sendMessage(obtainMessage(EVENT_DEACTIVATE_DONE, o));
}
}
/**
* Send the connectionCompletedMsg.
*
* @param cp is the ConnectionParams
* @param cause
*/
private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {
Message connectionCompletedMsg = cp.onCompletedMsg;
if (connectionCompletedMsg == null) {
return;
}
long timeStamp = System.currentTimeMillis();
connectionCompletedMsg.arg1 = cid;
if (cause == FailCause.NONE) {
createTime = timeStamp;
AsyncResult.forMessage(connectionCompletedMsg);
} else {
lastFailCause = cause;
lastFailTime = timeStamp;
AsyncResult.forMessage(connectionCompletedMsg, cause, new Exception());
}
if (DBG) log("notifyConnection at " + timeStamp + " cause=" + cause);
connectionCompletedMsg.sendToTarget();
}
/**
* Send ar.userObj if its a message, which is should be back to originator.
*
* @param dp is the DisconnectParams.
*/
private void notifyDisconnectCompleted(DisconnectParams dp) {
if (DBG) log("NotifyDisconnectCompleted");
Message msg = dp.onCompletedMsg;
AsyncResult.forMessage(msg);
msg.sendToTarget();
clearSettings();
}
protected void setHttpProxy(String httpProxy, String httpPort) {
if (httpProxy == null || httpProxy.length() == 0) {
phone.setSystemProperty("net.gprs.http-proxy", null);
return;
}
/**
* Clear all settings called when entering mInactiveState.
*/
protected void clearSettings() {
if (DBG) log("clearSettings");
if (httpPort == null || httpPort.length() == 0) {
httpPort = "8080"; // Default to port 8080
}
phone.setSystemProperty("net.gprs.http-proxy",
"http://" + httpProxy + ":" + httpPort + "/");
}
public String getInterface() {
return interfaceName;
}
public String getIpAddress() {
return ipAddress;
}
public String getGatewayAddress() {
return gatewayAddress;
}
public String[] getDnsServers() {
return dnsServers;
}
public void clearSettings() {
log("DataConnection.clearSettings()");
this.state = State.INACTIVE;
this.createTime = -1;
this.lastFailTime = -1;
this.lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
onConnectCompleted = null;
interfaceName = null;
ipAddress = null;
gatewayAddress = null;
@@ -246,80 +361,433 @@ public abstract class DataConnection extends Handler {
dnsServers[1] = null;
}
protected void onGetLastFailCompleted(AsyncResult ar) {
if (receivedDisconnectReq) {
// Don't bother reporting the error if there's already a
// pending disconnect request, since DataConnectionTracker
// has already updated its state.
notifyDisconnect(onDisconnect);
} else {
FailCause cause = FailCause.UNKNOWN;
/**
* Process setup completion.
*
* @param ar is the result
* @return SetupResult.
*/
private SetupResult onSetupConnectionCompleted(AsyncResult ar) {
SetupResult result;
String[] response = ((String[]) ar.result);
ConnectionParams cp = (ConnectionParams) ar.userObj;
if (ar.exception == null) {
int rilFailCause = ((int[]) (ar.result))[0];
cause = getFailCauseFromRequest(rilFailCause);
if (ar.exception != null) {
if (DBG) log("DataConnection Init failed " + ar.exception);
if (ar.exception instanceof CommandException
&& ((CommandException) (ar.exception)).getCommandError()
== CommandException.Error.RADIO_NOT_AVAILABLE) {
result = SetupResult.ERR_BadCommand;
result.mFailCause = FailCause.RADIO_NOT_AVAILABLE;
} else {
result = SetupResult.ERR_Other;
}
notifyFail(cause, onConnectCompleted);
}
}
protected void onForceRetry() {
if (receivedDisconnectReq) {
notifyDisconnect(onDisconnect);
} else if (cp.tag != mTag) {
if (DBG) {
log("BUG: onSetupConnectionCompleted is stale cp.tag=" + cp.tag + ", mtag=" + mTag);
}
result = SetupResult.ERR_Stale;
} else {
notifyFail(FailCause.RADIO_ERROR_RETRY, onConnectCompleted);
cid = Integer.parseInt(response[0]);
if (response.length > 2) {
interfaceName = response[1];
ipAddress = response[2];
String prefix = "net." + interfaceName + ".";
gatewayAddress = SystemProperties.get(prefix + "gw");
dnsServers[0] = SystemProperties.get(prefix + "dns1");
dnsServers[1] = SystemProperties.get(prefix + "dns2");
if (DBG) {
log("interface=" + interfaceName + " ipAddress=" + ipAddress
+ " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+ " DNS2=" + dnsServers[1]);
}
if (isDnsOk(dnsServers)) {
result = SetupResult.SUCCESS;
} else {
result = SetupResult.ERR_BadDns;
}
} else {
result = SetupResult.ERR_Other;
}
}
if (DBG) log("DataConnection setup result=" + result + " on cid = " + cid);
return result;
}
/**
* The parent state for all other states.
*/
private class DcDefaultState extends HierarchicalState {
@Override
protected boolean processMessage(Message msg) {
AsyncResult ar;
switch (msg.what) {
case EVENT_RESET:
if (DBG) log("DcDefaultState: msg.what=EVENT_RESET");
clearSettings();
transitionTo(mInactiveState);
break;
case EVENT_CONNECT:
if (DBG) log("DcDefaultState: msg.what=EVENT_CONNECT, fail not expected");
ConnectionParams cp = (ConnectionParams) msg.obj;
notifyConnectCompleted(cp, FailCause.UNKNOWN);
break;
case EVENT_DISCONNECT:
if (DBG) log("DcDefaultState: msg.what=EVENT_DISCONNECT");
notifyDisconnectCompleted((DisconnectParams) msg.obj);
break;
default:
if (DBG) {
log("DcDefaultState: shouldn't happen but ignore msg.what=" + msg.what);
}
break;
}
return true;
}
}
private DcDefaultState mDefaultState = new DcDefaultState();
@Override
public void handleMessage(Message msg) {
AsyncResult ar;
/**
* The state machine is inactive and expects a EVENT_CONNECT.
*/
private class DcInactiveState extends HierarchicalState {
@Override protected void enter() {
mTag += 1;
}
@Override protected boolean processMessage(Message msg) {
boolean retVal;
log("DataConnection.handleMessage()");
switch (msg.what) {
case EVENT_RESET:
if (DBG) {
log("DcInactiveState: msg.what=EVENT_RESET, ignore we're already reset");
}
retVal = true;
break;
switch (msg.what) {
case EVENT_CONNECT:
if (DBG) log("DcInactiveState msg.what=EVENT_CONNECT");
ConnectionParams cp = (ConnectionParams) msg.obj;
cp.tag = mTag;
onConnect(cp);
transitionTo(mActivatingState);
retVal = true;
break;
case EVENT_SETUP_DATA_CONNECTION_DONE:
onSetupConnectionCompleted((AsyncResult) msg.obj);
break;
case EVENT_FORCE_RETRY:
onForceRetry();
break;
case EVENT_GET_LAST_FAIL_DONE:
onGetLastFailCompleted((AsyncResult) msg.obj);
break;
case EVENT_LINK_STATE_CHANGED:
ar = (AsyncResult) msg.obj;
DataLink.LinkState ls = (DataLink.LinkState) ar.result;
onLinkStateChanged(ls);
break;
case EVENT_DEACTIVATE_DONE:
onDeactivated((AsyncResult) msg.obj);
break;
default:
if (DBG) log("DcInactiveState nothandled msg.what=" + msg.what);
retVal = false;
break;
}
return retVal;
}
}
private DcInactiveState mInactiveState = new DcInactiveState();
public State getState() {
log("DataConnection.getState()");
return state;
/**
* The state machine is activating a connection.
*/
private class DcActivatingState extends HierarchicalState {
@Override protected boolean processMessage(Message msg) {
boolean retVal;
AsyncResult ar;
ConnectionParams cp;
switch (msg.what) {
case EVENT_DISCONNECT:
if (DBG) log("DcActivatingState deferring msg.what=EVENT_DISCONNECT");
deferMessage(msg);
retVal = true;
break;
case EVENT_SETUP_DATA_CONNECTION_DONE:
if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
ar = (AsyncResult) msg.obj;
cp = (ConnectionParams) ar.userObj;
SetupResult result = onSetupConnectionCompleted(ar);
switch (result) {
case SUCCESS:
// All is well
notifyConnectCompleted(cp, FailCause.NONE);
transitionTo(mActiveState);
break;
case ERR_BadCommand:
// Vendor ril rejected the command and didn't connect.
notifyConnectCompleted(cp, result.mFailCause);
transitionTo(mInactiveState);
break;
case ERR_BadDns:
// Connection succeeded but DNS info is bad so disconnect
EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
dnsServers[0]);
tearDownData(cp);
transitionTo(mDisconnectingBadDnsState);
break;
case ERR_Other:
// Request the failure cause and process in this state
phone.mCM.getLastDataCallFailCause(
obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
break;
case ERR_Stale:
// Request is stale, ignore.
break;
default:
throw new RuntimeException("Unkown SetupResult, should not happen");
}
retVal = true;
break;
case EVENT_GET_LAST_FAIL_DONE:
ar = (AsyncResult) msg.obj;
cp = (ConnectionParams) ar.userObj;
FailCause cause = FailCause.UNKNOWN;
if (cp.tag == mTag) {
if (DBG) log("DcActivatingState msg.what=EVENT_GET_LAST_FAIL_DONE");
if (ar.exception == null) {
int rilFailCause = ((int[]) (ar.result))[0];
cause = getFailCauseFromRequest(rilFailCause);
}
notifyConnectCompleted(cp, cause);
transitionTo(mInactiveState);
} else {
if (DBG) {
log("DcActivatingState EVENT_GET_LAST_FAIL_DONE is stale cp.tag="
+ cp.tag + ", mTag=" + mTag);
}
}
retVal = true;
break;
default:
if (DBG) log("DcActivatingState not handled msg.what=" + msg.what);
retVal = false;
break;
}
return retVal;
}
}
private DcActivatingState mActivatingState = new DcActivatingState();
/**
* The state machine is connected, expecting an EVENT_DISCONNECT.
*/
private class DcActiveState extends HierarchicalState {
@Override protected boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
case EVENT_DISCONNECT:
if (DBG) log("DcActiveState msg.what=EVENT_DISCONNECT");
DisconnectParams dp = (DisconnectParams) msg.obj;
dp.tag = mTag;
tearDownData(dp);
transitionTo(mDisconnectingState);
retVal = true;
break;
default:
if (DBG) log("DcActiveState nothandled msg.what=" + msg.what);
retVal = false;
break;
}
return retVal;
}
}
private DcActiveState mActiveState = new DcActiveState();
/**
* The state machine is disconnecting.
*/
private class DcDisconnectingState extends HierarchicalState {
@Override protected boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
case EVENT_DEACTIVATE_DONE:
if (DBG) log("DcDisconnectingState msg.what=EVENT_DEACTIVATE_DONE");
AsyncResult ar = (AsyncResult) msg.obj;
DisconnectParams dp = (DisconnectParams) ar.userObj;
if (dp.tag == mTag) {
notifyDisconnectCompleted((DisconnectParams) ar.userObj);
transitionTo(mInactiveState);
} else {
if (DBG) log("DcDisconnectState EVENT_DEACTIVATE_DONE stale dp.tag="
+ dp.tag + " mTag=" + mTag);
}
retVal = true;
break;
default:
if (DBG) log("DcDisconnectingState not handled msg.what=" + msg.what);
retVal = false;
break;
}
return retVal;
}
}
private DcDisconnectingState mDisconnectingState = new DcDisconnectingState();
/**
* The state machine is disconnecting after a bad dns setup
* was found in mInactivatingState.
*/
private class DcDisconnectingBadDnsState extends HierarchicalState {
@Override protected boolean processMessage(Message msg) {
boolean retVal;
switch (msg.what) {
case EVENT_DEACTIVATE_DONE:
AsyncResult ar = (AsyncResult) msg.obj;
ConnectionParams cp = (ConnectionParams) ar.userObj;
if (cp.tag == mTag) {
if (DBG) log("DcDisconnectingBadDnsState msg.what=EVENT_DEACTIVATE_DONE");
notifyConnectCompleted(cp, FailCause.UNKNOWN);
transitionTo(mInactiveState);
} else {
if (DBG) log("DcDisconnectingBadDnsState EVENT_DEACTIVE_DONE stale dp.tag="
+ cp.tag + ", mTag=" + mTag);
}
retVal = true;
break;
default:
if (DBG) log("DcDisconnectingBadDnsState not handled msg.what=" + msg.what);
retVal = false;
break;
}
return retVal;
}
}
private DcDisconnectingBadDnsState mDisconnectingBadDnsState = new DcDisconnectingBadDnsState();
// ******* public interface
/**
* Disconnect from the network.
*/
public void reset() {
sendMessage(obtainMessage(EVENT_RESET));
}
/**
* Connect to the apn and return an AsyncResult in onCompletedMsg.
* Used for cellular networks that use Acess Point Names (APN) such
* as GSM networks.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj,
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
* @param apn is the Acces Point Name to connect to
*/
public void connect(Message onCompletedMsg, ApnSetting apn) {
sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(apn, onCompletedMsg)));
}
/**
* Connect to the apn and return an AsyncResult in onCompletedMsg.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj,
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
*/
public void connect(Message onCompletedMsg) {
sendMessage(obtainMessage(EVENT_CONNECT, new ConnectionParams(null, onCompletedMsg)));
}
/**
* Disconnect from the network.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
public void disconnect(Message onCompletedMsg) {
sendMessage(obtainMessage(EVENT_DISCONNECT, new DisconnectParams(onCompletedMsg)));
}
// ****** The following are used for debugging.
/**
* @return true if the state machine is in the inactive state.
*/
public boolean isInactive() {
boolean retVal = getCurrentState() == mInactiveState;
return retVal;
}
/**
* @return true if the state machine is in the inactive state.
*/
public boolean isActive() {
boolean retVal = getCurrentState() == mActiveState;
return retVal;
}
/**
* @return the interface name as a string.
*/
public String getInterface() {
return interfaceName;
}
/**
* @return the ip address as a string.
*/
public String getIpAddress() {
return ipAddress;
}
/**
* @return the gateway address as a string.
*/
public String getGatewayAddress() {
return gatewayAddress;
}
/**
* @return an array of associated DNS addresses.
*/
public String[] getDnsServers() {
return dnsServers;
}
/**
* @return the current state as a string.
*/
public String getStateAsString() {
String retVal = getCurrentState().getName();
return retVal;
}
/**
* @return the time of when this connection was created.
*/
public long getConnectionTime() {
log("DataConnection.getConnectionTime()");
return createTime;
}
/**
* @return the time of the last failure.
*/
public long getLastFailTime() {
log("DataConnection.getLastFailTime()");
return lastFailTime;
}
/**
* @return the last cause of failure.
*/
public FailCause getLastFailCause() {
log("DataConnection.getLastFailCause()");
return lastFailCause;
}
}

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony;
import android.os.Handler;
import android.os.Registrant;
/**
* Base class representing the data link layer (eg, PPP).
*
* {@hide}
*/
public abstract class DataLink extends Handler implements DataLinkInterface {
/** Registrant for link status change notifications. */
protected Registrant mLinkChangeRegistrant;
protected DataConnectionTracker dataConnection;
protected DataLink(DataConnectionTracker dc) {
dataConnection = dc;
}
public void setOnLinkChange(Handler h, int what, Object obj) {
mLinkChangeRegistrant = new Registrant(h, what, obj);
}
}

View File

@@ -1,77 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony;
import android.database.Cursor;
import android.os.Handler;
/**
* Data link interface.
*
* {@hide}
*/
public interface DataLinkInterface {
/**
* Link state enumeration.
*
*/
enum LinkState {
LINK_UNKNOWN,
LINK_UP,
LINK_DOWN,
LINK_EXITED
}
/** Normal exit */
final static int EXIT_OK = 0;
/** Open failed */
final static int EXIT_OPEN_FAILED = 7;
/**
* Sets the handler for link state change events.
*
* @param h Handler
* @param what User-defined message code
* @param obj User object
*/
void setOnLinkChange(Handler h, int what, Object obj);
/**
* Sets up the data link.
*/
void connect();
/**
* Tears down the data link.
*/
void disconnect();
/**
* Returns the exit code for a data link failure.
*
* @return exit code
*/
int getLastLinkExitCode();
/**
* Sets password information that may be required by the data link
* (eg, PAP secrets).
*
* @param cursor cursor to carriers table
*/
void setPasswordInfo(Cursor cursor);
}

View File

@@ -28,7 +28,7 @@ import android.telephony.SignalStrength;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.gsm.NetworkInfo;
import com.android.internal.telephony.gsm.PdpConnection;
import com.android.internal.telephony.gsm.GsmDataConnection;
import com.android.internal.telephony.test.SimulatedRadioControl;
import java.util.List;
@@ -1176,21 +1176,7 @@ public interface Phone {
void invokeOemRilRequestStrings(String[] strings, Message response);
/**
* Get the current active PDP context list
*
* @deprecated
* @param response <strong>On success</strong>, "response" bytes is
* made available as:
* (String[])(((AsyncResult)response.obj).result).
* <strong>On failure</strong>,
* (((AsyncResult)response.obj).result) == null and
* (((AsyncResult)response.obj).exception) being an instance of
* com.android.internal.telephony.gsm.CommandException
*/
void getPdpContextList(Message response);
/**
* Get the current active Data Call list, substitutes getPdpContextList
* Get the current active Data Call list
*
* @param response <strong>On success</strong>, "response" bytes is
* made available as:
@@ -1202,20 +1188,12 @@ public interface Phone {
*/
void getDataCallList(Message response);
/**
* Get current mutiple PDP link status
*
* @deprecated
* @return list of pdp link connections
*/
List<PdpConnection> getCurrentPdpList ();
/**
* Get current mutiple data connection status
*
* @return list of data connections
*/
List<DataConnection> getCurrentDataConnectionList ();
List<DataConnection> getCurrentDataConnectionList();
/**
* Update the ServiceState CellLocation for current network registration.

View File

@@ -35,7 +35,7 @@ import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
import com.android.internal.telephony.gsm.PdpConnection;
import com.android.internal.telephony.gsm.GsmDataConnection;
import com.android.internal.telephony.test.SimulatedRadioControl;
import java.util.List;
@@ -692,16 +692,6 @@ public abstract class PhoneBase extends Handler implements Phone {
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");
}
/**
* This should only be called in GSM mode.
* Only here for some backward compatibility
* issues concerning the GSMPhone class.
* @deprecated Always returns null.
*/
public List<PdpConnection> getCurrentPdpList() {
return null;
}
public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
// This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
Log.e(LOG_TAG, "Error! This function should never be executed, inactive CDMAPhone.");

View File

@@ -34,7 +34,7 @@ import android.util.Log;
import com.android.internal.telephony.cdma.CDMAPhone;
import com.android.internal.telephony.gsm.GSMPhone;
import com.android.internal.telephony.gsm.NetworkInfo;
import com.android.internal.telephony.gsm.PdpConnection;
import com.android.internal.telephony.gsm.GsmDataConnection;
import com.android.internal.telephony.test.SimulatedRadioControl;
import java.util.List;
@@ -564,24 +564,10 @@ public class PhoneProxy extends Handler implements Phone {
mActivePhone.invokeOemRilRequestStrings(strings, response);
}
/**
* @deprecated
*/
public void getPdpContextList(Message response) {
mActivePhone.getPdpContextList(response);
}
public void getDataCallList(Message response) {
mActivePhone.getDataCallList(response);
}
/**
* @deprecated
*/
public List<PdpConnection> getCurrentPdpList() {
return mActivePhone.getCurrentPdpList();
}
public List<DataConnection> getCurrentDataConnectionList() {
return mActivePhone.getCurrentDataConnectionList();
}

View File

@@ -657,13 +657,6 @@ public class CDMAPhone extends PhoneBase {
mSST.disableLocationUpdates();
}
/**
* @deprecated
*/
public void getPdpContextList(Message response) {
getDataCallList(response);
}
public void getDataCallList(Message response) {
mCM.getDataCallList(response);
}

View File

@@ -16,221 +16,77 @@
package com.android.internal.telephony.cdma;
import android.os.*;
import android.util.EventLog;
import android.os.Message;
import android.util.Log;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataLink;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyEventLog;
/**
* {@hide}
*
*/
public class CdmaDataConnection extends DataConnection {
private static final String LOG_TAG = "CDMA";
private static final boolean DBG = true;
/** Fail cause of last Data Call activate from RIL_LastDataCallActivateFailCause */
private final static int PS_NET_DOWN_REASON_OPERATOR_DETERMINED_BARRING = 8;
private final static int PS_NET_DOWN_REASON_UNKNOWN_APN = 27;
private final static int PS_NET_DOWN_REASON_AUTH_FAILED = 29;
private final static int PS_NET_DOWN_REASON_OPTION_NOT_SUPPORTED = 32;
private final static int PS_NET_DOWN_REASON_OPTION_UNSUBSCRIBED = 33;
/** It is likely that the number of error codes listed below will be removed
* in the foreseeable future. They have been added, but not agreed upon.
*
*/
private final static int PS_NET_DOWN_REASON_NOT_SPECIFIED = 0;
private final static int PS_NET_DOWN_REASON_CLOSE_IN_PROGRESS = 1;
private final static int PS_NET_DOWN_REASON_NW_INITIATED_TERMINATION = 2;
private final static int PS_NET_DOWN_REASON_APP_PREEMPTED = 3;
private final static int PS_NET_DOWN_REASON_LLC_SNDCP_FAILURE = 25;
private final static int PS_NET_DOWN_REASON_INSUFFICIENT_RESOURCES = 26;
private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP = 28;
private final static int PS_NET_DOWN_REASON_GGSN_REJECT = 30;
private final static int PS_NET_DOWN_REASON_ACTIVATION_REJECT = 31;
private final static int PS_NET_DOWN_REASON_OPTION_TEMP_OOO = 34;
private final static int PS_NET_DOWN_REASON_NSAPI_ALREADY_USED = 35;
private final static int PS_NET_DOWN_REASON_REGULAR_DEACTIVATION = 36;
private final static int PS_NET_DOWN_REASON_QOS_NOT_ACCEPTED = 37;
private final static int PS_NET_DOWN_REASON_NETWORK_FAILURE = 38;
private final static int PS_NET_DOWN_REASON_UMTS_REATTACH_REQ = 39;
private final static int PS_NET_DOWN_REASON_TFT_SEMANTIC_ERROR = 41;
private final static int PS_NET_DOWN_REASON_TFT_SYNTAX_ERROR = 42;
private final static int PS_NET_DOWN_REASON_UNKNOWN_PDP_CONTEXT = 43;
private final static int PS_NET_DOWN_REASON_FILTER_SEMANTIC_ERROR = 44;
private final static int PS_NET_DOWN_REASON_FILTER_SYNTAX_ERROR = 45;
private final static int PS_NET_DOWN_REASON_PDP_WITHOUT_ACTIVE_TFT = 46;
private final static int PS_NET_DOWN_REASON_INVALID_TRANSACTION_ID = 81;
private final static int PS_NET_DOWN_REASON_MESSAGE_INCORRECT_SEMANTIC = 95;
private final static int PS_NET_DOWN_REASON_INVALID_MANDATORY_INFO = 96;
private final static int PS_NET_DOWN_REASON_MESSAGE_TYPE_UNSUPPORTED = 97;
private final static int PS_NET_DOWN_REASON_MSG_TYPE_NONCOMPATIBLE_STATE = 98;
private final static int PS_NET_DOWN_REASON_UNKNOWN_INFO_ELEMENT = 99;
private final static int PS_NET_DOWN_REASON_CONDITIONAL_IE_ERROR = 100;
private final static int PS_NET_DOWN_REASON_MSG_AND_PROTOCOL_STATE_UNCOMPATIBLE = 101;
private final static int PS_NET_DOWN_REASON_PROTOCOL_ERROR = 111;
private final static int PS_NET_DOWN_REASON_APN_TYPE_CONFLICT = 112;
private final static int PS_NET_DOWN_REASON_UNKNOWN_CAUSE_CODE = 113;
private final static int PS_NET_DOWN_REASON_INTERNAL_MIN = 200;
private final static int PS_NET_DOWN_REASON_INTERNAL_ERROR = 201;
private final static int PS_NET_DOWN_REASON_INTERNAL_CALL_ENDED = 202;
private final static int PS_NET_DOWN_REASON_INTERNAL_UNKNOWN_CAUSE_CODE = 203;
private final static int PS_NET_DOWN_REASON_INTERNAL_MAX = 204;
private final static int PS_NET_DOWN_REASON_CDMA_LOCK = 500;
private final static int PS_NET_DOWN_REASON_INTERCEPT = 501;
private final static int PS_NET_DOWN_REASON_REORDER = 502;
private final static int PS_NET_DOWN_REASON_REL_SO_REJ = 503;
private final static int PS_NET_DOWN_REASON_INCOM_CALL = 504;
private final static int PS_NET_DOWN_REASON_ALERT_STOP = 505;
private final static int PS_NET_DOWN_REASON_ACTIVATION = 506;
private final static int PS_NET_DOWN_REASON_MAX_ACCESS_PROBE = 507;
private final static int PS_NET_DOWN_REASON_CCS_NOT_SUPPORTED_BY_BS = 508;
private final static int PS_NET_DOWN_REASON_NO_RESPONSE_FROM_BS = 509;
private final static int PS_NET_DOWN_REASON_REJECTED_BY_BS = 510;
private final static int PS_NET_DOWN_REASON_INCOMPATIBLE = 511;
private final static int PS_NET_DOWN_REASON_ALREADY_IN_TC = 512;
private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_GPS = 513;
private final static int PS_NET_DOWN_REASON_USER_CALL_ORIG_DURING_SMS = 514;
private final static int PS_NET_DOWN_REASON_NO_CDMA_SRV = 515;
private final static int PS_NET_DOWN_REASON_CONF_FAILED = 1000;
private final static int PS_NET_DOWN_REASON_INCOM_REJ = 1001;
private final static int PS_NET_DOWN_REASON_NO_GW_SRV = 1002;
private final static int PS_NET_DOWN_REASON_CD_GEN_OR_BUSY = 1500;
private final static int PS_NET_DOWN_REASON_CD_BILL_OR_AUTH = 1501;
private final static int PS_NET_DOWN_REASON_CHG_HDR = 1502;
private final static int PS_NET_DOWN_REASON_EXIT_HDR = 1503;
private final static int PS_NET_DOWN_REASON_HDR_NO_SESSION = 1504;
private final static int PS_NET_DOWN_REASON_HDR_ORIG_DURING_GPS_FIX = 1505;
private final static int PS_NET_DOWN_REASON_HDR_CS_TIMEOUT = 1506;
private final static int PS_NET_DOWN_REASON_HDR_RELEASED_BY_CM = 1507;
private final static int PS_NET_DOWN_REASON_CLIENT_END = 2000;
private final static int PS_NET_DOWN_REASON_NO_SRV = 2001;
private final static int PS_NET_DOWN_REASON_FADE = 2002;
private final static int PS_NET_DOWN_REASON_REL_NORMAL = 2003;
private final static int PS_NET_DOWN_REASON_ACC_IN_PROG = 2004;
private final static int PS_NET_DOWN_REASON_ACC_FAIL = 2005;
private final static int PS_NET_DOWN_REASON_REDIR_OR_HANDOFF = 2006;
// ***** Instance Variables
// ***** Constructor
CdmaDataConnection(CDMAPhone phone) {
super(phone);
if (DBG) log("CdmaDataConnection <constructor>");
private CdmaDataConnection(CDMAPhone phone, String name) {
super(phone, name);
}
/**
* Setup a data connection
* Create the connection object
*
* @param onCompleted
* notify success or not after down
* @param phone
* @return CdmaDataConnection that was created.
*/
void connect(Message onCompleted) {
static CdmaDataConnection makeDataConnection(CDMAPhone phone) {
synchronized (mCountLock) {
mCount += 1;
}
CdmaDataConnection cdmaDc = new CdmaDataConnection(phone, "CdmaDataConnection-" + mCount);
cdmaDc.start();
if (DBG) cdmaDc.log("Made " + cdmaDc.getName());
return cdmaDc;
}
/**
* Begin setting up a data connection, calls setupDataCall
* and the ConnectionParams will be returned with the
* EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
*
* @param cp is the connection parameters
*/
@Override
protected void onConnect(ConnectionParams cp) {
if (DBG) log("CdmaDataConnection Connecting...");
state = State.ACTIVATING;
onConnectCompleted = onCompleted;
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
// msg.obj will be returned in AsyncResult.userObj;
Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
msg.obj = cp;
phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), null, null,
null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), msg);
}
private void tearDownData(Message msg) {
if (phone.mCM.getRadioState().isOn()) {
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
}
}
protected void disconnect(Message msg) {
onDisconnect = msg;
if (state == State.ACTIVE) {
tearDownData(msg);
} else if (state == State.ACTIVATING) {
receivedDisconnectReq = true;
} else {
// state == INACTIVE. Nothing to do, so notify immediately.
notifyDisconnect(msg);
}
}
@Override
public String toString() {
return "State=" + state + " create=" + createTime + " lastFail="
+ lastFailTime + " lastFailCause=" + lastFailCause;
}
protected void notifyFail(FailCause cause, Message onCompleted) {
if (onCompleted == null) {
return;
}
state = State.INACTIVE;
lastFailCause = cause;
lastFailTime = System.currentTimeMillis();
onConnectCompleted = null;
if(DBG) {
log("Notify data connection fail at " + lastFailTime +
" due to " + lastFailCause);
}
AsyncResult.forMessage(onCompleted, cause, new Exception());
onCompleted.sendToTarget();
}
protected void notifySuccess(Message onCompleted) {
if (onCompleted == null) {
return;
}
state = State.ACTIVE;
createTime = System.currentTimeMillis();
onConnectCompleted = null;
onCompleted.arg1 = cid;
if (DBG) log("Notify data connection success at " + createTime);
AsyncResult.forMessage(onCompleted);
onCompleted.sendToTarget();
}
protected void notifyDisconnect(Message msg) {
if (DBG) log("Notify data connection disconnect");
if (msg != null) {
AsyncResult.forMessage(msg);
msg.sendToTarget();
}
clearSettings();
}
protected void onLinkStateChanged(DataLink.LinkState linkState) {
switch (linkState) {
case LINK_UP:
notifySuccess(onConnectCompleted);
break;
case LINK_DOWN:
case LINK_EXITED:
phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
break;
}
return "State=" + getCurrentState().getName() + " create=" + createTime + " lastFail="
+ lastFailTime + " lastFasilCause=" + lastFailCause;
}
@Override
protected FailCause getFailCauseFromRequest(int rilCause) {
FailCause cause;
@@ -253,73 +109,19 @@ public class CdmaDataConnection extends DataConnection {
return cause;
}
protected void log(String s) {
Log.d(LOG_TAG, "[CdmaDataConnection] " + s);
}
@Override
protected void onDeactivated(AsyncResult ar) {
notifyDisconnect((Message) ar.userObj);
if (DBG) log("CDMA Connection Deactivated");
}
@Override
protected void onSetupConnectionCompleted(AsyncResult ar) {
if (ar.exception != null) {
Log.e(LOG_TAG, "CdmaDataConnection Init failed " + ar.exception);
if (receivedDisconnectReq) {
// Don't bother reporting the error if there's already a
// pending disconnect request, since DataConnectionTracker
// has already updated its state.
notifyDisconnect(onDisconnect);
} else {
if (ar.exception instanceof CommandException
&& ((CommandException) (ar.exception)).getCommandError()
== CommandException.Error.RADIO_NOT_AVAILABLE) {
notifyFail(FailCause.RADIO_NOT_AVAILABLE, onConnectCompleted);
} else {
phone.mCM.getLastDataCallFailCause(obtainMessage(EVENT_GET_LAST_FAIL_DONE));
}
}
protected boolean isDnsOk(String[] domainNameServers) {
if ((NULL_IP.equals(domainNameServers[0])
&& NULL_IP.equals(domainNameServers[1])
&& !((CDMAPhone) phone).isDnsCheckDisabled())) {
return false;
} else {
if (receivedDisconnectReq) {
// Don't bother reporting success if there's already a
// pending disconnect request, since DataConnectionTracker
// has already updated its state.
tearDownData(onDisconnect);
} else {
String[] response = ((String[]) ar.result);
cid = Integer.parseInt(response[0]);
if (response.length > 2) {
interfaceName = response[1];
ipAddress = response[2];
String prefix = "net." + interfaceName + ".";
gatewayAddress = SystemProperties.get(prefix + "gw");
dnsServers[0] = SystemProperties.get(prefix + "dns1");
dnsServers[1] = SystemProperties.get(prefix + "dns2");
if (DBG) {
log("interface=" + interfaceName + " ipAddress=" + ipAddress
+ " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+ " DNS2=" + dnsServers[1]);
}
if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
&& !((CDMAPhone) phone).isDnsCheckDisabled()) {
// Work around a race condition where QMI does not fill in DNS:
// Deactivate PDP and let DataConnectionTracker retry.
EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
dnsServers[0]);
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
return;
}
}
onLinkStateChanged(DataLink.LinkState.LINK_UP);
if (DBG) log("CdmaDataConnection setup on cid = " + cid);
}
return true;
}
}
@Override
protected void log(String s) {
Log.d(LOG_TAG, "[" + getName() + "] " + s);
}
}

View File

@@ -386,7 +386,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
conn.disconnect(msg);
} else {
conn.clearSettings();
conn.reset();
}
}
}
@@ -403,7 +403,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
private CdmaDataConnection findFreeDataConnection() {
for (DataConnection connBase : dataConnectionList) {
CdmaDataConnection conn = (CdmaDataConnection) connBase;
if (conn.getState() == DataConnection.State.INACTIVE) {
if (conn.isInactive()) {
return conn;
}
}
@@ -801,7 +801,7 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
CdmaDataConnection dataConn;
for (int i = 0; i < DATA_CONNECTION_POOL_SIZE; i++) {
dataConn = new CdmaDataConnection(mCdmaPhone);
dataConn = CdmaDataConnection.makeDataConnection(mCdmaPhone);
dataConnectionList.add(dataConn);
}
}

View File

@@ -1050,33 +1050,10 @@ public class GSMPhone extends PhoneBase {
return mCT.getMute();
}
/**
* @deprecated Do not use.
*/
@Deprecated
public void getPdpContextList(Message response) {
getDataCallList(response);
}
public void getDataCallList(Message response) {
mCM.getDataCallList(response);
}
/**
* @deprecated Do not use.
*/
@Deprecated
public List<PdpConnection> getCurrentPdpList() {
ArrayList<DataConnection> connections = new ArrayList<DataConnection>();
ArrayList<PdpConnection> pdp_list = new ArrayList<PdpConnection>();
for(int n = 0; n < connections.size(); n++) {
pdp_list.add((PdpConnection) connections.get(n));
}
return pdp_list;
}
public List<DataConnection> getCurrentDataConnectionList () {
return mDataConnection.getAllDataConnections();
}

View File

@@ -0,0 +1,226 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony.gsm;
import android.os.Message;
import android.util.Log;
import com.android.common.Patterns;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
/**
* {@hide}
*/
public class GsmDataConnection extends DataConnection {
private static final String LOG_TAG = "GSM";
/** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
private static final int PDP_FAIL_NSAPI_IN_USE = 0x23;
private static final int PDP_FAIL_PROTOCOL_ERRORS = 0x6F;
private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
//***** Instance Variables
private ApnSetting apn;
//***** Constructor
private GsmDataConnection(GSMPhone phone, String name) {
super(phone, name);
}
/**
* Create the connection object
*
* @param phone
* @return GsmDataConnection that was created.
*/
static GsmDataConnection makeDataConnection(GSMPhone phone) {
synchronized (mCountLock) {
mCount += 1;
}
GsmDataConnection gsmDc = new GsmDataConnection(phone, "GsmDataConnection-" + mCount);
gsmDc.start();
if (DBG) gsmDc.log("Made " + gsmDc.getName());
return gsmDc;
}
/**
* Begin setting up a data connection, calls setupDataCall
* and the ConnectionParams will be returned with the
* EVENT_SETUP_DATA_CONNECTION_DONE AsyncResul.userObj.
*
* @param cp is the connection parameters
*/
@Override
protected
void onConnect(ConnectionParams cp) {
apn = cp.apn;
if (DBG) log("Connecting to carrier: '" + apn.carrier
+ "' APN: '" + apn.apn
+ "' proxy: '" + apn.proxy + "' port: '" + apn.port);
setHttpProxy (apn.proxy, apn.port);
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
// msg.obj will be returned in AsyncResult.userObj;
Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
msg.obj = cp;
int authType = apn.authType;
if (authType == -1) {
authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
RILConstants.SETUP_DATA_AUTH_NONE;
}
phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
apn.password, Integer.toString(authType), msg);
}
@Override
protected void clearSettings() {
super.clearSettings();
apn = null;
}
@Override
public String toString() {
return "State=" + getCurrentState().getName() + " Apn=" + apn +
" create=" + createTime + " lastFail=" + lastFailTime +
" lastFailCause=" + lastFailCause;
}
@Override
protected FailCause getFailCauseFromRequest(int rilCause) {
FailCause cause;
switch (rilCause) {
case PDP_FAIL_OPERATOR_BARRED:
cause = FailCause.OPERATOR_BARRED;
break;
case PDP_FAIL_INSUFFICIENT_RESOURCES:
cause = FailCause.INSUFFICIENT_RESOURCES;
break;
case PDP_FAIL_MISSING_UKNOWN_APN:
cause = FailCause.MISSING_UKNOWN_APN;
break;
case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
cause = FailCause.UNKNOWN_PDP_ADDRESS;
break;
case PDP_FAIL_USER_AUTHENTICATION:
cause = FailCause.USER_AUTHENTICATION;
break;
case PDP_FAIL_ACTIVATION_REJECT_GGSN:
cause = FailCause.ACTIVATION_REJECT_GGSN;
break;
case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
break;
case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
break;
case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
break;
case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
break;
case PDP_FAIL_NSAPI_IN_USE:
cause = FailCause.NSAPI_IN_USE;
break;
case PDP_FAIL_PROTOCOL_ERRORS:
cause = FailCause.PROTOCOL_ERRORS;
break;
case PDP_FAIL_ERROR_UNSPECIFIED:
cause = FailCause.UNKNOWN;
break;
case PDP_FAIL_REGISTRATION_FAIL:
cause = FailCause.REGISTRATION_FAIL;
break;
case PDP_FAIL_GPRS_REGISTRATION_FAIL:
cause = FailCause.GPRS_REGISTRATION_FAIL;
break;
default:
cause = FailCause.UNKNOWN;
}
return cause;
}
@Override
protected boolean isDnsOk(String[] domainNameServers) {
if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
&& !((GSMPhone) phone).isDnsCheckDisabled()) {
// Work around a race condition where QMI does not fill in DNS:
// Deactivate PDP and let DataConnectionTracker retry.
// Do not apply the race condition workaround for MMS APN
// if Proxy is an IP-address.
// Otherwise, the default APN will not be restored anymore.
if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
|| !isIpAddress(apn.mmsProxy)) {
return false;
}
}
return true;
}
@Override
protected void log(String s) {
Log.d(LOG_TAG, "[" + getName() + "] " + s);
}
public ApnSetting getApn() {
return this.apn;
}
private void setHttpProxy(String httpProxy, String httpPort) {
if (httpProxy == null || httpProxy.length() == 0) {
phone.setSystemProperty("net.gprs.http-proxy", null);
return;
}
if (httpPort == null || httpPort.length() == 0) {
httpPort = "8080"; // Default to port 8080
}
phone.setSystemProperty("net.gprs.http-proxy",
"http://" + httpProxy + ":" + httpPort + "/");
}
private boolean isIpAddress(String address) {
if (address == null) return false;
return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
}
}

View File

@@ -126,8 +126,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
*/
private ArrayList<DataConnection> pdpList;
/** Currently active PdpConnection */
private PdpConnection mActivePdp;
/** Currently active DataConnection */
private GsmDataConnection mActivePdp;
/** Is packet service restricted by network */
private boolean mIsPsRestricted = false;
@@ -137,7 +137,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// TODO: Increase this to match the max number of simultaneous
// PDP contexts we plan to support.
/**
* Pool size of PdpConnection objects.
* Pool size of DataConnection objects.
*/
private static final int PDP_CONNECTION_POOL_SIZE = 1;
@@ -382,7 +382,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
/**
* Formerly this method was ArrayList<PdpConnection> getAllPdps()
* Formerly this method was ArrayList<GsmDataConnection> getAllPdps()
*/
public ArrayList<DataConnection> getAllDataConnections() {
ArrayList<DataConnection> pdps = (ArrayList<DataConnection>)pdpList.clone();
@@ -452,7 +452,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
waitingApns = buildWaitingApns();
if (waitingApns.isEmpty()) {
if (DBG) log("No APN found");
notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN);
notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
return false;
} else {
log ("Create from allApns : " + apnListToString(allApns));
@@ -487,7 +487,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* there is no mechanism for abandoning an INITING/CONNECTING session,
* but would likely involve cancelling pending async requests or
* setting a flag or new state to ignore them when they came in
* @param tearDown true if the underlying PdpConnection should be
* @param tearDown true if the underlying GsmDataConnection should be
* disconnected.
* @param reason reason for the clean up.
*/
@@ -505,12 +505,11 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
setState(State.DISCONNECTING);
for (DataConnection conn : pdpList) {
PdpConnection pdp = (PdpConnection) conn;
if (tearDown) {
Message msg = obtainMessage(EVENT_DISCONNECT_DONE, reason);
pdp.disconnect(msg);
conn.disconnect(msg);
} else {
pdp.clearSettings();
conn.reset();
}
}
stopNetStatPoll();
@@ -564,10 +563,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return result;
}
private PdpConnection findFreePdp() {
private GsmDataConnection findFreePdp() {
for (DataConnection conn : pdpList) {
PdpConnection pdp = (PdpConnection) conn;
if (pdp.getState() == DataConnection.State.INACTIVE) {
GsmDataConnection pdp = (GsmDataConnection) conn;
if (pdp.isInactive()) {
return pdp;
}
}
@@ -576,13 +575,13 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
private boolean setupData(String reason) {
ApnSetting apn;
PdpConnection pdp;
GsmDataConnection pdp;
apn = getNextApn();
if (apn == null) return false;
pdp = findFreePdp();
if (pdp == null) {
if (DBG) log("setupData: No free PdpConnection found!");
if (DBG) log("setupData: No free GsmDataConnection found!");
return false;
}
mActiveApn = apn;
@@ -591,7 +590,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
pdp.connect(apn, msg);
pdp.connect(msg, apn);
setState(State.INITING);
phone.notifyDataConnection(reason);
@@ -974,13 +973,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
* seems like it deserves an error notification.
* Transient errors are ignored
*/
private boolean shouldPostNotification(PdpConnection.FailCause cause) {
boolean shouldPost = true;
// TODO CHECK
// if (dataLink != null) {
// shouldPost = dataLink.getLastLinkExitCode() != DataLink.EXIT_OPEN_FAILED;
//}
return (shouldPost && cause != PdpConnection.FailCause.UNKNOWN);
private boolean shouldPostNotification(GsmDataConnection.FailCause cause) {
return (cause != GsmDataConnection.FailCause.UNKNOWN);
}
/**
@@ -1046,7 +1040,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
}
}
private void notifyNoData(PdpConnection.FailCause lastFailCauseCode) {
private void notifyNoData(GsmDataConnection.FailCause lastFailCauseCode) {
setState(State.FAILED);
}
@@ -1069,7 +1063,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
mRetryMgr.resetRetryCount();
// TODO: To support simultaneous PDP contexts, this should really only call
// cleanUpConnection if it needs to free up a PdpConnection.
// cleanUpConnection if it needs to free up a GsmDataConnection.
cleanUpConnection(true, Phone.REASON_APN_SWITCHED);
}
@@ -1149,8 +1143,8 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
// that the existing connection may service that type, in which
// case we should try the next type, etc.
} else {
PdpConnection.FailCause cause;
cause = (PdpConnection.FailCause) (ar.result);
GsmDataConnection.FailCause cause;
cause = (GsmDataConnection.FailCause) (ar.result);
if(DBG) log("PDP setup failed " + cause);
// Log this failure to the Event Logs.
if (cause.isEventLoggable()) {
@@ -1259,9 +1253,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (cursor.getCount() > 0) {
allApns = createApnList(cursor);
// TODO: Figure out where this fits in. This basically just
// writes the pap-secrets file. No longer tied to PdpConnection
// writes the pap-secrets file. No longer tied to GsmDataConnection
// object. Not used on current platform (no ppp).
//PdpConnection pdp = pdpList.get(pdp_name);
//GsmDataConnection pdp = pdpList.get(pdp_name);
//if (pdp != null && pdp.dataLink != null) {
// pdp.dataLink.setPasswordInfo(cursor);
//}
@@ -1273,7 +1267,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
if (allApns.isEmpty()) {
if (DBG) log("No APN found for carrier: " + operator);
preferredApn = null;
notifyNoData(PdpConnection.FailCause.MISSING_UKNOWN_APN);
notifyNoData(GsmDataConnection.FailCause.MISSING_UKNOWN_APN);
} else {
preferredApn = getPreferredApn();
Log.d(LOG_TAG, "Get PreferredAPN");
@@ -1289,14 +1283,14 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
DataConnection pdp;
for (int i = 0; i < PDP_CONNECTION_POOL_SIZE; i++) {
pdp = new PdpConnection(mGsmPhone);
pdp = GsmDataConnection.makeDataConnection(mGsmPhone);
pdpList.add(pdp);
}
}
private void destroyAllPdpList() {
if(pdpList != null) {
PdpConnection pdp;
GsmDataConnection pdp;
pdpList.removeAll(pdpList);
}
}
@@ -1361,7 +1355,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
return result.toString();
}
private void startDelayedRetry(PdpConnection.FailCause cause, String reason) {
private void startDelayedRetry(GsmDataConnection.FailCause cause, String reason) {
notifyNoData(cause);
reconnectAfterFail(cause, reason);
}

View File

@@ -1,327 +0,0 @@
/*
* Copyright (C) 2006 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony.gsm;
import android.os.*;
import android.util.EventLog;
import android.util.Log;
import com.android.common.Patterns;
import com.android.internal.telephony.CommandException;
import com.android.internal.telephony.CommandsInterface;
import com.android.internal.telephony.DataConnection;
import com.android.internal.telephony.DataLink;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.RILConstants;
import com.android.internal.telephony.TelephonyEventLog;
/**
* {@hide}
*/
public class PdpConnection extends DataConnection {
private static final String LOG_TAG = "GSM";
private static final boolean DBG = true;
/** Fail cause of last PDP activate, from RIL_LastPDPActivateFailCause */
private static final int PDP_FAIL_OPERATOR_BARRED = 0x08;
private static final int PDP_FAIL_INSUFFICIENT_RESOURCES = 0x1A;
private static final int PDP_FAIL_MISSING_UKNOWN_APN = 0x1B;
private static final int PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE = 0x1C;
private static final int PDP_FAIL_USER_AUTHENTICATION = 0x1D;
private static final int PDP_FAIL_ACTIVATION_REJECT_GGSN = 0x1E;
private static final int PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED = 0x1F;
private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED = 0x20;
private static final int PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED = 0x21;
private static final int PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER = 0x22;
private static final int PDP_FAIL_NSAPI_IN_USE = 0x23;
private static final int PDP_FAIL_PROTOCOL_ERRORS = 0x6F;
private static final int PDP_FAIL_ERROR_UNSPECIFIED = 0xffff;
private static final int PDP_FAIL_REGISTRATION_FAIL = -1;
private static final int PDP_FAIL_GPRS_REGISTRATION_FAIL = -2;
//***** Instance Variables
private String pdp_name;
private ApnSetting apn;
//***** Constructor
PdpConnection(GSMPhone phone) {
super(phone);
}
/**
* Setup PDP connection for provided apn
* @param apn for this connection
* @param onCompleted notify success or not after down
*/
void connect(ApnSetting apn, Message onCompleted) {
if (DBG) log("Connecting to carrier: '" + apn.carrier
+ "' APN: '" + apn.apn
+ "' proxy: '" + apn.proxy + "' port: '" + apn.port);
setHttpProxy (apn.proxy, apn.port);
state = State.ACTIVATING;
this.apn = apn;
onConnectCompleted = onCompleted;
createTime = -1;
lastFailTime = -1;
lastFailCause = FailCause.NONE;
receivedDisconnectReq = false;
int authType = apn.authType;
if (authType == -1) {
authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
RILConstants.SETUP_DATA_AUTH_NONE;
}
phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
apn.password, Integer.toString(authType),
obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE));
}
private void tearDownData(Message msg) {
if (phone.mCM.getRadioState().isOn()) {
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_DEACTIVATE_DONE, msg));
}
}
protected void disconnect(Message msg) {
onDisconnect = msg;
if (state == State.ACTIVE) {
tearDownData(msg);
} else if (state == State.ACTIVATING) {
receivedDisconnectReq = true;
} else {
// state == INACTIVE. Nothing to do, so notify immediately.
notifyDisconnect(msg);
}
}
public void clearSettings() {
super.clearSettings();
apn = null;
}
public String toString() {
return "State=" + state + " Apn=" + apn +
" create=" + createTime + " lastFail=" + lastFailTime +
" lastFailCause=" + lastFailCause;
}
protected void notifyFail(FailCause cause, Message onCompleted) {
if (onCompleted == null) return;
state = State.INACTIVE;
lastFailCause = cause;
lastFailTime = System.currentTimeMillis();
onConnectCompleted = null;
if (DBG) {
log("Notify PDP fail at " + lastFailTime +
" due to " + lastFailCause);
}
AsyncResult.forMessage(onCompleted, cause, new Exception());
onCompleted.sendToTarget();
}
protected void notifySuccess(Message onCompleted) {
if (onCompleted == null) {
return;
}
state = State.ACTIVE;
createTime = System.currentTimeMillis();
onConnectCompleted = null;
onCompleted.arg1 = cid;
if (DBG) log("Notify PDP success at " + createTime);
AsyncResult.forMessage(onCompleted);
onCompleted.sendToTarget();
}
protected void notifyDisconnect(Message msg) {
if (DBG) log("Notify PDP disconnect");
if (msg != null) {
AsyncResult.forMessage(msg);
msg.sendToTarget();
}
clearSettings();
}
protected void onLinkStateChanged(DataLink.LinkState linkState) {
switch (linkState) {
case LINK_UP:
notifySuccess(onConnectCompleted);
break;
case LINK_DOWN:
case LINK_EXITED:
phone.mCM.getLastPdpFailCause(
obtainMessage (EVENT_GET_LAST_FAIL_DONE));
break;
}
}
protected FailCause getFailCauseFromRequest(int rilCause) {
FailCause cause;
switch (rilCause) {
case PDP_FAIL_OPERATOR_BARRED:
cause = FailCause.OPERATOR_BARRED;
break;
case PDP_FAIL_INSUFFICIENT_RESOURCES:
cause = FailCause.INSUFFICIENT_RESOURCES;
break;
case PDP_FAIL_MISSING_UKNOWN_APN:
cause = FailCause.MISSING_UKNOWN_APN;
break;
case PDP_FAIL_UNKNOWN_PDP_ADDRESS_TYPE:
cause = FailCause.UNKNOWN_PDP_ADDRESS;
break;
case PDP_FAIL_USER_AUTHENTICATION:
cause = FailCause.USER_AUTHENTICATION;
break;
case PDP_FAIL_ACTIVATION_REJECT_GGSN:
cause = FailCause.ACTIVATION_REJECT_GGSN;
break;
case PDP_FAIL_ACTIVATION_REJECT_UNSPECIFIED:
cause = FailCause.ACTIVATION_REJECT_UNSPECIFIED;
break;
case PDP_FAIL_SERVICE_OPTION_OUT_OF_ORDER:
cause = FailCause.SERVICE_OPTION_OUT_OF_ORDER;
break;
case PDP_FAIL_SERVICE_OPTION_NOT_SUPPORTED:
cause = FailCause.SERVICE_OPTION_NOT_SUPPORTED;
break;
case PDP_FAIL_SERVICE_OPTION_NOT_SUBSCRIBED:
cause = FailCause.SERVICE_OPTION_NOT_SUBSCRIBED;
break;
case PDP_FAIL_NSAPI_IN_USE:
cause = FailCause.NSAPI_IN_USE;
break;
case PDP_FAIL_PROTOCOL_ERRORS:
cause = FailCause.PROTOCOL_ERRORS;
break;
case PDP_FAIL_ERROR_UNSPECIFIED:
cause = FailCause.UNKNOWN;
break;
case PDP_FAIL_REGISTRATION_FAIL:
cause = FailCause.REGISTRATION_FAIL;
break;
case PDP_FAIL_GPRS_REGISTRATION_FAIL:
cause = FailCause.GPRS_REGISTRATION_FAIL;
break;
default:
cause = FailCause.UNKNOWN;
}
return cause;
}
protected void log(String s) {
Log.d(LOG_TAG, "[PdpConnection] " + s);
}
@Override
protected void onDeactivated(AsyncResult ar) {
notifyDisconnect((Message) ar.userObj);
if (DBG) log("PDP Connection Deactivated");
}
@Override
protected void onSetupConnectionCompleted(AsyncResult ar) {
if (ar.exception != null) {
Log.e(LOG_TAG, "PDP Context Init failed " + ar.exception);
if (receivedDisconnectReq) {
// Don't bother reporting the error if there's already a
// pending disconnect request, since DataConnectionTracker
// has already updated its state.
notifyDisconnect(onDisconnect);
} else {
if ( ar.exception instanceof CommandException &&
((CommandException) (ar.exception)).getCommandError()
== CommandException.Error.RADIO_NOT_AVAILABLE) {
notifyFail(FailCause.RADIO_NOT_AVAILABLE,
onConnectCompleted);
} else {
phone.mCM.getLastPdpFailCause(
obtainMessage(EVENT_GET_LAST_FAIL_DONE));
}
}
} else {
if (receivedDisconnectReq) {
// Don't bother reporting success if there's already a
// pending disconnect request, since DataConnectionTracker
// has already updated its state.
tearDownData(onDisconnect);
} else {
String[] response = ((String[]) ar.result);
cid = Integer.parseInt(response[0]);
if (response.length > 2) {
interfaceName = response[1];
ipAddress = response[2];
String prefix = "net." + interfaceName + ".";
gatewayAddress = SystemProperties.get(prefix + "gw");
dnsServers[0] = SystemProperties.get(prefix + "dns1");
dnsServers[1] = SystemProperties.get(prefix + "dns2");
if (DBG) {
log("interface=" + interfaceName + " ipAddress=" + ipAddress
+ " gateway=" + gatewayAddress + " DNS1=" + dnsServers[0]
+ " DNS2=" + dnsServers[1]);
}
if (NULL_IP.equals(dnsServers[0]) && NULL_IP.equals(dnsServers[1])
&& !((GSMPhone) phone).isDnsCheckDisabled()) {
// Work around a race condition where QMI does not fill in DNS:
// Deactivate PDP and let DataConnectionTracker retry.
// Do not apply the race condition workaround for MMS APN
// if Proxy is an IP-address.
// Otherwise, the default APN will not be restored anymore.
if (!apn.types[0].equals(Phone.APN_TYPE_MMS)
|| !isIpAddress(apn.mmsProxy)) {
EventLog.writeEvent(TelephonyEventLog.EVENT_LOG_BAD_DNS_ADDRESS,
dnsServers[0]);
phone.mCM.deactivateDataCall(cid, obtainMessage(EVENT_FORCE_RETRY));
return;
}
}
}
onLinkStateChanged(DataLink.LinkState.LINK_UP);
if (DBG) log("PDP setup on cid = " + cid);
}
}
}
private boolean isIpAddress(String address) {
if (address == null) return false;
return Patterns.IP_ADDRESS.matcher(apn.mmsProxy).matches();
}
public ApnSetting getApn() {
return this.apn;
}
}