首页 > Android, Telephony > 一次数据业务错误提示的bug分析

一次数据业务错误提示的bug分析

2011-12-21 20:24 星期三    浏览: 2,930    绿 发表评论 阅读评论

症状描述:使用 3G 上网约半小时后在不关闭数据开关情况下关机,再次开机后第一次使用手机自带 www 浏览器上网,弹出提示框:没有网络连接,未连接到互联网,因此
浏览器无法载入该网页,但 3G 上网图标有下载显示,可以看到网页已经打开。

 

Mobile Data 开关在ConnectivityService.java中设置和获取,搜索MOBILE_DATA关键字。
/**
* @see ConnectivityManager#getMobileDataEnabled()
*/
public boolean getMobileDataEnabled() {
enforceAccessPermission();
boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.MOBILE_DATA, 1) == 1;
if (DBG) Slog.d(TAG, “getMobileDataEnabled returning ” + retVal);
return retVal;
}

/**
* @see ConnectivityManager#setMobileDataEnabled(boolean)
*/
public void setMobileDataEnabled(boolean enabled) {
enforceChangePermission();
if (DBG) Slog.d(TAG, “setMobileDataEnabled(” + enabled + “)”);

mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
(enabled ? ENABLED : DISABLED), 0));
===============================

浏览器开始装载时,在onCreate中获取网络信息NetworkInfo,它是通过ConnectivityManager来进行的。
若网络不是up状态,则提示无网络连接:
in packages/apps/Browser/src/com/android/browser/BrowserActivity.java
public void onCreate(Bundle icicle)

// Find out if the network is currently up.
ConnectivityManager cm = (ConnectivityManager) getSystemService(
Context.CONNECTIVITY_SERVICE);
NetworkInfo info = cm.getActiveNetworkInfo();
if (info != null) {
mIsNetworkUp = info.isAvailable();
}

void onPageStarted(WebView view, String url, Bitmap favicon) {

if (!mIsNetworkUp) createAndShowNetworkDialog();

————————
ConnectivityManager及其service用于获取对应的NetworkStateTracker(如Wifi和3G的网络状态跟踪器)中的NetworkInfo对象:
frameworks/base/core/java/android/net/ConnectivityManager.java

public NetworkInfo getActiveNetworkInfo() {
try {
return mService.getActiveNetworkInfo();
} catch (RemoteException e) {
return null;
}
}

frameworks/base/services/java/com/android/server/ConnectivityService.java

public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
if (mActiveDefaultNetwork != -1) {
return mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
}
return null;
}

frameworks/base/core/java/android/net/NetworkStateTracker.java

public NetworkInfo getNetworkInfo() {
return mNetworkInfo;
}

———————
上层应用是通过获取网络状态信息NetworkInfo中的mIsAvailable来判断的,而该值是通过setIsAvailable来调用的(另外可通过parcel构建NetworkInfo信息,包括该成员变量的赋值,暂不考虑)。
frameworks/base/core/java/android/net/NetworkInfo.java
/**
* Indicates whether network connectivity is possible. A network is unavailable
* when a persistent or semi-persistent condition prevents the possibility
* of connecting to that network. Examples include
* <ul>
* <li>The device is out of the coverage area for any network of this type.</li>
* <li>The device is on a network other than the home network (i.e., roaming), and
* data roaming has been disabled.</li>
* <li>The device’s radio is turned off, e.g., because airplane mode is enabled.</li>
* </ul>
* @return {@code true} if the network is available, {@code false} otherwise
*/
public boolean isAvailable() {
return mIsAvailable;
}

/**
* Sets if the network is available, ie, if the connectivity is possible.
* @param isAvailable the new availability value.
*
* @hide
*/
public void setIsAvailable(boolean isAvailable) {
mIsAvailable = isAvailable;
}

--------------------
针对GPRS/3G的数据状态跟踪器,它里面有个Receiver,该Receiver接收Intent,从Intent提取值来给NetworkInfo赋值:
frameworks/base/core/java/android/net/MobileDataStateTracker.java

private class MobileDataStateReceiver extends BroadcastReceiver {

boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY,
false);

// set this regardless of the apnTypeList. It’s all the same radio/network
// underneath
mNetworkInfo.setIsAvailable(!unavailable);

