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

看此篇看不太懂的同志们可以先看看我另一篇文章: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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值