您的位置:首页 > 移动开发 > Android开发

Android启用GPRS成功后反馈流程(MTK)

2015-03-03 10:02 483 查看
看此篇看不太懂的同志们可以先看看我另一篇文章:http://blog.csdn.net/yankebin/article/details/44035489

理解了建立GPRS通信的流程再来看这篇文章就相对来说好理解了

android通信流程本身就是一个很复杂的问题,我只是以我工作过程中遇到的细节为主要线索,理一理整个过程中需要注意的地方,如有错误和不当,还望大家海涵和指正。

(1).先回过头来看看数据网络开启过程中的CdmaDataConnection和GsmDataConnection中的onConnect()方法,该方法中在调用RIL的setupDataCall()时,传入了标识为EVENT_SETUP_DATA_CONNECTION_DONE 的Message,在RIL的setupDataCall()使用该Message获取了RILRequest的实例并将该message作为RIL Parcel的第一个元素写入到其中。

RILRequest rr = RILRequest. obtain(RIL_REQUEST_SETUP_DATA_CALL, result);

该obtain方法作用是从池中检索一个新的RILRequest实例,第一个参数是定义在RILConstants中以RIL_REQUEST_打头的整型值,第二个参数是操作完成后要发送的东西。由此看来之前标识EVENT_SETUP_DATA_CONNECTION_DONE 的Message会在执行完后将发送出去。RILRequest,代表着一个即将发送出去的RIL请求,它里面包含了Request请求号、序列号(自0开始累加)和保存请求结果的Message。

/**

* Retrieves a new RILRequest instance from the pool.

*

* @param request RIL_REQUEST_*

* @param result sent when operation completes

* @return a RILRequest instance from the pool.

*/

static RILRequest obtain( int request, Message result) {

RILRequest rr = null;

synchronized(sPoolSync ) {

if (sPool != null) {

rr = sPool;

sPool = rr.mNext ;

rr. mNext = null;

sPoolSize--;

}

}

if (rr == null) {

rr = new RILRequest();

}

synchronized(sSerialMonitor ) {

rr. mSerial = sNextSerial++;

}

rr. mRequest = request;

rr. mResult = result;

rr. mp = Parcel.obtain();

//这里要求message不能为空,并且已经关联了相应的handler,看来在执行完操作之后发送的消息将由此handler接收并处理


if (result != null && result.getTarget() == null) {

throw new NullPointerException("Message target must not be null");

}


// first elements in any RIL Parcel

rr. mp.writeInt(request);

rr. mp.writeInt(rr.mSerial );

return rr;

}


(2).当RILSender发送一个RIL请求后(即Android启动GPRS流程(MTK)中(21)的send方法),rild收到请求后会进行分发,发送AT命令,若AT命令没有得到响应回复(分为2种,请求回应和主动上报),rild的分发线程被阻塞,java部分的RIL请求送出去后将得不到处理。当RIL请求得到正常处理时,RILReciver所在的线程(在RIL的构造方法中初始化)将接收到回送的response消息,并进行解析。

//***** Instance Variables

//定义在RIL类中的成员变量

LocalSocket mSocket;

HandlerThread mSenderThread;/

RILSender mSender;

Thread mReceiverThread;

RILReceiver mReceiver;

------------------------------------------------------------------

public RIL(Context context, int preferredNetworkType, int cdmaSubscription) {
super(context);
if (RILJ_LOGD) {
riljLog("RIL(context, preferredNetworkType=" + preferredNetworkType +
" cdmaSubscription=" + cdmaSubscription + ")");
}    mCdmaSubscription  = cdmaSubscription;
mPreferredNetworkType = preferredNetworkType;
mPhoneType = RILConstants.NO_PHONE;

PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
mWakeLock.setReferenceCounted(false);
mWakeLockTimeout = SystemProperties.getInt(TelephonyProperties.PROPERTY_WAKE_LOCK_TIMEOUT,
DEFAULT_WAKE_LOCK_TIMEOUT);
mRequestMessagesPending = 0;
mRequestMessagesWaiting = 0;
//初始化SenderThread,RILSender
mSenderThread = new HandlerThread("RILSender");
mSenderThread.start();

Looper looper = mSenderThread.getLooper();
mSender = new RILSender(looper);

ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
Context.CONNECTIVITY_SERVICE);
if (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) {
riljLog("Not starting RILReceiver: wifi-only");
} else {
riljLog("Starting RILReceiver");

//初始化RILReceiver和mReceiverThread

mReceiver = new RILReceiver();
mReceiverThread = new Thread(mReceiver, "RILReceiver");
mReceiverThread.start();

IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
context.registerReceiver(mIntentReceiver, filter);
}
}


(3).RILReceiver实现了Runnable。因此这里消息的接收应该在重写的run方法中。该方法中先用一个外层的死循环来连接socket套接字的端点(endPoint,不太懂),但通过 s.connect(l);可能会连接不成功(原因不是很理解,之后再查吧),因此这里如果尝试不成功,会终止执行后面的代码,开始下一次循环,记录尝试次数的变量retryCount 在这里没有看到太大用处,仅是用来根据其值输出相应的日志信息,连接成功后,重置了该retryCount,并将套接字赋值给了全局的变量mSocket ,此后开始其嵌套的内层死循环。内层死循环是从socket中获取到rild的响应,通过readRilMessage(InputStream is, byte[] buffer)将回应写入到buffer缓冲区里,并返回消息的长度,之后再通过 p.unmarshall( buffer , 0, length)得到原始的字节(发送的时候进行了marshall处理),接下来就是通过 processResponse(p)进行消息的处理了,之后先设置当前radio的状态,再关闭socket,重置RILRequest的序列号,并放回RILRequest池里,清空mRequestsList ,最后再用notifyRegistrantsRilConnectionChanged通知所有的registrants(应该是监听ril的吧,具体细节不知),ril已经连接或者断开,当然这里是通知断开了。

public void run() {

int retryCount = 0;

String socketRil = getRilSocketName( mySimId);

try {

for (;;) {//外层死循环,用来处理socket的连接

LocalSocket s = null;

LocalSocketAddress l;

socketRil = getRilSocketName( mySimId);

..........

try {

s = new LocalSocket();

l = new LocalSocketAddress(socketRil,

LocalSocketAddress.Namespace. RESERVED);

s.connect(l);

} catch (IOException ex){

try {

if (s != null) {

s.close();

}

} catch (IOException ex2) {

//ignore failure to close after failure to connect

}

// don't print an error message after the the first time

// or after the 8th time

//官方源码这里值是8,注释也可以看出来,这里MTK做了修改,将值增大到16

if (retryCount == 16) {

Log. e (LOG_TAG,

"Couldn't find '" + socketRil

+ "' socket after " + retryCount

+ " times, continuing to retry silently" );

} else if (retryCount > 0 && retryCount < 16) {

Log. i (LOG_TAG,

"Couldn't find '" + socketRil

+ "' socket; retrying after timeout" );

}

try {

Thread. sleep(SOCKET_OPEN_RETRY_MILLIS);

} catch (InterruptedException er) {

}

retryCount++;

continue;

}

retryCount = 0;

mSocket = s;

Log. i(LOG_TAG, "Connected to '" + socketRil + "' socket" );

int length = 0;

try {

InputStream is = mSocket.getInputStream();

for (;;) { //内层死循环用来从输入流中读取数据

Parcel p;

//readRilMessage是把以 little-endian 存储的数据还原到本来的样子

//以 little-endian 存储时,数据低位存储在内存低地址,数据高位存储在内存高地址;

//read(buffer, offset, remaining); 读入 remaining 长度的流数据;
//JVM 用 little-endian 存储 int 型的 messageLength ,所以得用位操作转换一下

length = readRilMessage(is, buffer);

if (length < 0) {

// End-of-stream reached

break;

}
p = Parcel. obtain();
p.unmarshall( buffer, 0, length);//返回原始字节数据
p.setDataPosition(0);
//Log.v(LOG_TAG, "Read packet: " + length + " bytes");
processResponse(p);//处理回应
p.recycle();
}
} catch (java.io.IOException ex) {
Log. i(LOG_TAG, "'" + socketRil + "' socket closed" ,
ex);
} catch (Throwable tr) {
Log. e(LOG_TAG, "Uncaught exception read length=" + length +
"Exception:" + tr.toString());
}
Log. i(LOG_TAG, "Disconnected from '" + socketRil
+ "' socket");
setRadioState (RadioState. RADIO_UNAVAILABLE);//存储新的radio状态为无效状态并发送通知
try {
mSocket.close();
} catch (IOException ex) {
}
mSocket = null;
RILRequest. resetSerial();//重置序列号
// Clear request list on close
synchronized (mRequestsList ) {
for (int i = 0, sz = mRequestsList.size() ; i < sz ; i++) {
RILRequest rr = mRequestsList.get(i);
rr.onError( RADIO_NOT_AVAILABLE, null );
rr.release();//将RILRequest放回池中
}
mRequestsList.clear(); //清理请求列表
}
}} catch (Throwable tr) {
Log. e(LOG_TAG, "Uncaught exception", tr);
}
//MTK-END [mtk04070][111121][ALPS00093395]Refined for supporting Gemini
/* We're disconnected so we don't know the ril version */
notifyRegistrantsRilConnectionChanged(-1);//通知所有的Registrants,ril的连接状态改变
}


(4).接下来看一下 processResponse(p)这里的操作。主要是对消息的处理,这里的分支是因为为了匹配定义在ril.cpp的常量值也就是AT的response的两个分类,这两个值分别是:RESPONSE_SOLICITED请求响应(对ril的请求响应,比如这里的开启数据网络)和RESPONSE_UNSOLICITED非请求响应(主动响应,主动上报的,比如网络状态,短信,来电等)。因此processSolicited (p)是对数据网络请求的回应的处理。之后调用releaseWakeLockIfDone释放唤醒锁(唤醒锁是一种机制用来表示有应用程序需要设备留在唤醒状态)。