而该Intent的发送则是通过TelephonyRegistry来进行的,即当数据连接状态改变时,它负责通知:
frameworks/base/services/java/com/android/server/TelephonyRegistry.java

private void broadcastDataConnectionStateChanged(int state,
boolean isDataConnectivityPossible,
String reason, String apn, String[] apnTypes, String interfaceName, String gateway) {
// Note: not reporting to the battery stats service here, because the
// status bar takes care of that after taking into account all of the
// required info.
Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
if (!isDataConnectivityPossible) {
intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, true);
 }

public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
String reason, String apn, String[] apnTypes, String interfaceName, int networkType,
String gateway) {
…..
broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
apnTypes, interfaceName, gateway);
}

通知动作是在DefaultPhoneNotifier中调用的,包括连接是否可用信息
frameworks/base/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java
public void notifyDataConnection(Phone sender, String reason) {
TelephonyManager telephony = TelephonyManager.getDefault();
try {
mRegistry.notifyDataConnection(
convertDataState(sender.getDataConnectionState()),
sender.isDataConnectivityPossible(), reason,
sender.getActiveApn(),
sender.getActiveApnTypes(),
sender.getInterfaceName(null),
((telephony!=null) ? telephony.getNetworkType() :
TelephonyManager.NETWORK_TYPE_UNKNOWN),
sender.getGateway(null));
} catch (RemoteException ex) {
// system process is dead
}
}
--------------------
连接可用信息又是根据GSMPhone(GSM/WCDMA手机)来判断的:
frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java

/**
* The only circumstances under which we report that data connectivity is not
* possible are
* <ul>
* <li>Data roaming is disallowed and we are roaming.</li>
* <li>The current data state is {@code DISCONNECTED} for a reason other than
* having explicitly disabled connectivity. In other words, data is not available
* because the phone is out of coverage or some like reason.</li>
* </ul>
* @return {@code true} if data connectivity is possible, {@code false} otherwise.
*/
public boolean isDataConnectivityPossible() {
// TODO: Currently checks if any GPRS connection is active. Should it only
// check for “default”?
boolean noData = mDataConnection.getDataEnabled() &&
getDataConnectionState() == DataState.DISCONNECTED;
return !noData && getIccCard().getState() == SimCard.State.READY &&
getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());
 }

debug建议:
(1)The phone is in roaming state, but we don’t enable data romaing swtich in Settings UI.
(2)If it’s not (1), please add code in:frameworks/base/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java as the following:
bill@laptop:~/u8500-android-2.3_v4.27/frameworks/base$ git diff
diff –git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index f128f5b..73f3156 100644
— a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1104,6 +1104,15 @@ public class GSMPhone extends PhoneBase {
// check for “default”?
boolean noData = mDataConnection.getDataEnabled() &&
getDataConnectionState() == DataState.DISCONNECTED;
+
+ Log.d(“YCG”, “mDataConnection.getDataEnabled()=”+mDataConnection.getDataEnabled()
+ +”,getDataConnectionState()=”+getDataConnectionState()
+ +”,getIccCard().getState()= “+getIccCard().getState()
+ +”,getServiceState().getState()=”+getServiceState().getState()
+ +”,mDataConnection.getDataOnRoamingEnabled()=”+mDataConnection.getDataOnRoamingEnabled()
+ +”,getServiceState().getRoaming()=”+getServiceState().getRoaming()
+ );
+
return !noData && getIccCard().getState() == SimCard.State.READY &&
getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());

The cause is basically clear. When data connection is down(not up), browser shows the alert dialog.

 

 

=============Log 信息====================

12-15 16:04:34.210 D/YCG ( 1748): mDataConnection.getDataEnabled()=true,getDataConnectionState()=DISCONNECTED,getIccCard().getState()= UNKNOWN,getServiceState().getState()=3,mDataConnection.getDataOnRoamingEnabled()=true,getServiceState().getRoaming()=false

12-15 16:04:34.270 D/YCG ( 1748): mDataConnection.getDataEnabled()=true,getDataConnectionState()=DISCONNECTED,getIccCard().getState()= UNKNOWN,getServiceState().getState()=3,mDataConnection.getDataOnRoamingEnabled()=true,getServiceState().getRoaming()=false

