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

来源:互联网 发布:2017电视机出口数据 编辑:程序博客网 时间:2024/06/06 12:37

看此篇看不太懂的同志们可以先看看我另一篇文章: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 AsyncResultforMessage (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 将接收该消息并进行处理。

@Overridepublic 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);    }
1 0
原创粉丝点击