private void processResponse (Parcel p) {
int type;
type = p.readInt();
//MTK修改开始
/* Solve [ALPS00308613]Receive incoming VT call causes EE, mtk04070, 20120628 */
if (mIsFirstResponse &&
((type == RESPONSE_UNSOLICITED) || (type == RESPONSE_SOLICITED))) {
if (FeatureOption.MTK_VT3G324M_SUPPORT == false) {
Log. d(LOG_TAG, "FeatureOption.MTK_VT3G324M_SUPPORT == false" );
disableVTCapability();
}
mIsFirstResponse = false;
}
//MTK修改结束
if (type == RESPONSE_UNSOLICITED) {
processUnsolicited (p);
} else if (type == RESPONSE_SOLICITED) {
processSolicited (p);
}
releaseWakeLockIfDone();
}


(5).processSolicited(p)方法对响应进行处理。方法中从parcel读取数据,根据读取的serial(从Android启用GPRS流程(MTK)的(21)中加入到mRequestsList)使用findAndRemoveRequestFromList找到RILRequest实例,再根据RILRequest的request值找到相应的分支。根据在setupDataCall(Android启用GPRS流程(MTK) (20) )请求的code是RIL_REQUEST_SETUP_DATA_CALL找到该分支。该该分支中调用了responseSetupDataCall(p)方法对响应的结果进行解析,包括ip地址,网关,dns等等。如果解析发现有错误,将抛出异常。不管是否存在异常,都会将AR执行的返回结果放置到AsyncResult中,并赋值给RILRequest中的Message的obj,再通过sendToTarget()发送给调用者处理。这里的Mssage最初是在GsmDataConnection或CdmaDataConnection中的onConnect()方法中创建的,其关联的handler是StateMachine.java中的SmHandler,因此最终的消息处理在DataConnection.java中。进入到DataConnection.java,找到处理Message.what为EVENT_SETUP_DATA_CONNECTION_DONE的地方。

private void processSolicited (Parcel p) {

int serial, error;

boolean found = false;

serial = p.readInt();

error = p.readInt();

RILRequest rr;

rr = findAndRemoveRequestFromList(serial);

if (rr == null) {

Log. w(LOG_TAG, "Unexpected solicited response! sn: "

+ serial + " error: " + error);

return;

}


………..

if (error == 0 || p.dataAvail() > 0) {

// either command succeeds or command fails but with data payload

try {switch (rr.mRequest) {

/*


cat libs/telephony/ril_commands.h \

| egrep “^ *{RIL_” \

| sed -re ‘s/{([^,]+),[^,]+,([^}]+).+/case \1: ret = \2(p); break;/’

*/

//接下来非常多的RIL请求处理,目测有几十种(这里省略部分)

case RIL_REQUEST_GET_SIM_STATUS : ret =  responseIccCardStatus(p); break;

.........

case RIL_REQUEST_SEND_SMS : ret =  responseSMS(p); break;

case RIL_REQUEST_SEND_SMS_EXPECT_MORE : ret =  responseSMS(p); break;

case RIL_REQUEST_SETUP_DATA_CALL : ret =  responseSetupDataCall(p); break;

.....

case RIL_REQUEST_QUERY_MODEM_TYPE : ret = responseInts(p); break;

default:

throw new RuntimeException("Unrecognized solicited response: " + rr. mRequest);

//break;

}} catch (Throwable tr) {

// Exceptions here usually mean invalid RIL responses

//解析发现RILResponse存在错误,就会抛出异常

Log. w(LOG_TAG, rr.serialString() + "< "

+ requestToString(rr.mRequest)

+ " exception, possible invalid RIL response" , tr);

if (rr.mResult != null) {//只要message不为空,仍然将其回送到调用者并由其进行处理

AsyncResult. forMessage(rr.mResult, null, tr);//使用新构造一个AsyncResult ,并赋值给message的obj对象

rr. mResult.sendToTarget();

}

rr.release();//将RILRequest放回池中

return;

}

}

if (error != 0) {

rr.onError(error, ret);

rr.release();

return;

}

if (RILJ_LOGD ) riljLog(rr.serialString() + "< " + requestToString(rr.mRequest)

+ " " + retToString(rr.mRequest , ret));

if (rr.mResult != null) {

//解析正常,并且message存在,将AT执行的返回结果放到AsyncResult中,并赋值rr. mResult的obj,再由sendToTarget()回送到调用者并由其进行处理

AsyncResult. forMessage(rr.mResult, ret, null);//赋值到rr.mResult的obj对象

rr. mResult.sendToTarget();

}

rr.release();

}


//使用异常和处理的结果,及消息,新构造一个AsyncResult ,并赋值给message的obj对象,该变了obj的值,obj就包含了更多信息。

/* Saves and sets m.obj /

public static AsyncResult

forMessage (Message m, Object r, Throwable ex)

{

AsyncResult ret;

//此时m.obj是

ret = new AsyncResult (m.obj , r, ex);

m. obj = ret;

return ret;

}


(6).DataConnection.java对EVENT_SETUP_DATA_CONNECTION_DONE的处理在DcActivatingState的processMessage()方法中。说明当ril的消息返回时,此时的连接状态正处在激活中。msg当中包含的obj就是在上AsyncResult. forMessage()处理之后的AsyncResult,而AsyncResult中的userObj实际上就是在GsmDataConnection/CdmaDataConnection的OnConnect()方法当中封装到Message当中的ConnectionParams。如果在RIL.java中处理AT的响应详细有异常,AsyncResult中的成员变量result将为null,如果没有异常则成员变量exception为null ,当从消息之中获取到这些消息后,调用onSetupConnectionCompleted方法对AsyncResult进行处理和分类。只有当结果为 DataCallState.SetupResult为SUCCESS时才会切换到ActiveState状态.在切换到ActiveState状态之前,先通过setEnterNotificationParams()方法将连接参数cp和failCause设置给DcActiveState状态的成员变量mConnectionParams和mFailCause,在transitionTo到Activestate后,将会在其enter()方法中调用notifyConnectCompleted()将连接成功的消息发送出去。

/**

* The state machine is activating a connection.

*/

