关于RILJ多次发出GET_CURRENT_CALLS请求的问题分析

本文来自本文来自http://blog.csdn.net/linyongan 

在刚接触Qcril的时候,特别是在研究接电话和打电话的流程的时候,可能会有小伙伴跟我一样,被RILJ发出的GET_CURRENT_CALLS请求搞晕了。有时候会RILJ会多次发出GET_CURRENT_CALLS请求,两次或者三次,不确定。
举个例子,每次出现GET_CURRENT_CALLS error之后,RILJ会再发出一次GET_CURRENT_CALLS请求,所以,我们先假设“GET_CURRENT_CALLS error会导致RILJ重新发出GET_CURRENT_CALLS请求”,下面我们就根据代码去验证一下呗。



下面是打电话的一段log

09-09 17:32:03.599 D/RILJ    ( 2795): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED
09-09 17:32:03.607 D/RILJ    ( 2795): [UNSL]< UNSOL_RESPONSE_CALL_STATE_CHANGED
09-09 17:32:03.686 D/RILJ    ( 2795): [5658]> GET_CURRENT_CALLS
09-09 17:32:03.688 D/RILJ    ( 2795): [5659]> GET_CURRENT_CALLS
09-09 17:32:03.691 D/RilRequest( 2795): [5659]< GET_CURRENT_CALLS error: 
com.android.internal.telephony.CommandException: GENERIC_FAILURE ret=
09-09 17:32:03.693 I/RILQ    (  268): (0/268):RIL[0][event] 
qcril_qmi_get_call_list_to_send: RILVI: calls rep:[qmi call id 1, 
android call id 1, qmi call state 3] reported/skipped 1/0 calls
09-09 17:32:03.696 V/RILJ    ( 2795): Incoming UUS : NOT present!
09-09 17:32:03.696 D/RILJ    ( 2795): InCall VoicePrivacy is disabled
09-09 17:32:03.696 D/RILJ    ( 2795): [5658]< GET_CURRENT_CALLS  
[id=1,ACTIVE,toa=129,norm,mo,0,voc,noevp,,cli=1,,0] 
09-09 17:32:03.745 D/CdmaCallTracker( 2795): Event EVENT_POLL_CALLS_RESULT Received
09-09 17:32:03.745 D/CdmaCallTracker( 2795): Event EVENT_POLL_CALLS_RESULT Received
09-09 17:32:03.751 D/CallStateMonitor( 2795): handleMessage(10)
09-09 17:32:03.751 D/CallNotifier( 2795): PHONE_ENHANCED_VP_OFF...
09-09 17:32:03.752 I/Timeline( 2795): Timeline: Activity_idle id: 
android.os.BinderProxy@41bd7cc0 time:5637716
09-09 17:32:03.995 D/RILJ    ( 2795): [5660]> GET_CURRENT_CALLS
09-09 17:32:03.999 I/RILQ    (  268): (0/268):RIL[0][event] 
qcril_qmi_get_call_list_to_send: RILVI: calls rep:
[qmi call id 1, android call id 1, qmi call state 3] 
reported/skipped 1/0 calls
09-09 17:32:04.001 V/RILJ    ( 2795): Incoming UUS : NOT present!
09-09 17:32:04.002 D/RILJ    ( 2795): InCall VoicePrivacy is disabled
09-09 17:32:04.002 D/RILJ    ( 2795): [5660]< GET_CURRENT_CALLS 
[id=1,ACTIVE,toa=129,norm,mo,0,voc,noevp,,cli=1,,0] 
09-09 17:32:04.002 D/CdmaCallTracker( 2795): Event EVENT_POLL_CALLS_RESULT Received

从上面log可以看到,连续发出两次GET_CURRENT_CALLS请求之后,后面紧跟着会发出第三次,而且第二次查询失败了:

09-09 17:32:03.691 D/RilRequest( 2795): [5659]< GET_CURRENT_CALLS error: 
com.android.internal.telephony.CommandException: 
GENERIC_FAILURE ret=

首先,RILRequest是RILJ的内部类,在RILJ的processSolicited方法里也有:

   if (error != 0) {
       switch (rr.mRequest) {
         case RIL_REQUEST_ENTER_SIM_PIN:
         case RIL_REQUEST_ENTER_SIM_PIN2:
         case RIL_REQUEST_CHANGE_SIM_PIN:
         case RIL_REQUEST_CHANGE_SIM_PIN2:
         case RIL_REQUEST_SET_FACILITY_LOCK:
           if (mIccStatusChangedRegistrants != null) {
              if (RILJ_LOGD) {
              riljLog("ON some errors fakeSimStatusChanged: reg count="
                      + mIccStatusChangedRegistrants.size());
              }
              mIccStatusChangedRegistrants.notifyRegistrants();
            }
         break;
     }
    rr.onError(error, ret);
} 

当RILJ发出去的请求出错之后会进入这个if语句,最后进入RILRequest的onError方法。

 void onError(int error, Object ret) {
        CommandException ex;
        ex = CommandException.fromRilErrno(error);
        if (RIL.RILJ_LOGD) Rlog.d(LOG_TAG, serialString() + "< "
            + RIL.requestToString(mRequest)
            + " error: " + ex + " ret=" + RIL.retToString(mRequest, ret));

        if (mResult != null) {
            AsyncResult.forMessage(mResult, ret, ex);
            mResult.sendToTarget();
        }

        if (mParcel != null) {
            mParcel.recycle();
            mParcel = null;
        }
}