12-15 16:04:36.470 D/YCG ( 1748): mDataConnection.getDataEnabled()=true,getDataConnectionState()=DISCONNECTED,getIccCard().getState()= READY,getServiceState().getState()=1,mDataConnection.getDataOnRoamingEnabled()=true,getServiceState().getRoaming()=false
12-15 16:04:36.470 I/TelephonyRegistry( 1642): notifyServiceState: 1 home null null null (manual) UMTS CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false
12-15 16:04:36.470 I/TelephonyRegistry( 1642): notifyDataConnection: state=0 isDataConnectivityPossible=false reason=null interfaceName=null networkType=3
12-15 16:04:36.480 D/YCG ( 1748): mDataConnection.getDataEnabled()=true,getDataConnectionState()=CONNECTING,getIccCard().getState()= READY,getServiceState().getState()=1,mDataConnection.getDataOnRoamingEnabled()=true,getServiceState().getRoaming()=false
12-15 16:04:36.480 I/TelephonyRegistry( 1642): notifyDataConnection: state=1 isDataConnectivityPossible=false reason=gprsAttached interfaceName=null networkType=3

———–
注:刚开机时:
1.数据连接为DISCONNECTED
2.SIM卡提示为UNKNOWN状态
3.getServiceState().getState()=3 意味着RADIO还未打开。

getServiceState().getState() == ServiceState.STATE_IN_SERVICE

/**
* Normal operation condition, the phone is registered
* with an operator either in home network or in roaming.
*/
public static final int STATE_IN_SERVICE = 0;

/**
* Phone is not registered with any operator, the phone
* can be currently searching a new operator to register to, or not
* searching to registration at all, or registration is denied, or radio
* signal is not available.
*/
public static final int STATE_OUT_OF_SERVICE = 1;

/**
* The phone is registered and locked. Only emergency numbers are allowed. {@more}
*/
public static final int STATE_EMERGENCY_ONLY = 2;

/**
* Radio of telephony is explicitly powered off.
*/
public static final int STATE_POWER_OFF = 3;

开机完成后,还未注册上:getServiceState().getState()=1

12-15 16:05:07.981 D/YCG ( 1748): mDataConnection.getDataEnabled()=true,getDataConnectionState()=CONNECTED,getIccCard().getState()= READY,getServiceState().getState()=1,mDataConnection.getDataOnRoamingEnabled()=true,getServiceState().getRoaming()=false
12-15 16:05:07.981 I/TelephonyRegistry( 1642): notifyDataConnection: state=2 isDataConnectivityPossible=false reason=gprsAttached interfaceName=rmnet0 networkType=3

My Comments1:

After adding my debug code, from the output log, the prompt msg is showed because of “getServiceState().getState()=1″. The value 1 means STATE_OUT_OF_SERVICE: “Phone is not registered with any operator, the phone can be currently searching a new operator to register to, or not searching to registration at all, or registration is denied, or radio signal is not available.”
See the log:
—————————————–
12-15 16:05:07.981 D/YCG ( 1748): mDataConnection.getDataEnabled()=true,getDataConnectionState()=CONNECTED,getIccCard().getState()= READY,getServiceState().getState()=1,mDataConnection.getDataOnRoamingEnabled()=true,getServiceState().getRoaming()=false
12-15 16:05:07.981 I/TelephonyRegistry( 1642): notifyDataConnection: state=2 isDataConnectivityPossible=false reason=gprsAttached interfaceName=rmnet0 networkType=3
—————————————-
So need check further why ServiceState is STATE_OUT_OF_SERVICE.