private class DcActivatingState extends State {

@Override

public boolean processMessage(Message msg) {

boolean retVal;

AsyncResult ar;

ConnectionParams cp;

........

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;

DataCallState.SetupResult result = onSetupConnectionCompleted(ar);

if (DBG ) log("DcActivatingState onSetupConnectionCompleted result=" + result);

switch (result) {

case SUCCESS :

// All is well

mActiveState.setEnterNotificationParams(cp, FailCause.NONE);

transitionTo( mActiveState);

break;

case ERR_BadCommand ://指令错误

// Vendor ril rejected the command and didn't connect.

// Transition to inactive but send notifications after

// we've entered the mInactive state.

mInactiveState.setEnterNotificationParams(cp, result.mFailCause, -1);

transitionTo( mInactiveState);

break;

case ERR_UnacceptableParameter :

// The addresses given from the RIL are bad

tearDownData(cp);

transitionTo( mDisconnectingErrorCreatingConnection );

break;

case ERR_GetLastErrorFromRil :

//获取到了上一次RIL请求的消息,然后会切换到mInactiveState状态去

// Request failed and this is an old RIL

phone.mCM .getLastDataCallFailCause(

obtainMessage( EVENT_GET_LAST_FAIL_DONE, cp));

break;

case ERR_RilError ://ril层存在错误

// Request failed and mFailCause has the reason

mInactiveState.setEnterNotificationParams(cp, result.mFailCause,

getSuggestedRetryTime(ar));

transitionTo( mInactiveState);

break;

case ERR_Stale :

// Request is stale, ignore.

break;

default:

throw new RuntimeException("Unknown SetupResult, should not happen");

}

retVal = HANDLED;

break;

........


}

(7).看看onSetupConnectionCompleted()方法都做是怎么做的处理吧。先根据成员变量exception是否为null判断。如果不为null根据exception的类型,判断是属于何种异常则关联上相应的失败原因。如果为null,则判断连接参数的tag值与当前的tag值是否一致(该值在DataConnection的DcInactiveState中的enter方法修改值并在EVENT_CONNECT发生时,放置到了ConnectionParams中),一致则说明是同一次网络开启请求的处理,否则则认为本次响应的信息是错误的。即没有异常,tag值也能匹配,并且响应的staus是正确的,说明本次开启操作正确,接下来更新使用updateLinkProperty()方法更新LinkProperties(包括HttpProxy,会调用DataCallState中的setLinkProperties()方法,将DataCallState的成员变量ifname,addresses, dnses ,gateways 等关联到LinkProperties中,ifname就是interface name对应apn创建成功之后的网络设备名),并将状态机切换到ActiveState状态。

private DataCallState.SetupResult onSetupConnectionCompleted (AsyncResult ar) {

DataCallState response = (DataCallState) ar.result;

ConnectionParams cp = (ConnectionParams) ar.userObj;

DataCallState.SetupResult result;

if(ar.exception!=null) {

if(DBG) {

log("onSetupConnectionCompleted failed, ar.exception="+ ar.exception+

" response="+ response);

}

if(ar.exceptioninstanceofCommandException

&& ((CommandException) (ar.exception)).getCommandError()

== CommandException.Error.RADIO_NOT_AVAILABLE) {

result = DataCallState.SetupResult.ERR_BadCommand;

result.mFailCause= FailCause.RADIO_NOT_AVAILABLE;

}elseif((response ==null) || (response.version< 4)) {

result = DataCallState.SetupResult.ERR_GetLastErrorFromRil;

}else{

result = DataCallState.SetupResult.ERR_RilError;

result.mFailCause= FailCause.fromInt(response.status);

}

}elseif(cp.tag!=mTag) {//在EVENT_CONNECT发送时,mtag赋值到cp的tag,这里进行匹配判断,确定是否是同一次操作

if(DBG) {

log("BUG: onSetupConnectionCompleted is stale cp.tag="+ cp.tag+", mtag="+mTag);

}

result = DataCallState.SetupResult.ERR_Stale;

}elseif(response.status!= 0) {

result = DataCallState.SetupResult.ERR_RilError;

result.mFailCause= FailCause.fromInt(response.status);

}else{//

if(DBG) log("onSetupConnectionCompleted received DataCallState: "+ response);

cid= response.cid;

result = updateLinkProperty(response).setupResult;

}

return result;

}


(8).根据notifyConnectCompleted()名,明显可以知道该方法是通知网络连接完成用的。那来看看这个方法都做了些啥子东西。是怎么把消息发送出去的。

private void notifyConnectCompleted(ConnectionParams cp, FailCause cause) {

Log. e("YKB","notifyConnectCompleted-->ConnectionParams "+cp.apn.toString()+" msg:"+ cp.onCompletedMsg.toString());

Message connectionCompletedMsg = cp.onCompletedMsg;

if(connectionCompletedMsg==null) {

return;

}

longtimeStamp = System.currentTimeMillis();

//cid是上面第(7)点从response中取出的成员变量cid ;根据DataCallState注释说是在ril.h中的,

//查到源码目 录/hardware/ril/include/telephony/ril.h,

//找到cid的注释为:Context ID, uniquely identifies this call

connectionCompletedMsg.arg1=cid;

if(cause == FailCause.NONE) {

createTime= timeStamp;

AsyncResult. forMessage(connectionCompletedMsg);

}else{

lastFailCause= cause;

lastFailTime= timeStamp;

AsyncResult. forMessage(connectionCompletedMsg, cause,

newCallSetupException(mRetryOverride));

}

if(DBG) log("notifyConnectionCompleted at "+ timeStamp +" cause="+ cause);

connectionCompletedMsg.sendToTarget();

}


方法先从cp中取相应的Message,这个message是哪儿来的呢,回忆一下。在Android 启用GPRS流程(MTK)中,当DataConnection.java的bringUp()方法时将传递过来的参数message和apnStting封装成了ConnectionParams,所以这里判断的cp. onCompletedMsg就是传递给bringUp的那个参数Message,好吧。再回忆一下,这个message是在哪儿传给bringUp()的。实际上这个message是在CdmaDataConnectionTracker和GsmDataConnectionTracker中的setupData()方法中进行构造的。

Message msg = obtainMessage();

msg.what= DctConstants.EVENT_DATA_SETUP_COMPLETE;

msg.obj= reason;

conn. bringUp(msg,mActiveApn) ;


接下来将唯一标识当前数据请求的id放置在message的arg1中,并根据记录下当前的时间戳,然后将该Message又构造成一个一个AsyncResult实例。(为什么要构造成AsyncResult来进行传递,不是很明白)发送给相应的handler进行处理。由于在构造message时是使用的GsmDataConnectionTracker.java和CdmaDataConnectionTracker.java的obtainMessage方法,而这两个Tracker继承自DataConnectionTracker而DataConnectionTracker又继承自Handler,因此该消息将在DataConnectionTracker中进行处理。

(9).DataConnectionTracker.java中的handleMessage方法中找到分支

(/frameworks/opt/telephony/src/java/com/android/internal/telephony/DataConnectionTracker.java)

case DctConstants.EVENT_DATA_SETUP_COMPLETE:

mCidActive= msg.arg1;

onDataSetupComplete((AsyncResult) msg.obj);

break;


看到将arg1(也就是唯一的请求标识cid)赋值给了成员变量mCidActive 。比较简单没什么说的,接下来还是看onDataSetupComplete()方法。不出意外的肯定又会分支到CdmaDataConnectionTracker和GsmDataConnectionTracker。

(10).先看CdmaDataConnectionTracker中onDataSetupComplete()方法吧

protected void onDataSetupComplete(AsyncResult ar) {

String reason =null;

if(ar.userObjinstanceofString) {

reason = (String) ar.userObj;

}

if(isDataSetupCompleteOk(ar)) {

// Everything is setup

notifyDefaultData(reason);

}else{

FailCause cause = (FailCause) (ar.result);

if(DBG) log("Data Connection setup failed "+ cause);

// No try for permanent failure

if(cause.isPermanentFail()) {

notifyNoData(cause);

return;

}

intretryOverride = -1;

if(ar.exceptioninstanceofDataConnection.CallSetupException) {

retryOverride =

((DataConnection.CallSetupException)ar.exception).getRetryOverride();

}

if(retryOverride == RILConstants.MAX_INT) {

if(DBG) log("No retry is suggested.");

}else{

startDelayedRetry(cause, reason, retryOverride);

}

}

}


首先是将AsyncResult的uerObj成员变量取出来(CdmaDataConnectionTracker在构造EVENT_DATA_SETUP_COMPLETE时,传递的reason是字符串,而GsmDataConnectionTracker传递是ApnContext)。稍后使用DataConnectionTracker中的isDataSetupCompleteOk()对AsyncResult进行是否创建完成的判断。

protected boolean isDataSetupCompleteOk(AsyncResult ar) {

if(ar.exception!=null) {

if(DBG) log("isDataSetupCompleteOk return false, ar.result="+ ar.result);

returnfalse;

}

if(mFailDataSetupCounter<= 0) {

if(DBG) log("isDataSetupCompleteOk return true");

returntrue;

}

ar.result=mFailDataSetupFailCause;

if(DBG) {

log("isDataSetupCompleteOk return false"+

" mFailDataSetupCounter="+mFailDataSetupCounter+

" mFailDataSetupFailCause="+mFailDataSetupFailCause);

}

mFailDataSetupCounter-= 1;

returnfalse;

}


由于在成功返回构造AsyncResult只使用了Message,因此这里AsyncResult的exception成员变量必定为null,接下来是通过判断CdmaDataConnectionTracker的成员变量mFailDataSetupCounter来决定数据连接的创建返回值。而mFailDataSetupCounter的值只有在接收到广播

// Used for debugging. Send the INTENT with an optional counter value with the number

// of times the setup is to fail before succeeding. If the counter isn’t passed the

// setup will fail once. Example fail two times with FailCause.SIGNAL_LOST(-3)

// adb shell am broadcast \

// -a com.android.internal.telephony.dataconnectiontracker.intent_set_fail_data_setup_counter \

// –ei fail_data_setup_counter 3 – ei fail_data_setup_fail_cause -3

protectedstaticfinalStringINTENT_SET_FAIL_DATA_SETUP_COUNTER=

"com.android.internal.telephony.dataconnectiontracker. intent_set_fail_data_setup_counter";


时才会改变。根据该广播的注释可知它是用于调试的,用来记录接续之前建立数据失败的次数。实际上这里没什么用,所以这里通常都是返回成功的。因此将直接调用notifyDefaultData(String reason)通知网络状态改变了。

privatevoidnotifyDefaultData(String reason) {

setState(DctConstants.State.CONNECTED);//修改状态,在setState中会将CdmaDataConnectionTracker成员变量mState标记为Connected

notifyDataConnection(reason);//会调用到DataConnectionTracker.java中,该方法用来发送通知-所有活动的apn当前数据连接状态。


和GsmDataConnectionTracker不同,GsmDataConnectionTracker重写了这个方法。

startNetStatPoll();//开始NetStat投票(作用不明确,暂时未理解)

startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);//启动数据失速警报(大概是在指定的一个时间后发出一个广播INTENT_DATA_STALL_ALARM 这个指定的时间从Settings.Global取出)

mDataConnections.get(0).resetRetryCount();//重置尝试次数为0

}


notifyDataConnection(reason);调用的是DataConnectionTracker.java方法,在该方法中通过PhoneBase的notifyDataConnection(string,string)把消息传递出去。

protected void notifyDataConnection(String reason) {

for(intid = 0; id < DctConstants.APN_NUM_TYPES; id++) {

// Only active apns' state changed

if(dataEnabled[id] &&mActiveApn!=null

&&mActiveApn.canHandleType(apnIdToType(id))) {

mPhone.notifyDataConnection(reason, apnIdToType(id));

}

}

notifyOffApnsOfAvailability(reason);

}


再回到onDataSetupComplete(AsyncResult ar),如果失败了,根据参数中ar携带的FailCause进行分支处理,如果FailCause是固定错误,则不会进行失败尝试(MTK这里进行了修改,cause.isPermanentFail()始终返回的为false),如果ar携带的异常类型是DataConnection.CallSetupException,则从取该异常的成员变量mRetryOverride进行重试数据建立建立

