GsmDataConnectiontracker.java中:
private class ApnChangeObserver extends ContentObserver {
public ApnChangeObserver () {
super(mDataConnectionTracker);
}
@Override
public void onChange(boolean selfChange) {
sendMessage(obtainMessage(EVENT_APN_CHANGED));
}
}
handle处理:
case EVENT_APN_CHANGED:
onApnChanged();
break;
调用方法:
/**
* Handles changes to the APN database.
*/
private void onApnChanged() {
boolean isConnected;
isConnected = (state != State.IDLE && state != State.FAILED);
if (hasFwkChangedPreferredApn) {
hasFwkChangedPreferredApn = false;
return;
}
// The "current" may no longer be valid. MMS depends on this to send properly.
mGsmPhone.updateCurrentCarrierInProvider();
// TODO: It'd be nice to only do this if the changed entrie(s)
// match the current operator.
createAllApnList();
if (state != State.DISCONNECTING) {
cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
// reset reconnect timer
mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
trySetupData(Phone.REASON_APN_CHANGED);
}
}
}
private boolean setupData(String reason) {
ApnSetting apn;
GsmDataConnection pdp;
apn = getNextApn();
if (apn == null) return false;
pdp = findFreePdp();
if (pdp == null) {
if (DBG) log("setupData: No free GsmDataConnection found!");
return false;
}
mActiveApn = apn;
mActivePdp = pdp;
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
pdp.connect(msg, apn);
setState(State.INITING);
phone.notifyDataConnection(reason);
return true;
}
DataConnection中:
/**
* 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)));
}
handle处理:
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;
GsmDataConnection。java处理:
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) && (apn.user.length() != 0)) ?
RILConstants.SETUP_DATA_AUTH_PAP_CHAP : RILConstants.SETUP_DATA_AUTH_NONE;
}
String protocol;
if (Phone.REASON_IPV6_FALLBACK.equals(cp.onCompletedMsg.obj)) {
// IPv6 fail, fallback to IPv4
if (DBG) log("IPv6 fail, fallback to IPv4, set protocal to IP");
protocol = "IP";
} else if (phone.getServiceState().getRoaming()) {
protocol = apn.roamingProtocol;
} else {
protocol = apn.protocol;
}
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),
protocol, msg);
}
Ril。java处理:
public void
setupDataCall(String radioTechnology, String profile, String apn,
String user, String password, String authType, String protocol,
Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
rr.mp.writeInt(7);
rr.mp.writeString(radioTechnology);
rr.mp.writeString(profile);
rr.mp.writeString(apn);
rr.mp.writeString(user);
rr.mp.writeString(password);
rr.mp.writeString(authType);
rr.mp.writeString(protocol);
if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ requestToString(rr.mRequest) + " " + radioTechnology + " "
+ profile + " " + apn + " " + user + " "
+ password + " " + authType + " " + protocol);
send(rr);
}
DataConnection处理消息:
case EVENT_SETUP_DATA_CONNECTION_DONE:
724 if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
725
726 ar = (AsyncResult) msg.obj;
727 cp = (ConnectionParams) ar.userObj;
728
729 SetupResult result = onSetupConnectionCompleted(ar);
730 switch (result) {
731 case SUCCESS:
732 // All is well
733 mActiveState.setEnterNotificationParams(cp, FailCause.NONE);
734 transitionTo(mActiveState);
735 break;
736 case ERR_BadCommand:
737 // Vendor ril rejected the command and didn't connect.
738 // Transition to inactive but send notifications after
739 // we've entered the mInactive state.
740 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
741 transitionTo(mInactiveState);
742 break;
743 case ERR_BadDns:
744 // Connection succeeded but DNS info is bad so disconnect
745 EventLog.writeEvent(EventLogTags.PDP_BAD_DNS_ADDRESS, dnsServers[0]);
746 tearDownData(cp);
747 transitionTo(mDisconnectingBadDnsState);
748 break;
749 case ERR_Other:
750 // Request the failure cause and process in this state
751 phone.mCM.getLastDataCallFailCause(
752 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
753 break;
754 case ERR_Stale:
755 // Request is stale, ignore.
756 break;
757 default:
758 throw new RuntimeException("Unkown SetupResult, should not happen");
759 }
760 retVal = true;
761 break;
DcActiveState extends HierarchicalState的方法:
@Override public void enter() {
/**
* Now that we've transitioned to Active state we
* can send notifications. Previously we sent the
* notifications in the processMessage handler but
* that caused a race condition because the synchronous
* call to isActive.
*/
if ((mConnectionParams != null) && (mFailCause != null)) {
log("DcActiveState: enter notifyConnectCompleted");
notifyConnectCompleted(mConnectionParams, mFailCause);
}
}
GsmDataConnectiontracker.java:
protected void onDataSetupComplete(AsyncResult ar) {
String reason = null;
if (ar.userObj instanceof String) {
reason = (String) ar.userObj;
}
if (ar.exception == null) {
// everything is setup
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && preferredApn == null) {
Log.d(LOG_TAG, "PREFERRED APN is null");
preferredApn = mActiveApn;
setPreferredApn(preferredApn.id);
}
} else {
SystemProperties.set("gsm.defaultpdpcontext.active", "false");
}
notifyDefaultData(reason);
// TODO: For simultaneous PDP support, we need to build another
// trigger another TRY_SETUP_DATA for the next APN type. (Note
// that the existing connection may service that type, in which
// case we should try the next type, etc.
} else {
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()) {
GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
cause.ordinal(), loc != null ? loc.getCid() : -1,
TelephonyManager.getDefault().getNetworkType());
}
// set the first default apn to preferred apn.
Boolean enableDefaultPreferredApn = CustomizedValues.getBoolean(
DEFAULT_PREFERRED_APN_PROPERTY, false);
if (enableDefaultPreferredApn && isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
if (canSetPreferApn && preferredApn == null && mActiveApn != null) {
if(DBG) log("set first preferred APN is null");
preferredApn = mActiveApn;
setPreferredApn(preferredApn.id);
}
}
if (!waitingApns.isEmpty()) {
// Count permanent failures and remove the APN we just tried
if (cause.isPermanentFail()
&& !(cause.isIpv6FallBackCause() && mActiveApn != null
&& APN_PROTOCOL_IPV6.equals(mActiveApn.protocol))) {
waitingApnsPermanentFailureCountDown--;
}
waitingApns.remove(0);
}
else {
if (DBG) log("onDataSetupComplete: waitingApns cleared from outside!");
// Consider this a error case, reset the Countdown
waitingApnsPermanentFailureCountDown = 0;
}
if (DBG) log(String.format("onDataSetupComplete: waitingApns.size=%d" +
" waitingApnsPermanenatFailureCountDown=%d",
waitingApns.size(), waitingApnsPermanentFailureCountDown));
// See if there are more APN's to try
if (waitingApns.isEmpty()) {
if (waitingApnsPermanentFailureCountDown == 0) {
if (DBG) log("onDataSetupComplete: Permanent failures stop retrying");
notifyNoData(cause);
phone.notifyDataConnection(Phone.REASON_APN_FAILED);
} else {
if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
startDelayedRetry(cause, reason);
}
} else {
if (DBG) log("onDataSetupComplete: Try next APN");
setState(State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
}
}
}
private class ApnChangeObserver extends ContentObserver {
public ApnChangeObserver () {
super(mDataConnectionTracker);
}
@Override
public void onChange(boolean selfChange) {
sendMessage(obtainMessage(EVENT_APN_CHANGED));
}
}
handle处理:
case EVENT_APN_CHANGED:
onApnChanged();
break;
调用方法:
/**
* Handles changes to the APN database.
*/
private void onApnChanged() {
boolean isConnected;
isConnected = (state != State.IDLE && state != State.FAILED);
if (hasFwkChangedPreferredApn) {
hasFwkChangedPreferredApn = false;
return;
}
// The "current" may no longer be valid. MMS depends on this to send properly.
mGsmPhone.updateCurrentCarrierInProvider();
// TODO: It'd be nice to only do this if the changed entrie(s)
// match the current operator.
createAllApnList();
if (state != State.DISCONNECTING) {
cleanUpConnection(isConnected, Phone.REASON_APN_CHANGED);
if (!isConnected) {
// reset reconnect timer
mRetryMgr.resetRetryCount();
mReregisterOnReconnectFailure = false;
trySetupData(Phone.REASON_APN_CHANGED);
}
}
}
private boolean setupData(String reason) {
ApnSetting apn;
GsmDataConnection pdp;
apn = getNextApn();
if (apn == null) return false;
pdp = findFreePdp();
if (pdp == null) {
if (DBG) log("setupData: No free GsmDataConnection found!");
return false;
}
mActiveApn = apn;
mActivePdp = pdp;
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
msg.obj = reason;
pdp.connect(msg, apn);
setState(State.INITING);
phone.notifyDataConnection(reason);
return true;
}
DataConnection中:
/**
* 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)));
}
handle处理:
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;
GsmDataConnection。java处理:
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) && (apn.user.length() != 0)) ?
RILConstants.SETUP_DATA_AUTH_PAP_CHAP : RILConstants.SETUP_DATA_AUTH_NONE;
}
String protocol;
if (Phone.REASON_IPV6_FALLBACK.equals(cp.onCompletedMsg.obj)) {
// IPv6 fail, fallback to IPv4
if (DBG) log("IPv6 fail, fallback to IPv4, set protocal to IP");
protocol = "IP";
} else if (phone.getServiceState().getRoaming()) {
protocol = apn.roamingProtocol;
} else {
protocol = apn.protocol;
}
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),
protocol, msg);
}
Ril。java处理:
public void
setupDataCall(String radioTechnology, String profile, String apn,
String user, String password, String authType, String protocol,
Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
rr.mp.writeInt(7);
rr.mp.writeString(radioTechnology);
rr.mp.writeString(profile);
rr.mp.writeString(apn);
rr.mp.writeString(user);
rr.mp.writeString(password);
rr.mp.writeString(authType);
rr.mp.writeString(protocol);
if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ requestToString(rr.mRequest) + " " + radioTechnology + " "
+ profile + " " + apn + " " + user + " "
+ password + " " + authType + " " + protocol);
send(rr);
}
DataConnection处理消息:
case EVENT_SETUP_DATA_CONNECTION_DONE:
724 if (DBG) log("DcActivatingState msg.what=EVENT_SETUP_DATA_CONNECTION_DONE");
725
726 ar = (AsyncResult) msg.obj;
727 cp = (ConnectionParams) ar.userObj;
728
729 SetupResult result = onSetupConnectionCompleted(ar);
730 switch (result) {
731 case SUCCESS:
732 // All is well
733 mActiveState.setEnterNotificationParams(cp, FailCause.NONE);
734 transitionTo(mActiveState);
735 break;
736 case ERR_BadCommand:
737 // Vendor ril rejected the command and didn't connect.
738 // Transition to inactive but send notifications after
739 // we've entered the mInactive state.
740 mInactiveState.setEnterNotificationParams(cp, result.mFailCause);
741 transitionTo(mInactiveState);
742 break;
743 case ERR_BadDns:
744 // Connection succeeded but DNS info is bad so disconnect
745 EventLog.writeEvent(EventLogTags.PDP_BAD_DNS_ADDRESS, dnsServers[0]);
746 tearDownData(cp);
747 transitionTo(mDisconnectingBadDnsState);
748 break;
749 case ERR_Other:
750 // Request the failure cause and process in this state
751 phone.mCM.getLastDataCallFailCause(
752 obtainMessage(EVENT_GET_LAST_FAIL_DONE, cp));
753 break;
754 case ERR_Stale:
755 // Request is stale, ignore.
756 break;
757 default:
758 throw new RuntimeException("Unkown SetupResult, should not happen");
759 }
760 retVal = true;
761 break;
DcActiveState extends HierarchicalState的方法:
@Override public void enter() {
/**
* Now that we've transitioned to Active state we
* can send notifications. Previously we sent the
* notifications in the processMessage handler but
* that caused a race condition because the synchronous
* call to isActive.
*/
if ((mConnectionParams != null) && (mFailCause != null)) {
log("DcActiveState: enter notifyConnectCompleted");
notifyConnectCompleted(mConnectionParams, mFailCause);
}
}
GsmDataConnectiontracker.java:
protected void onDataSetupComplete(AsyncResult ar) {
String reason = null;
if (ar.userObj instanceof String) {
reason = (String) ar.userObj;
}
if (ar.exception == null) {
// everything is setup
if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
SystemProperties.set("gsm.defaultpdpcontext.active", "true");
if (canSetPreferApn && preferredApn == null) {
Log.d(LOG_TAG, "PREFERRED APN is null");
preferredApn = mActiveApn;
setPreferredApn(preferredApn.id);
}
} else {
SystemProperties.set("gsm.defaultpdpcontext.active", "false");
}
notifyDefaultData(reason);
// TODO: For simultaneous PDP support, we need to build another
// trigger another TRY_SETUP_DATA for the next APN type. (Note
// that the existing connection may service that type, in which
// case we should try the next type, etc.
} else {
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()) {
GsmCellLocation loc = ((GsmCellLocation)phone.getCellLocation());
EventLog.writeEvent(EventLogTags.PDP_SETUP_FAIL,
cause.ordinal(), loc != null ? loc.getCid() : -1,
TelephonyManager.getDefault().getNetworkType());
}
// set the first default apn to preferred apn.
Boolean enableDefaultPreferredApn = CustomizedValues.getBoolean(
DEFAULT_PREFERRED_APN_PROPERTY, false);
if (enableDefaultPreferredApn && isApnTypeActive(Phone.APN_TYPE_DEFAULT)) {
if (canSetPreferApn && preferredApn == null && mActiveApn != null) {
if(DBG) log("set first preferred APN is null");
preferredApn = mActiveApn;
setPreferredApn(preferredApn.id);
}
}
if (!waitingApns.isEmpty()) {
// Count permanent failures and remove the APN we just tried
if (cause.isPermanentFail()
&& !(cause.isIpv6FallBackCause() && mActiveApn != null
&& APN_PROTOCOL_IPV6.equals(mActiveApn.protocol))) {
waitingApnsPermanentFailureCountDown--;
}
waitingApns.remove(0);
}
else {
if (DBG) log("onDataSetupComplete: waitingApns cleared from outside!");
// Consider this a error case, reset the Countdown
waitingApnsPermanentFailureCountDown = 0;
}
if (DBG) log(String.format("onDataSetupComplete: waitingApns.size=%d" +
" waitingApnsPermanenatFailureCountDown=%d",
waitingApns.size(), waitingApnsPermanentFailureCountDown));
// See if there are more APN's to try
if (waitingApns.isEmpty()) {
if (waitingApnsPermanentFailureCountDown == 0) {
if (DBG) log("onDataSetupComplete: Permanent failures stop retrying");
notifyNoData(cause);
phone.notifyDataConnection(Phone.REASON_APN_FAILED);
} else {
if (DBG) log("onDataSetupComplete: Not all permanent failures, retry");
startDelayedRetry(cause, reason);
}
} else {
if (DBG) log("onDataSetupComplete: Try next APN");
setState(State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
sendMessageDelayed(obtainMessage(EVENT_TRY_SETUP_DATA, reason), APN_DELAY_MILLIS);
}
}
}