而设置该状态的有2个地方:
1. GsmServiceStateTracker.java中的 protected void handlePollStateResult (int what, AsyncResult ar) {
见最后一行:
networkType=3 if (states.length > 0) {
try {
regState = Integer.parseInt(states[0]);
if (states.length >= 3) {
if (states[1] != null && states[1].length() > 0) {
lac = Integer.parseInt(states[1], 16);
}
if (states[2] != null && states[2].length() > 0) {
cid = Integer.parseInt(states[2], 16);
}
}
if (states.length > 14) {
if (states[14] != null && states[14].length() > 0) {
psc = Integer.parseInt(states[14], 16);
}
}
} catch (NumberFormatException ex) {
Log.w(LOG_TAG, “error parsing RegistrationState: ” + ex);
}
}

mGsmRoaming = regCodeIsRoaming(regState);
newSS.setState (regCodeToServiceState(regState));

2. private void pollState() {
pollingContext = new int[1];
pollingContext[0] = 0;

switch (cm.getRadioState()) {
case RADIO_UNAVAILABLE:
newSS.setStateOutOfService();
newCellLoc.setStateInvalid();
setSignalStrengthDefaultValues();
mGotCountryCode = false;
pollStateDone();
break;

检查ril log:
在 12-15 16:05:07.981之后 newSS中括号中的地一个值为1(注册上)或5(漫游)才正常:
---------------------
12-15 16:05:08.051 D/GSM ( 1748): Poll ServiceState done: oldSS=[1 home null null null (manual) UMTS CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] newSS=[0 home CHN-UNICOM UNICOM 46001 (manual) UMTS CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] oldGprs=0 newGprs=0 oldType=UMTS newType=UMTS

在之前的两次都正常:
12-15 16:04:35.270 D/GSM ( 1748): Poll ServiceState done: oldSS=[3 home null null null Unknown CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] newSS=[1 home null null null (manual) Unknown CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] oldGprs=1 newGprs=1 oldType=unknown newType=unknown

12-15 16:04:36.470 D/GSM ( 1748): Poll ServiceState done: oldSS=[1 home null null null (manual) Unknown CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] newSS=[1 home null null null (manual) UMTS CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] oldGprs=1 newGprs=0 oldType=unknown newType=UMTS

My comments2:
Root cause is digged out, the registratation state is STATE_OUT_OF_SERVICE because the poll state of the last time is not correct:
the first member value of newSS should be 1(normal) or 5(roaming), but it is 0, which is not normal. we need check why the registration state is not normal, maybe need to check the vaule in requestRegistrationState in u300-ril.c, but I am not sure.
———————————–
12-15 16:05:08.051 D/GSM ( 1748): Poll ServiceState done: oldSS=[1 home null null null (manual) UMTS CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] newSS=[0 home CHN-UNICOM UNICOM 46001 (manual) UMTS CSS not supported -1 -1RoamInd: -1DefRoamInd: -1EmergOnly: false] oldGprs=0 newGprs=0 oldType=UMTS newType=UMTS
———————————–

最后是因为PS业务早于CS注册上,特定平台有差异,Android的framework对其检查较严格导致。所以在判断数据业务是否可用时,去掉一项检查:

index f128f5b..2bfece7 100644
— a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -1104,8 +1104,22 @@ public class GSMPhone extends PhoneBase {
// check for “default”?
boolean noData = mDataConnection.getDataEnabled() &&
getDataConnectionState() == DataState.DISCONNECTED;
+
+ Log.d(“YCG”, “mDataConnection.getDataEnabled()=”+mDataConnection.getDataEnabled()
+ +”,getDataConnectionState()=”+getDataConnectionState()
+ +”,getIccCard().getState()= “+getIccCard().getState()
+ +”,getServiceState().getState()=”+getServiceState().getState()
+ +”,mDataConnection.getDataOnRoamingEnabled()=”+mDataConnection.getDataOnRoamingEnabled()
+ +”,getServiceState().getRoaming()=”+getServiceState().getRoaming()
+ );
+ //The log shows getServiceState().getState()=1″. The value 1 means STATE_OUT_OF_SERVICE. It caused by: CS is unavailable but PS available
+ //It means this prb will occur when CS is later than PS, so we don’t take CS into account when report data conectivity. In fact, it is not
+ //mandatory, PS report info from RIL is enough, I think. —-by YCG, Dec 21 2011
+
return !noData && getIccCard().getState() == SimCard.State.READY &&
- getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&
+ /*getServiceState().getState() == ServiceState.STATE_IN_SERVICE &&*/ //Don’t consider it for ER398936
(mDataConnection.getDataOnRoamingEnabled() || !getServiceState().getRoaming());

本文链接地址: http://blog.redwolf-soft.com/?p=1246

原创文章,版权©红狼博客所有, 转载随意,但请注明出处。

    分享到:

相关文章:

  • 无相关文章
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.
订阅评论
  欢迎参与讨论,请在这里发表您的看法、交流您的观点。