(11).回到GsmDataConnectionTracker.java的onDataSetupComplete(AsyncResult ar).由于在GsmDataConnectionTracker中的setupData()方法中进行构造Message传递的message的obj对象是ApnContext,因此这里首先从ar中取出userobj进行类型判断和强转,如果类型不匹配,将抛出异常,反之则得到一个ApnConext实例。和CdmaDataConnectionTracker一样,也是调用DataConnectionTracker的isDataSetupCompleteOk(ar)对数据连接完成进行确认的判断,若为false则需要进行相应的处理,处理之后使用trySetupData()方法对建立数据连接进行重试。如果为ture,则从apnContext中取出DataConnectionAc实例,该实例是用来在不同handler之间进行消息传递的通道,这个DataConnectionAc的设置是在setupData(ApnContext apnContext)进行的,如果该实例不存在,则存在该错误,并进行数据连接重试,若存在,则再从apnContext中取出DataConnection和apnSetting的实例,并根据apnSetting中包含的端口号,代理信息构造ProxyProperties ,再由DataConnectionAc更新到当前LinkProperties上去。最后判断一下当前的连接是不是default连接,并更新systemProperties(gsm.defaultpdpcontext.active),如果是默认连接且mPreferredApn 尚为设置,则更新mPreferredApn 的引用。最后通过notifyDefaultData(apnContext)通知当前数据连接状态;

@Override
protected void onDataSetupComplete(AsyncResult ar) {

DataConnection.FailCause cause = DataConnection.FailCause.UNKNOWN;//新构造的unkonw
booleanhandleError =false;
ApnContext apnContext =null;
if(ar.userObjinstanceofApnContext){//obj的类型判断
apnContext = (ApnContext)ar.userObj;
}else{
thrownewRuntimeException("onDataSetupComplete: No apnContext");
}

if(isDataSetupCompleteOk(ar)) {
//AsyncChannel to a DataConnection(数据连接的通信通道),DataConnectionAc 是为了让GsmDataConnectionTracker所在的
//handler和DataConnection所在的Handler进行通信
DataConnectionAc dcac = apnContext.getDataConnectionAc();
........
if(dcac ==null) {//说明存在错误。
log("onDataSetupComplete: no connection to DC, handle as error");
cause = DataConnection.FailCause.CONNECTION_TO_DATACONNECTIONAC_BROKEN;
handleError =true;//更新标志位,表示需要处理错误,以便重新尝试
}else{
DataConnection dc = apnContext.getDataConnection();
ApnSetting apn = apnContext.getApnSetting();
if(DBG) {
log("onDataSetupComplete: success apn="+ (apn ==null?"unknown": apn.apn));
}
//获取端口号,代理信息,若存在就关联到LinkProperties上去
if(apn !=null&& apn.proxy!=null&& apn.proxy.length() != 0) {
try{
String port = apn.port;
if(TextUtils.isEmpty(port)) port ="8080";
ProxyProperties proxy =newProxyProperties(apn.proxy,
Integer. parseInt(port),null);
dcac.setLinkPropertiesHttpProxySync(proxy);
}catch(NumberFormatException e) {
loge("onDataSetupComplete: NumberFormatException making ProxyProperties ("+
apn.port+"): "+ e);
}
}
// everything is setup
if(TextUtils.equals(apnContext.getApnType(),PhoneConstants.APN_TYPE_DEFAULT)) {
SystemProperties. set("gsm.defaultpdpcontext.active","true");
if(canSetPreferApn&&mPreferredApn==null) {
if(DBG) log("onDataSetupComplete: PREFERED APN is null");
mPreferredApn= apn;
if(mPreferredApn!=null) {
setPreferredApn(mPreferredApn.id);
}
}
}else{
SystemProperties. set("gsm.defaultpdpcontext.active","false");
}
mTetheringExt.onDataSetupComplete(apnContext);
// Notify call start again if call is not IDLE and not concurrent
//如果当前gsm电话状态不是空闲,并且语音通话和数据网络不支持并发,那么就要再次通知通话开始了
if(((GsmCallTracker)mGsmPhone.getCallTracker()).state!= PhoneConstants.State.IDLE&&                    !mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed()) {
if(DBG) log("onDataSetupComplete: In 2G phone call, notify data REASON_VOICE_CALL_STARTED");
notifyDataConnection(Phone.REASON_VOICE_CALL_STARTED);
}
notifyDefaultData(apnContext);
/// M: SCRI and Fast Dormancy Feature @{
//MTK-START [mtk04070][111205][ALPS00093395]Add for SCRI
/* Add by MTK03594 for SCRI feature */
startScriPoll();
//MTK-END [mtk04070][111205][ALPS00093395]Add for SCRI
/// @}
}
//isDataSetupCompleteOk(ar)为false
}else{
cause = (DataConnection.FailCause) (ar.result);
if(DBG) {
ApnSetting apn = apnContext.getApnSetting();
log(String. format("onDataSetupComplete: error apn=%s cause=%s",
(apn ==null?"unknown": apn.apn), cause));
}

if(cause.isEventLoggable()) {
// Log this failure to the Event Logs.
intcid = getCellLocationId();
EventLog. writeEvent(EventLogTags .PDP_SETUP_FAIL,
cause.ordinal(), cid, TelephonyManager. getDefault().getNetworkType());
}
// Count permanent failures and remove the APN we just tried
if(cause.isPermanentFail()) apnContext.decWaitingApnsPermFailCount();
if(cause == DataConnection.FailCause.GMM_ERROR&&
mPhone.getServiceStateTracker().getCurrentDataConnectionState() != ServiceState.STATE_IN_SERVICE) {
// stop retry for GMM_ERROR and let GPRS attach event to trigger如果是GMM_ERROR停止重试,并且触发GPRS附加事件
//更新ApnConext中的成员变量mWaitingApns和mWaitingApnsPermanentFailureCountDown(此时mWaitingApns的size为0)
//mWaitingApnsPermanentFailureCountDown设置为0,而0表示mWaitingApns中的所有的apn存在永久性错误
apnContext.setWaitingApns(newArrayList<ApnSetting>());
log("onDataSetupComplete: GMM_ERROR, wait for GPRS attach to retry.");
}elseif(mGsmDCTExt.needDelayedRetry(cause.getErrorCode())) {//根据FailCause中的errorcode判断是否需要重试
log("onDataSetupComplete: need delayed retry");
intretryCount = apnContext.getRetryCount();
//配置一个简单的线性序列的时间,加上一个随机值
apnContext.getDataConnection().configureRetry(2, 45000, 0);//重试参数(最大重试次数,延迟时间,随机值介于0和第二个参数之间)
apnContext.getDataConnection().setRetryCount(retryCount);
apnContext.removeWaitingApn(apnContext.getApnSetting());//移除所以出于waiting状态的apn
}
if(DBG) {
log(String. format("onDataSetupComplete: WaitingApns.size=%d"+
" WaitingApnsPermFailureCountDown=%d",
apnContext.getWaitingApns().size(),
apnContext.getWaitingApnsPermFailCount()));
}
handleError =true;
}
//处理错误
if(handleError) {
// See if there are more APN's to try
if(apnContext.getWaitingApns().isEmpty()) {
if(apnContext.getWaitingApnsPermFailCount() == 0) {
if(DBG) {
log("onDataSetupComplete: All APN's had permanent failures, stop retrying");
}
apnContext.setState(DctConstants.State.FAILED);
mPhone.notifyDataConnection(Phone.REASON_APN_FAILED, apnContext.getApnType());
apnContext.setDataConnection(null);//清理DataConnection,在trySetupData将重新关联新的实例
apnContext.setDataConnectionAc(null);//清理DataConnectionAc,在trySetupData将重新关联新的实例
// M: try to enable apn which is in waiting list
if(apnContext.getApnType() == PhoneConstants.APN_TYPE_MMS) {
enableWaitingApn();
}
if(PhoneFactory.isDualTalkMode()) {
if(apnContext.getApnType() != PhoneConstants.APN_TYPE_DEFAULT&&mWaitingApnList.isEmpty()) {
// try to restore default
trySetupData(Phone.REASON_DATA_ENABLED, PhoneConstants.APN_TYPE_DEFAULT);
}
}
}else{
if(DBG) log("onDataSetupComplete: Not all permanent failures, retry");

// check to see if retry should be overridden for this failure.

intretryOverride = -1;

if(ar.exceptioninstanceofDataConnection.CallSetupException) {

retryOverride =                    ((DataConnection.CallSetupException)ar.exception).getRetryOverride();
}
if(retryOverride == RILConstants.MAX_INT) {
if(DBG) log("No retry is suggested.");
}else{
startDelayedRetry(cause, apnContext, retryOverride);
}
}
//handleError为false
}else{
if(DBG) log("onDataSetupComplete: Try next APN");
apnContext.setState(DctConstants.State.SCANNING);
// Wait a bit before trying the next APN, so that
// we're not tying up the RIL command channel
startAlarmForReconnect(APN_DELAY_MILLIS, apnContext);
}
}
}


(12).来看看GsmDataConnectionTracker中的notifyDefaultData(apnContext)做了些什么处理.和第(10)中CdmaDataConnectionTracker的notifyDefaultData(String)做的事情都差不多,更新ApnContext的状态,开启NetStatPoll,DataStallAlarm,重置重试次数,之后也是通过phoneBase的实例mPhone调用notifyDataConnection(string,string)把消息传递出去。Gsm和Cdma的分支在这里又合并到一起。

private void notifyDefaultData(ApnContext apnContext) {

// M: If context is disabled and state is DISCONNECTING,

// should not change the state to confuse the following enableApnType() which returns PhoneConstants.APN_ALREADY_ACTIVE as CONNECTED

if(apnContext.getState() != DctConstants.State.DISCONNECTING) {

apnContext.setState(DctConstants.State.CONNECTED);

}

// setState(DctConstants.State.CONNECTED);

mPhone.notifyDataConnection(apnContext.getReason(), apnContext.getApnType());

startNetStatPoll();

startDataStallAlarm(DATA_STALL_NOT_SUSPECTED);

// reset reconnect timer

apnContext.setRetryCount(0);

}