看到了吧,是在onError方法里打印出出错的log,mResult != null,所以下一步会回到CdmaCallTracker的handleMessage方法里,这个例子是打电话,所以这里处理的是EVENT_POLL_CALLS_RESULT的逻辑,下面这两行log也证明了会进入这里。

public void handleMessage (Message msg) {
     ...
   case EVENT_POLL_CALLS_RESULT:{
        Rlog.d(LOG_TAG, "Event EVENT_POLL_CALLS_RESULT Received");
        ar = (AsyncResult)msg.obj;
        if(msg == mLastRelevantPoll) {
          if(DBG_POLL) 
          log("handle EVENT_POLL_CALL_RESULT: set needsPoll=F");
          mNeedsPoll = false;
          mLastRelevantPoll = null;
          handlePollCalls((AsyncResult)msg.obj);
        }
     }
     break;
     ...
}


09-09 17:32:03.745 D/CdmaCallTracker( 2795): Event EVENT_POLL_CALLS_RESULT Received
09-09 17:32:03.745 D/CdmaCallTracker( 2795): Event EVENT_POLL_CALLS_RESULT Received

最后会进入handlePollCalls方法里。

protected void handlePollCalls(AsyncResult ar) {
        List polledCalls;
        if (ar.exception == null) {
            polledCalls = (List)ar.result;
        } else if (isCommandExceptionRadioNotAvailable(ar.exception)) {
            // just a dummy empty ArrayList to cause the loop
            // to hang up all the calls
            polledCalls = new ArrayList();
        } else {
            // Radio probably wasn't ready--try again in a bit
            // But don't keep polling if the channel is closed
            pollCallsAfterDelay();
            return;
        }
}

GET_CURRENT_CALLS error对应的是CommandException,所以跳过if和else if,进入else里,也就是进入pollCallsAfterDelay方法里,pollCallsAfterDelay方法在CdmaCallTracker的父类CallTracker中实现

 protected void pollCallsAfterDelay() {
        Message msg = obtainMessage();
        msg.what = EVENT_REPOLL_AFTER_DELAY;
        sendMessageDelayed(msg, POLL_DELAY_MSEC);
}

POLL_DELAY_MSEC的值是250,也就是说RILJ在250秒之后会重新发出GET_CURRENT_CALLS请求,所以我们最开始的假设是正确的!!!也就是说,在GET_CURRENT_CALLS失败之后,RILJ会重新发出GET_CURRENT_CALLS请求!

09-09 17:32:03.745 D/CdmaCallTracker( 2795): Event EVENT_POLL_CALLS_RESULT Received
...
09-09 17:32:03.995 D/RILJ    ( 2795): [5660]> GET_CURRENT_CALLS

从log中也可以看到“17:32:03.745”与“17:32:03.995”相差了250毫秒,我们上面的代码分析也是正确的!
这个问题也就讲到这里啦~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中创建`CAPABILITY_PLACE_EMERGENCY_CALLS`参数的方法取决于您的应用程序的需求和使用场景。以下是一种常见的做法: 1. 在AndroidManifest.xml文件中,确保您的应用程序具有以下权限声明: ```xml <uses-permission android:name="android.permission.CALL_PHONE" /> ``` 这将允许您的应用程序拨打电话。 2. 在您的应用程序代码中,您可以使用`TelecomManager`类来获取系统的通信服务并设置特定能力。首先,获取`TelecomManager`实例: ```java TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE); ``` 3. 接下来,您可以使用`telecomManager.registerPhoneAccount()`方法注册一个新的电话账户: ```java PhoneAccountHandle accountHandle = new PhoneAccountHandle(new ComponentName(this, YourPhoneAccountService.class), "YOUR_ACCOUNT_ID"); PhoneAccount.Builder builder = new PhoneAccount.Builder(accountHandle, "Your Phone Account"); builder.setCapabilities(PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS); PhoneAccount account = builder.build(); telecomManager.registerPhoneAccount(account); ``` 在上述代码中,您需要提供一个自定义的`YourPhoneAccountService`类,其中包含实现电话账户服务的逻辑代码。确保替换`YOUR_ACCOUNT_ID`和`Your Phone Account`为适当的值。 4. 最后,确保您的应用程序实现了所需的能力。检查能力是否已设置如下: ```java PhoneAccount account = telecomManager.getPhoneAccount(accountHandle); int capabilities = account.getCapabilities(); boolean canPlaceEmergencyCalls = (capabilities & PhoneAccount.CAPABILITY_PLACE_EMERGENCY_CALLS) != 0; ``` 通过检查`canPlaceEmergencyCalls`变量的值,您可以确定`CAPABILITY_PLACE_EMERGENCY_CALLS`参数是否已设置。 请注意,上述代码仅为示例,并且可能需要根据您的应用程序的具体要求进行调整和修改。确保在使用敏感权限和功能时遵循Android平台的最佳实践和安全准则。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值