(13).PhoneBase继承自handler,实现了Phone接口。在这个方法中又调用PhoneNotifier的来传递消息,它是对所有系统范围状态改变通知的抽象。DefaultPhoneNotifier实现了phoneNotifier,这里实际上调用的DefaultPhoneNotifier的notifyDataConnection(Phone sender, String reason, String apnType, DataState state)方法.此外在getDataConnectionState(apntype)会分支到GSMPhone.java和CDMAPhone.java,返回相对应的PhoneConstants中的DataState枚举类型(这里是返回PhoneConstants.DataState.CONNECTED)

(frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneBase.java)

(frameworks/base/telephony/java/com/android/internal/telephony/PhoneConstants.java)

(frameworks/opt/telephony/src/java/com/android/internal/telephony/cdma/CDMAPhone.java)

(frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/GSMPhone.java)

public void notifyDataConnection(String reason, String apnType) {

mNotifier.notifyDataConnection(this, reason, apnType, getDataConnectionState(apnType));

}


在DefaultPhoneNotifier中又调用了doNotifyDataConnection()方法,接下来就看看这个方法做了什么处理

//MTK-START [mtk04070][111125][ALPS00093395]MTK modified

public void notifyDataConnection(Phone sender, String reason, String apnType,

PhoneConstants.DataState state) {

doNotifyDataConnection(sender, reason, apnType, state);

}


//MTK-END [mtk04070][111125][ALPS00093395]MTK modified

(14).doNotifyDataConnection() 根据传入的 apnType先从phone 中取出连接参数 linkProperties 和linkCapabilities( 代表链接功能的类 ),再获取包含手机状态和服务相关信息的 ServiceState实例,作为之后TelephonyRegistry和 notifyDataStateChangeCallback()的参数。之后通过ITelephonyRegistry.aidl跨进程调用到 TelephonyRegistry.java的notifyDataConnection() 方法。

(frameworks/opt/telephony/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java)

(/frameworks/base/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl)

private void doNotifyDataConnection(Phone sender, String reason, String apnType,
PhoneConstants.DataState state) {
//TODO
// use apnType as the key to which connection we're talking about.
// pass apnType back up to fetch particular for this one.
TelephonyManager telephony = TelephonyManager. getDefault();//TelephonyManager 单列模式类,懒汉式,通过此方法获取 TelephonyManager 实例
LinkProperties linkProperties = null;
LinkCapabilities linkCapabilities = null;
booleanroaming =false;

if(state == PhoneConstants.DataState.CONNECTED) {
linkProperties = sender.getLinkProperties(apnType);
linkCapabilities = sender.getLinkCapabilities(apnType);
}
ServiceState ss = sender.getServiceState();/
if(ss !=null) roaming = ss.getRoaming();// 获取到手机信息和服务信息类,获取漫游信息

intnetworkType = TelephonyManager.NETWORK_TYPE_UNKNOWN;
if(!FeatureOption.MTK_GEMINI_SUPPORT) {
// 上面通过 getDefault获取到telephony ,由于是懒汉式,所以不会为 null
networkType = ((telephony!= null) ? telephony.getNetworkType() : TelephonyManager.NETWORK_TYPE_UNKNOWN );
} else{
networkType = ((telephony!= null) ? telephony.getNetworkTypeGemini (sender.getMySimId()) : TelephonyManager.NETWORK_TYPE_UNKNOWN );
}
log( "doNotifyDataConnection " +"apnType="+ apnType + ",networkType="+ networkType +", state="+ state);
notifyDataStateChangeCallback(
state.toString(),
reason,
sender.getActiveApnHost(apnType),
apnType,
sender.isDataConnectivityPossible(apnType),
mSimId);
try{
// 将 PhoneConstants.DataState转换成 TelephoneManager当中定义的状态。这里是将 PhoneConstants.DataState. CONNECTED 转换为TelephonyManager.DATA_CONNECTED
mRegistry.notifyDataConnection(
convertDataState(state),
sender.isDataConnectivityPossible(apnType),// 检查该apn数据连接是否被允许,之后会通过调用到 PhoneBase.java,再分支到CdmaDataConnectionTracker和 GsmDataConnectionTracker的isDataPossible(String apnType) 方法
reason,
sender.getActiveApnHost(apnType), //返回或的apn 主机字符串 (其实是ApnSetting.apn)
apnType,
linkProperties,
linkCapabilities,
networkType,
roaming);
} catch(RemoteException ex) {
// system process is dead
}

// M: Update SIM indication state for data connection state change
if(senderinstanceofPhoneBase) {
((PhoneBase)sender).updateDataStateOfSimIndication(apnType, state);
}
}


notifyDataStateChangeCallback() 根据方法名推测是一个数据状态改变的回调

private void notifyDataStateChangeCallback(String state, String reason, String apnName,
String apnType, booleanunavailable,intsimId)
{
Iterator<IDataStateChangedCallback> iterator = mDataStateChangedCallbacks.iterator();
while(iterator.hasNext()) {
IDataStateChangedCallback callback = iterator.next();
callback.onDataStateChanged(state, reason, apnName, apnType, unavailable, simId);
}
}


IDataStateChangedCallback 是一个接口,包含一个方法,该方法在 framework中没有找到该接口的实现,推测是内置的系统级别应用程序进行实现。

public interface IDataStateChangedCallback {
voidonDataStateChanged(String state, String reason, String apnName,
String apnType, booleanunavailable,intsimId);
}


(15).TelephonyRegistry的 notifyDataConnection()方法。首先是检查是否有 notify权限( android.Manifest.permission.MODIFY_PHONE_STATE ),没有权限的话,将不会继续执行连接消息的传递。再判断是否需要对目前的连接信息进行修改,如果有进行修改,则标记 modified为true 。方法中 mRecords.events的实际上就是在NetworkController.java中注册的消息,如果这些消息存在,并且 过IPhoneStateListener的 onDataConnectionStateChanged()回调触发相应的处理,(之前进行过 LISTEN_DATA_CONNECTION_STATE 注册的都将触发,已知 NetworkController.java)。最后通过broadcastDataConnectionStateChanged () 发送网络状态改变的广播出去, ConnectivityService.java中将接收到这个广播,再继续做处理。

(frameworks/base/services/java/com/android/server/TelephonyRegistry.java)

public void notifyDataConnection(intstate, booleanisDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
LinkCapabilities linkCapabilities, intnetworkType,booleanroaming) {
if(!checkNotifyPermission("notifyDataConnection()" )) {
return;
}
synchronized(mRecords ) {
// M: For synchronization of mRecords, move log into synchronization protection.
if(DBG ) {
Slog. i(TAG, "notifyDataConnection: state=" + state +" isDataConnectivityPossible="
+ isDataConnectivityPossible + " reason='"+ reason
+ "' apn='"+ apn +"' apnType=" + apnType +" networkType="+ networkType
+ " mRecords.size()="+mRecords .size() +" mRecords="+ mRecords);
}
booleanmodified =false;
if(state == TelephonyManager.DATA_CONNECTED) {// 数据已连接
if(!mConnectedApns .contains(apnType)) {
mConnectedApns.add(apnType);//添加到连接的 apn列表中
if(mDataConnectionState != state) {//修改当前的成员变量标识连接状态
mDataConnectionState= state;
modified = true;
}
}
} else{// 如果不是连接,则移除
if(mConnectedApns .remove(apnType)) {
if(mConnectedApns .isEmpty()) {
mDataConnectionState= state;//连接状态修改
modified = true;
} else{
// leave mDataConnectionState as is and
// send out the new status for the APN in question.
}
}
}
mDataConnectionPossible= isDataConnectivityPossible;
mDataConnectionReason= reason;
mDataConnectionLinkProperties= linkProperties;
mDataConnectionLinkCapabilities= linkCapabilities;
if(mDataConnectionNetworkType != networkType) {//网络连接类型修改
mDataConnectionNetworkType= networkType;
// need to tell registered listeners about the new network type
modified = true;
}
if(modified) {
if(DBG ) {
Slog. d(TAG, "onDataConnectionStateChanged(" +mDataConnectionState
+ ", "+mDataConnectionNetworkType +")");
}
for(Record r :mRecords ) {
//PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 侦听更改数据连接状态
if((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
try{
// 触发IPhoneStateListener的 onDataConnectionStateChanged回调
r.callback.onDataConnectionStateChanged( mDataConnectionState,
mDataConnectionNetworkType);
} catch(RemoteException ex) {
mRemoveList.add(r.binder );
}
}
}
handleRemoveListLocked();// mRemoveList 和 mRecords 是同步域,根据 mRemoveList的binder 移除mRecords中的 Record,
}
}
broadcastDataConnectionStateChanged (state, isDataConnectivityPossible, reason, apn,
apnType, linkProperties, linkCapabilities, roaming);
}


(16)在framework 中NetworkController.java(/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java )的构造方法中调用了TelephonyManager的 listen方法进行注册。监听包括网络服务状态 (LISTEN_SERVICE_STATE), 信号强弱 (LISTEN_SIGNAL_STRENGTHS状态栏的信号强度图标 ),手机通话状态(通话,空闲,响铃 LISTEN_CALL_STATE),数据连接状态 (LISTEN_DATA_CONNECTION_STATE),以及数据连接上的数据业务方向改变 (状态栏使用它来显示相应的数据流量图标 )。

public NetworkController(Context context) {
......

ConnectivityManager cm = (ConnectivityManager) mContext.getSystemService(
Context. CONNECTIVITY_SERVICE);
mHasMobileDataFeature= cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
.......

// set up the default wifi icon, used when no radios have ever appeared
updateWifiIcons();
updateWimaxIcons();
// telephony
mPhone= (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
//用的或运算将多种类型都带进去了
mPhone.listen(mPhoneStateListener ,
PhoneStateListener. LISTEN_SERVICE_STATE
| PhoneStateListener. LISTEN_SIGNAL_STRENGTHS
| PhoneStateListener. LISTEN_CALL_STATE
| PhoneStateListener. LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener. LISTEN_DATA_ACTIVITY);
.......

// broadcasts
IntentFilter filter = newIntentFilter();
filter.addAction(WifiManager. RSSI_CHANGED_ACTION);
filter.addAction(WifiManager. WIFI_STATE_CHANGED_ACTION);
filter.addAction(WifiManager. NETWORK_STATE_CHANGED_ACTION );
filter.addAction(TelephonyIntents. ACTION_SIM_STATE_CHANGED);
filter.addAction(TelephonyIntents. SPN_STRINGS_UPDATED_ACTION );
filter.addAction(ConnectivityManager. CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager. INET_CONDITION_ACTION);
filter.addAction(Intent. ACTION_CONFIGURATION_CHANGED );
filter.addAction(Intent. ACTION_AIRPLANE_MODE_CHANGED );
.......

}


在框架中NetworkStatsService.java中也进行了TelephonyManager的listen方法进行PhoneStateListener. LISTEN_DATA_CONNECTION_STATE 注册,不过貌似应该不会触发。由于

COMBINE_SUBTYPE_ENABLED 恒为true ,这里只是提出来这个类有注册的行为。

(frameworks/base/services/java/com/android/server/net/NetworkStatsService.java)

public void systemReady() {
.........

// watch for networkType changes that aren't broadcast through
// CONNECTIVITY_ACTION_IMMEDIATE above.
// publicstaticfinalbooleanCOMBINE_SUBTYPE_ENABLED= true;
if(!COMBINE_SUBTYPE_ENABLED ) {
mTeleManager.listen(mPhoneListener ,LISTEN_DATA_CONNECTION_STATE);
}
registerPollAlarmLocked();
registerGlobalAlert();
}


(17).在系统内置的应用程序Settings中也调用了 TelephonyManager的listen 方法进行了 PhoneStateListener. LISTEN_DATA_CONNECTION_STATE注册( 可能还有其他应用程序进行相同操作,但目前只发现 settings,内置程序phne中 /src/com/android/phone/CallNotifier.java进行了 PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR |PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR |PhoneStateListener.LISTEN_SERVICE_STATE单未进行 LISTEN_DATA_CONNECTION_STATE 的注册)

(/packages/apps/Settings/src/com/android/settings/deviceinfo/Status.java)

(/packages/apps/Settings/src/com/android/settings/RadioInfo.java)

先来看下 Status.java

protected void onResume() {
super.onResume();
........
mTelephonyManager.listen(mPhoneStateListener ,
PhoneStateListener. LISTEN_DATA_CONNECTION_STATE);
mTelephonyManager.listen(mSignalStrengthListener ,
PhoneStateListener.LISTEN_SIGNAL_STRENGTHS);
mTelephonyManager.listen(mPhoneServiceListener ,
PhoneStateListener.LISTEN_SERVICE_STATE);
.......
}


再来看 RadioInfo.java

protected void onResume() {
.......
mPhoneStateReceiver.registerIntent();
mTelephonyManager.listen(mPhoneStateListener ,
PhoneStateListener. LISTEN_DATA_CONNECTION_STATE
| PhoneStateListener.LISTEN_DATA_ACTIVITY
| PhoneStateListener.LISTEN_CELL_LOCATION
| PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR
| PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR
| PhoneStateListener.LISTEN_CELL_INFO);
}


(18.)接下来看下TelephonyManager的 listen方法实现( /frameworks/base/telephony/java/android/telephony/TelephonyManager.java ):根据相应的PhoneStateListener类型,在 TelephonyRegistry.java实现相应的listen 方法。

public void listen (PhoneStateListener listener, intevents) {
//MTK-START [mtk04070][111116][ALPS00093395]Support Gemini
String pkgForDebug = sContext!=null ?sContext.getPackageName() : "<unknown>";
try{
// getITelephony()返回ITelephony (frameworks/base/telephony/java/com/android/internal/telephony/ITelephony.aidl)
// 由应用程序 Phone中的PhoneInterfaceManager 继承ITelephony.Stub
Boolean notifyNow = ( getITelephony() !=null);
sRegistry.listen(pkgForDebug, listener.callback , events, notifyNow);

/* Add by mtk01411 for Data related event */
if(FeatureOption.MTK_GEMINI_SUPPORT) {
if(events == PhoneStateListener.LISTEN_NONE) {
/* Unregister previous listened events */
mRegistry2.listen(pkgForDebug, listener.callback , events, notifyNow);
} elseif(events == PhoneStateListener.LISTEN_CALL_STATE) {
mRegistry2.listen(pkgForDebug, listener.callback , events, notifyNow);
} else{
intdata_events = PhoneStateListener.LISTEN_NONE;
if((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) !=0 ) {
data_events |= PhoneStateListener. LISTEN_DATA_CONNECTION_STATE ;
}
if((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) !=0 ) {
data_events |= PhoneStateListener. LISTEN_DATA_ACTIVITY;
}

if(data_events != PhoneStateListener.LISTEN_NONE) {
/* For 3rd party application: */
/* This solution is only useful if only one PS can be attached for one of two sim cards */
/* If PS can be attached on both sim cards at the same time: This solution can't work */
/* => Because the same callback may recevie two same events and can't identify which event comes from which sim card */
mRegistry2.listen(pkgForDebug, listener.callback , data_events, notifyNow);
}
}

}
//MTK-END [mtk04070][111116][ALPS00093395]Support Gemini
} catch(RemoteException ex) {
// system process dead
ex.printStackTrace();
} catch(NullPointerException ex) {
// system process dead
ex.printStackTrace();
}
}


(19).回到TelephonyRegistry.java 来看看它的 listen方法实现

public void listen(String pkgForDebug, IPhoneStateListener callback, intevents,
booleannotifyNow) {
intcallerUid = UserHandle.getCallingUserId();// 多用户的处理,获取是调用的用户 id
intmyUid = UserHandle.myUserId();
if(DBG ) {
Slog. d(TAG, "listen: E pkg="+ pkgForDebug +" events=0x" + Integer.toHexString (events)
+ " myUid="+ myUid
+ " callerUid="+ callerUid);
}
if(events != 0) {
/* Checks permission and throws Security exception */
checkListenerPermission(events);

synchronized(mRecords ) {
// register
Record r = null;
find_and_add: {
IBinder b = callback.asBinder();
finalintN =mRecords .size();
for(int i = 0; i < N; i++) {
r = mRecords.get(i);
if(b == r.binder ) {
breakfind_and_add;
}
}
r = newRecord();
r. binder= b;
r.callback= callback;
r. pkgForDebug= pkgForDebug;
r. callerUid= callerUid;
mRecords.add(r);//加入到了 mRecords 中,在 notifyDataConnection中for 循环中使用
if(DBG ) Slog.i (TAG ,"listen: add new record="+ r);
}
intsend = events & (events ^ r.events );
r. events= events;
if(notifyNow) {
if((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try{
r.callback.onServiceStateChanged( newServiceState(mServiceState ));
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH ) != 0) {
try{
intgsmSignalStrength =mSignalStrength .getGsmSignalStrength();
r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1
: gsmSignalStrength));
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) {
try{
r.callback.onMessageWaitingIndicatorChanged( mMessageWaiting);
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) {
try{
r.callback.onCallForwardingIndicatorChanged( mCallForwarding);
} catch(RemoteException ex) {
remove(r. binder);
}
}
if(validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) {
try{
r.callback.onCellLocationChanged( newBundle(mCellLocation ));
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {
try{
r.callback.onCallStateChanged( mCallState,mCallIncomingNumber );
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) {
try{
r.callback.onDataConnectionStateChanged( mDataConnectionState,
mDataConnectionNetworkType);
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_DATA_ACTIVITY) != 0) {
try{
r.callback.onDataActivity( mDataActivity);
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
try{
r.callback.onSignalStrengthsChanged( mSignalStrength);
} catch(RemoteException ex) {
remove(r. binder);
}
}
if((events & PhoneStateListener.LISTEN_OTASP_CHANGED) != 0) {
try{
r.callback.onOtaspChanged( mOtaspMode);
} catch(RemoteException ex) {
remove(r. binder);
}
}
if(validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try{
if(DBG_LOC ) Slog.d (TAG ,"listen: mCellInfo="+ mCellInfo);
r.callback.onCellInfoChanged( mCellInfo);
} catch(RemoteException ex) {
remove(r. binder);
}
}
}
}
} else{
remove(callback.asBinder());
}
}


(20).当TelephonyRegistry 的notifyDataConnection()方法中触发 onDataConnectionStateChanged()时,实际上将回调到以下地方:具体都是做一些更新的操作

a.在framework 中NetworkController.java

@Override
publicvoidonDataConnectionStateChanged (intstate,intnetworkType) {
if(DEBUG ) {
Slog. d(TAG, "onDataConnectionStateChanged : state=" + state
+ " type="+ networkType);
}
mDataState= state;
mDataNetType= networkType;
updateDataNetType();
updateDataIcon();// 更新数据图标
refreshViews();// 刷新view
}


b.在framework 中NetworkStatsService.java

private PhoneStateListener mPhoneListener=new PhoneStateListener() {
@Override
publicvoidonDataConnectionStateChanged (intstate,intnetworkType) {
finalbooleanstateChanged = state !=mLastPhoneState ;
finalbooleannetworkTypeChanged = networkType !=mLastPhoneNetworkType;
if(networkTypeChanged && !stateChanged) {
// networkType changed without a state change, which means we
// need to roll our own update. delay long enough for
// ConnectivityManager to process.
//TODO: add direct event to ConnectivityService instead of
// relying on this delay.
if(LOGV ) Slog.v (TAG ,"triggering delayed updateIfaces()");
mHandler.sendMessageDelayed(
mHandler.obtainMessage(MSG_UPDATE_IFACES), SECOND_IN_MILLIS);//发消息进行更新
}
mLastPhoneState= state;
mLastPhoneNetworkType= networkType;
}
};


c.在应用程序Setting中 Status.java中:

private PhoneStateListener mPhoneStateListener= newPhoneStateListener() {
@Override
publicvoidonDataConnectionStateChanged (int state) {
updateDataState();//
updateNetworkType();
}
}


d.在应用程序Setting中 RadioInfo.java中:

public void onDataConnectionStateChanged(intstate) {
updateDataState();
updateDataStats();
updatePdpList();
updateNetworkType();
}


(21).TelephonyRegistry的 notifyDataConnection()方法最后调用 broadcastDataConnectionStateChanged ()方法发送数据连接变化的广播.这里将当前的状态, apn类型,连接参数等都封装在了 action为ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE的intent 中,通过intent将这些内容发送出去。之后 frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/QuickSettingsConnectionModel.java 和/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/toolbar/SimSwitchPanel.java 将接收到该广播并进行处理。

private void broadcastDataConnectionStateChanged( intstate,
booleanisDataConnectivityPossible,
String reason, String apn, String apnType, LinkProperties linkProperties,
LinkCapabilities linkCapabilities, booleanroaming) {
// 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 =newIntent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE);
intent.putExtra(PhoneConstants. STATE_KEY, DefaultPhoneNotifier.convertDataState(state).toString());
if(!isDataConnectivityPossible) {
intent.putExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,true );
}
if(reason !=null) {
intent.putExtra(PhoneConstants. STATE_CHANGE_REASON_KEY, reason);
}
if(linkProperties !=null) {
intent.putExtra(PhoneConstants. DATA_LINK_PROPERTIES_KEY, linkProperties);
String iface = linkProperties.getInterfaceName();
if(iface !=null) {
intent.putExtra(PhoneConstants. DATA_IFACE_NAME_KEY, iface);
}
}
if(linkCapabilities !=null) {
intent.putExtra(PhoneConstants. DATA_LINK_CAPABILITIES_KEY , linkCapabilities);
}
if(roaming) intent.putExtra(PhoneConstants.DATA_NETWORK_ROAMING_KEY, true);

intent.putExtra(PhoneConstants. DATA_APN_KEY, apn);
intent.putExtra(PhoneConstants. DATA_APN_TYPE_KEY, apnType);

if(FeatureOption.MTK_GEMINI_SUPPORT) {
intent.putExtra(PhoneConstants. GEMINI_SIM_ID_KEY,mySimId );
}

// To make sure MobileDataStateTracker can receive this intent firstly,
// using oredered intent ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE
// redirect original intent. -->
mContext.sendOrderedBroadcast(intent,null,mDataConnChangeReceiver, null, 0,null,null);
// <--
}


(21).在广播ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE发送之后,将被 MobileDataStateTracker中的内部类MobileDataStateReceiver和 TelephonyRegistry的mDataConnChangeReceiver 接收。TelephonyRegistry中将接收到 intent又使用action :TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED发送出去。

而在 MobileDataStateReceiver中处理则比较复杂,这里就没有不再进行细致分析了。先根据 intent中的apntype 从全局的trakerMap中取出相应的 tracker 实例,再根据PhoneConstants. STATE_KEY 取出 state值,并由此进行分支处理。在 CONNECTED 分支中, tracker调用setDetailedState() 修改apn对应的 networkinfo中的状态信息,并发送EVENT_STATE_CHANGED消息 ,ConnectionService的内部类NetworkStateTrackerHandler 将接收该消息并进行处理。

@Override
public void onReceive(Context context, Intent intent) {
if(intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED_MOBILE)) {
String apnType = intent.getStringExtra(PhoneConstants. DATA_APN_TYPE_KEY);
MobileDataStateTracker tracker = mTrackerMap.get(apnType);
if(tracker ==null) {
return;
}
......
// 子类型改变了,发出相应的消息
tracker. mNetworkInfo.setSubtype(newSubType, subTypeName);
if(newSubType != oldSubtype && tracker.mNetworkInfo.isConnected()) {
Message msg = tracker.mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED,
oldSubtype, 0, tracker.mNetworkInfo );
msg.sendToTarget();
}
// 根据intent中传递过来的字符串 state值再次转换为 PhoneConstants.DataState ,并根据 state进行分支处理
PhoneConstants.DataState state = Enum. valueOf(PhoneConstants.DataState.class,
intent.getStringExtra(PhoneConstants. STATE_KEY));
String reason = intent.getStringExtra(PhoneConstants. STATE_CHANGE_REASON_KEY);
String apnName = intent.getStringExtra(PhoneConstants. DATA_APN_KEY);
tracker.mNetworkInfo .setRoaming(intent.getBooleanExtra(PhoneConstants. DATA_NETWORK_ROAMING_KEY,false ));
if(VDBG ) {
tracker.log(tracker. mApnType+" setting isAvailable to " +
!intent.getBooleanExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,false ));
}
tracker.mNetworkInfo .setIsAvailable(!intent.getBooleanExtra(PhoneConstants. NETWORK_UNAVAILABLE_KEY,false ));

if(tracker.mMobileDataState != state) {
tracker. mMobileDataState= state;
switch(state) {
caseDISCONNECTED:
if(tracker.isTeardownRequested()) {
tracker.setTeardownRequested( false);
}
if(FeatureOption.MTK_GEMINI_SUPPORT) {
tracker.setDetailedStateGemini(DetailedState. DISCONNECTED, reason, apnName, slot);
} else{
tracker.setDetailedState(DetailedState. DISCONNECTED, reason, apnName);
}
// can't do this here - ConnectivityService needs it to clear stuff
// it's ok though - just leave it to be refreshed next time
// we connect.
//if (DBG) log("clearing mInterfaceName for "+ mApnType +
//        " as it DISCONNECTED");
//mInterfaceName = null;
break;
caseCONNECTING:
if(FeatureOption.MTK_GEMINI_SUPPORT) {
tracker.setDetailedStateGemini(DetailedState. CONNECTING, reason, apnName, slot);
} else{
tracker.setDetailedState(DetailedState. CONNECTING, reason, apnName);
}
break;
caseSUSPENDED:
if(FeatureOption.MTK_GEMINI_SUPPORT) {
tracker.setDetailedStateGemini(DetailedState. SUSPENDED, reason, apnName, slot);
} else{
tracker.setDetailedState(DetailedState. SUSPENDED, reason, apnName);
}
break;
caseCONNECTED:
tracker. mLinkProperties= intent.getParcelableExtra(
PhoneConstants. DATA_LINK_PROPERTIES_KEY);
if(tracker.mLinkProperties ==null) {
tracker.loge( "CONNECTED event did not supply link properties." );
tracker. mLinkProperties=new LinkProperties();
}
tracker. mLinkCapabilities= intent.getParcelableExtra(
PhoneConstants. DATA_LINK_CAPABILITIES_KEY );
if(tracker.mLinkCapabilities ==null) {
tracker.loge( "CONNECTED event did not supply link capabilities." );
tracker. mLinkCapabilities=new LinkCapabilities();
}
if(FeatureOption.MTK_GEMINI_SUPPORT) {
tracker.setDetailedStateGemini(DetailedState. CONNECTED, reason, apnName, slot);
} else{
tracker.setDetailedState(DetailedState. CONNECTED, reason, apnName);
}

break;
}
}
.....
}


privatevoid setDetailedState(NetworkInfo.DetailedState state, String reason,
String extraInfo) {

if(state !=mNetworkInfo .getDetailedState()) {
booleanwasConnecting = (mNetworkInfo .getState() == NetworkInfo.State. CONNECTING);
String lastReason = mNetworkInfo.getReason();
/*
* If a reason was supplied when the CONNECTING state was entered, and no
* reason was supplied for entering the CONNECTED state, then retain the
* reason that was supplied when going to CONNECTING.
*/
if(wasConnecting && state == NetworkInfo.DetailedState.CONNECTED&& reason == null
&& lastReason != null)
reason = lastReason;
mNetworkInfo.setDetailedState(state, reason, extraInfo);//修改networkInfo 中的状态信息
Message msg =mTarget.obtainMessage(EVENT_STATE_CHANGED, newNetworkInfo(mNetworkInfo ));//给ConnectionService 中NetworkStateTrackerHandler发消息
msg.sendToTarget();
} elseif(reason !=null&& (reason.equals(PhoneConstants. REASON_NO_SUCH_PDP) || reason.equals(Phone.REASON_APN_FAILED )) && state == DetailedState. DISCONNECTED){
mNetworkInfo.setDetailedState(state, reason, extraInfo);
Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo);
msg.sendToTarget();
}
}


(22).回到ConnectionService.java 中来,这里果然是连接管理的最核心啊,也是反馈的终点了。

private class NetworkStateTrackerHandler extendsHandler {
.....
@Override
publicvoidhandleMessage(Message msg) {
NetworkInfo info;
switch(msg.what ) {
caseNetworkStateTracker.EVENT_STATE_CHANGED:
info = (NetworkInfo) msg. obj;
inttype = info.getType();
NetworkInfo.State state = info.getState();

if(VDBG || (state == NetworkInfo.State.CONNECTED) ||
(state == NetworkInfo.State. DISCONNECTED)) {
log("ConnectivityChange for "+
info.getTypeName() + ": "+
state + "/"+ info.getDetailedState());
}

EventLogTags.writeConnectivityStateChanged(
info.getType(), info.getSubtype(), info.getDetailedState().ordinal());

if(info.getDetailedState() ==
NetworkInfo.DetailedState. FAILED) {
handleConnectionFailure(info);
} elseif(info.getDetailedState() ==
DetailedState. CAPTIVE_PORTAL_CHECK) {
handleCaptivePortalTrackerCheck(info);
} elseif(state == NetworkInfo.State.DISCONNECTED) {
handleDisconnect(info);
} elseif(state == NetworkInfo.State.SUSPENDED) {
//TODO: need to think this over.
// the logic here is, handle SUSPENDED the same as
// DISCONNECTED. The only difference being we are
// broadcasting an intent with NetworkInfo that's
// suspended. This allows the applications an
// opportunity to handle DISCONNECTED and SUSPENDED
// differently, or not.
Slog. d(TAG, "Change to Suspend_State due to reason=" + info.getReason() +" with network="+ info.getSubtypeName()) ;
if(((info.getReason() !=null) && info.getReason().equals(Phone.REASON_VOICE_CALL_STARTED ))
&& (info.getSubtype() == TelephonyManager. NETWORK_TYPE_GPRS
|| info.getSubtype() == TelephonyManager.NETWORK_TYPE_EDGE
|| info.getSubtype() == TelephonyManager.NETWORK_TYPE_UNKNOWN)) {
Xlog.e( MTK_TAG,"Suspend PS TX/RX Temporarily without deactivating PDP context");
sendSuspendedBroadcast(info);// 手机2G网络挂起
} else{
Xlog.e( MTK_TAG,"Switch to Suspend:invoke handleDisconnect()" );
handleDisconnect(info);// 做断开处理
}
} elseif(state == NetworkInfo.State.CONNECTED) {
handleConnect(info);// 做连接处理
}
if(mLockdownTracker !=null) {
mLockdownTracker.onNetworkInfoChanged(info);
}
break;
.......
}
}
}


(23.)最后一步操作了,根据NetworkInfo对应状态变化执行 handleConnect(进行Connected 处理)或者 handleDisconnect(Disconnected)处理。并发出 CONNECTIVITY_ACTION 的广播,该广播是一个公共广播,应用程序或者框架中都可以进行广播的接收。消息传递给应用程序,知晓了网络的连接状况已经改变,并且可以获取到具体当前的网络状态

private void handleDisconnect(NetworkInfo info) {

………

/*
* If the disconnected network is not the active one, then don't report
* this as a loss of connectivity. What probably happened is that we're
* getting the disconnect for a network that we explicitly disabled
* in accordance with network preference policies.
*/
if(!mNetConfigs [prevNetType].isDefault()) {
List pids = mNetRequestersPids[prevNetType];
for(int i = 0; i<pids.size(); i++) {
Integer pid = (Integer)pids.get(i);
// will remove them because the net's no longer connected
// need to do this now as only now do we know the pids and
// can properly null things that are no longer referenced.
reassessPidDns(pid.intValue(), false);
}
}

Intent intent =new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager. EXTRA_NETWORK_INFO, new NetworkInfo(info));
intent.putExtra(ConnectivityManager. EXTRA_NETWORK_TYPE, info.getType());
if(info.isFailover()) {
intent.putExtra(ConnectivityManager. EXTRA_IS_FAILOVER,true );
info.setFailover( false);
}
if(info.getReason() !=null) {
intent.putExtra(ConnectivityManager. EXTRA_REASON, info.getReason());
}
if(info.getExtraInfo() !=null) {
intent.putExtra(ConnectivityManager. EXTRA_EXTRA_INFO,
info.getExtraInfo());
}

if(mNetConfigs [prevNetType].isDefault()) {

/** M: Support CMCC Wi-Fi to Mobile @{ */
booleanmobileData = getMobileDataEnabled();
log("mobileData="+ mobileData + ", prevNetType="+ prevNetType +",mActiveDefaultNetwork "+mActiveDefaultNetwork);

if(mIcsExt ==null){
log("Null in mIcsExt");
return;
}

if(mIcsExt .isDefaultFailover(prevNetType,mActiveDefaultNetwork)){
isFailover = tryFailover(prevNetType);
if(mActiveDefaultNetwork != -1) {
NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo();
intent.putExtra(ConnectivityManager. EXTRA_OTHER_NETWORK_INFO, switchTo);
} else{
mDefaultInetConditionPublished= 0;// we're not connected anymore
intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true );
}
} else{
mDefaultInetConditionPublished= 0;// we're not connected anymore
intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true );
mActiveDefaultNetwork= -1;
if(!mIcsExt .isUserPrompt()) {
isFailover = tryFailover(prevNetType);
if(mActiveDefaultNetwork != -1) {
NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo();
intent.putExtra(ConnectivityManager. EXTRA_OTHER_NETWORK_INFO, switchTo);
} else{
mDefaultInetConditionPublished= 0;// we're not connected anymore
intent.putExtra(ConnectivityManager. EXTRA_NO_CONNECTIVITY,true );
}
}
}
/** M: @} */
}
intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished);
if(FeatureOption.MTK_GEMINI_SUPPORT) {
if(ConnectivityManager.isRadioNumValid(simId)) {
intent.putExtra(ConnectivityManager. EXTRA_SIM_ID,simId);
}
}
// Reset interface if no other connections are using the same interface
booleandoReset =true;
LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties();
if(linkProperties !=null) {
String oldIface = linkProperties.getInterfaceName();
if(TextUtils.isEmpty(oldIface) == false) {
for(NetworkStateTracker networkStateTracker :mNetTrackers) {
if(networkStateTracker ==null)continue;
NetworkInfo networkInfo = networkStateTracker.getNetworkInfo();
if(networkInfo.isConnected() && networkInfo.getType() != prevNetType) {
LinkProperties l = networkStateTracker.getLinkProperties();
if(l ==null)continue;
if(oldIface.equals(l.getInterfaceName())) {
doReset = false;
break;
}
}
}
}
}

// do this before we broadcast the change
handleConnectivityChange(prevNetType, doReset);

finalIntent immediateIntent =newIntent(intent);
immediateIntent.setAction( CONNECTIVITY_ACTION_IMMEDIATE );
sendStickyBroadcast(immediateIntent);
sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay());
/*
* If the failover network is already connected, then immediately send
* out a followup broadcast indicating successful failover
*/
if(mActiveDefaultNetwork != -1) {
sendConnectedBroadcastDelayed( mNetTrackers[mActiveDefaultNetwork ].getNetworkInfo(),
getConnectivityChangeDelay());
}

/* whenever any interface is down, try to restore default */
if(FeatureOption.MTK_DT_SUPPORT !=true)
{
if(!isFailover) {
tryRestoreDefault();
}
}
}
pivate void handleConnect(NetworkInfo info) {
finalintnewNetType = info.getType();

setupDataActivityTracking(newNetType);

// snapshot isFailover, because sendConnectedBroadcast() resets it
booleanisFailover = info.isFailover();
finalNetworkStateTracker thisNet =mNetTrackers [newNetType];
finalString thisIface = thisNet.getLinkProperties().getInterfaceName();

// if this is a default net and other default is running
// kill the one not preferred
if(mNetConfigs [newNetType].isDefault()) {//是否是默认网络
if(mActiveDefaultNetwork != -1 &&mActiveDefaultNetwork!= newNetType) {
if(isNewNetTypePreferredOverCurrentNetType(newNetType)) {//网络优先级判断,wifi开启的情况下,数据网络会在这里通过 tearDown关掉
// tear down the other
NetworkStateTracker otherNet =
mNetTrackers[mActiveDefaultNetwork ];
if(DBG ) {
log("Policy requires "+ otherNet.getNetworkInfo().getTypeName() +
" teardown");
}
if(!teardown(otherNet)) {
loge("Network declined teardown request");
//MTK mark
Xlog.e(MTK_TAG, "Since we may teardown it by other way, just go on" );
//teardown (thisNet);
//return;
}
} else{
// don't accept this one
if(VDBG ) {
log("Not broadcasting CONNECT_ACTION "+
"to torn down network " + info.getTypeName());
}
teardown(thisNet);
return;
}
}
synchronized(ConnectivityService.this) {
// have a new default network, release the transition wakelock in a second
// if it's held.  The second pause is to allow apps to reconnect over the
// new network
if(mNetTransitionWakeLock .isHeld()) {
mHandler.sendMessageDelayed(mHandler .obtainMessage(
EVENT_CLEAR_NET_TRANSITION_WAKELOCK ,
mNetTransitionWakeLockSerialNumber , 0),
1000);
}
}
mActiveDefaultNetwork= newNetType;
// this will cause us to come up initially as unconnected and switching
// to connected after our normal pause unless somebody reports us as reall
// disconnected
mDefaultInetConditionPublished= 0;
mDefaultConnectionSequence++;
mInetConditionChangeInFlight=false ;
// Don't do this - if we never sign in stay, grey
//reportNetworkCondition(mActiveDefaultNetwork, 100);
}
thisNet.setTeardownRequested( false);
updateNetworkSettings(thisNet);
handleConnectivityChange(newNetType, false);
sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay());

// notify battery stats service about this network
finalString iface = thisNet.getLinkProperties().getInterfaceName();
if(iface !=null) {
try{
BatteryStatsService. getService().noteNetworkInterfaceType(iface, newNetType);
} catch(RemoteException e) {
// ignored; service lives in system_server
}
}
}
--------------------------------------------------------------


private void sendConnectedBroadcastDelayed(NetworkInfo info, intdelayMs) {
sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE );
sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息