高通平台IA APN问题分析之一

1、问题描述

在android 5G产品开发过程中,通过UI设置APN后,OTA空口发现APN并未使用UI设置的APN,将相关问题分析记录如下。

2、qcril-nr中设置 IA APN 流程

1、设置IA APN时通过函数getAttachListSync,QMI对应QMI_WDS_GET_LTE_ATTACH_PDN_LIST_REQ_V01,获取所有attach apn list。当attach apn list不为空 ,调用函数compareModemAttachParams比对APN是否和modem attach的参数是否一致。

cpp 复制代码
void ProfileHandler::handleInitialAttachRequest(std::shared_ptr<Message> msg)
{
  std::shared_ptr<SetInitialAttachApnRequestMessage> m =
       std::static_pointer_cast<SetInitialAttachApnRequestMessage>(msg);
  Log::getInstance().d("[ProfileHandler]: Handling: " + msg->dump());
  if( m != NULL ) {
    requestProfile = m->mProfile;
    if(mPendingMessage != nullptr)
    {
      Log::getInstance().d("[ProfileHandler] Received another IA, Stopping retry timer.");
      sendSetInitialAttachResponse(RIL_E_INTERNAL_ERR);
    }
    mPendingMessage = msg;

    if(!wds_endpoint)
    {
      Log::getInstance().d("[ProfileHandler] wds_endpoint is NULL. Sending error response");
      sendSetInitialAttachResponse(RIL_E_GENERIC_FAILURE);
      return;
    }
    
    //1、获取所以attach list apn
    Message::Callback::Status status = wds_endpoint->getAttachListSync(attach_list);
    {
      Log::getInstance().d("[ProfileHandler] failed to get attach list, result="
                           + std::to_string((int) status));
      sendSetInitialAttachResponse(RIL_E_OEM_ERROR_3);
      return;
    }
    if(attach_list == nullptr) {
      Log::getInstance().d("Modem Attach list is NULL. Returning Failure response");
      sendSetInitialAttachResponse(RIL_E_GENERIC_FAILURE);
      return;
    }

    {
      stringstream ss;
      ss << "Attach List:";
      copy(attach_list->begin(), attach_list->end(), ostream_iterator<int>(ss, ","));
      Log::getInstance().d("[ProfileHandler] " + ss.str());
      logBuffer.addLogWithTimestamp(ss.str());
    }
    //Check if first profile in attach list is a null profile
    //2、当attach apn list不为空 ,调用函数compareModemAttachParams比对APN是否和modem attach的参数是否一致.
    if (!attach_list->empty() && isNullProfile(attach_list->front())) {
      compareModemAttachParams();
    }
    else {
      initialAttachHandler();
    }
  }
}

2、使用QMI获取QMI_WDS_GET_LTE_ATTACH_PARAMS_REQ_V01 modem attach网络参数, 对比modem中APN是否一直,如果一致,直接返回成功

cpp 复制代码
void ProfileHandler::compareModemAttachParams()
{
  wds_get_lte_attach_params_resp_msg_v01 curr_attach_params;
  memset(&curr_attach_params, 0x0, sizeof(curr_attach_params));
  if (!wds_endpoint)
  {
    sendSetInitialAttachResponse(RIL_E_INTERNAL_ERR);
    return;
  }
  //3、获取modem attch参数,可能为空
  auto rc = wds_endpoint->getLteAttachParams(&curr_attach_params);
  if (rc == Message::Callback::Status::SUCCESS)
  {
    if (curr_attach_params.resp.result == QMI_RESULT_SUCCESS_V01)
    {
      if (!matchModemProfileParams(&curr_attach_params,requestProfile.apn,requestProfile.protocol))
      {
        Log::getInstance().d("[ProfileHandler] : Modem attach params did not match, fallback to inital attach logic");
        initialAttachHandler();
      }
      else {
        //4、modem参数和ap设置的参数完全一致,直接返回成功
        sendSetInitialAttachResponse(RIL_E_SUCCESS);
      }
      return;
    }
     else if ((curr_attach_params.resp.result == QMI_RESULT_FAILURE_V01) &&
             (curr_attach_params.resp.error == QMI_ERR_OP_IN_PROGRESS_V01))
    {
      if(mIARetry == MAX_IA_RETRY_ATTEMPT)
      {
        Log::getInstance().d("[ProfileHandler] : Reached maximum retries for GET_LTE_ATTACH_PARAMS");
        sendSetInitialAttachResponse(RIL_E_INTERNAL_ERR);
        return;
      }
      else {
        Log::getInstance().d("[ProfileHandler] : Starting Retry Attach Timer");
        auto timeoutFn = std::bind(&ProfileHandler::getAttachParamsTimeoutHander, this, std::placeholders::_1);
        mIARetryAttachTimer = TimeKeeper::getInstance().set_timer(timeoutFn, nullptr, RETRY_ATTACH_TIMEOUT);
        return;
      }
    }
  }
  //for any other scenario fallback to the initial attach logic
  initialAttachHandler();
}

3、如果不匹配,调用initialAttachHandler进行进一步的处理

cpp 复制代码
void ProfileHandler::initialAttachHandler( )
{
  RIL_Errno result = RIL_E_SUCCESS;
  Log::getInstance().d("[ProfileHandler] initialAttachHandler ENTRY");

  if (!attach_list) {
    Log::getInstance().d("[ProfileHandler] attachlist is NULL");
    sendSetInitialAttachResponse(RIL_E_INTERNAL_ERR);
    return;
  }
  // Check if requestProfile matches any of the the attached profiles
  ProfileHandler::AttachResponse resp = matchAttachProfile(*attach_list);
  
  //5、检查attch apn是否在attach_list中,如果modem存在
  if ( resp == SUCCESS )
  {
    attachProfileKey = util.findOrCreateProfileForLteAttach(convertDataProfileInfoToProfileParams(requestProfile));
    if (attachProfileKey == nullptr)
    {
      Log::getInstance().d("[ProfileHandler] No matching profile found "
                           "and failed to create new profile");
      Log::getInstance().d("EXIT with FAILURE" );
      result = RIL_E_OEM_ERROR_3;
      sendSetInitialAttachResponse(RIL_E_OEM_ERROR_3);
      return;
    }
    // update attach list
    if( !(attach_list->empty()) )
    {
      attach_list->pop_front();
    }
    attach_list->push_front(attachProfileKey->getProfileId());
    {
      stringstream ss;
      ss << "New Attach List:";
      copy(attach_list->begin(), attach_list->end(), ostream_iterator<int>(ss, ","));
      Log::getInstance().d("[ProfileHandler] " + ss.str());
      logBuffer.addLogWithTimestamp(ss.str());
    }

    //6、更新modem profile num,更新到modem
    if(requestProfile.preferred &&
      ((int)requestProfile.supportedApnTypesBitmap & (int)ApnTypes_t::DEFAULT) == (int)ApnTypes_t::DEFAULT) {
      Log::getInstance().d("[ProfileHandler] Setting default profile to profileId " + std::to_string(attachProfileKey->getProfileId()));
      wds_endpoint->setDefaultProfileNum(attachProfileKey->getTechType(), attachProfileKey->getProfileId());
    }

    /* Three Cases:

       1st Case:
       Non-LTE RAT: If the current RAT is non-LTE, then we update the attach list
       only.  Detach/Attach request is not sent to modem.

       If the current RAT is LTE & PS Service is available,
       2nd Case:
       LTE( PS Service Available) + DDS SUB: We send Detach request to modem &
       after detach is complete, we update the 'attach list' on modem.
       Later Attach request is sent to modem.

       3rd Case:
       LTE( PS Service Available) + Non-DDS SUB: We update the attach list first &
       then issue Detach request to modem. After receiving Detach response from modem,
       we send this as IA response to telephony without waiting for Detach Indication.
       So IA request ends here. Attach request is NOT sent to modem.
    */

    //7、同步apn list到modem
    AttachResult res = setAttachList();
    if ( res == AttachResult::DETACH_NEEDED)
    {
      Log::getInstance().d("[ProfileHandler] :: Legacy method. Obsolete with newer modem versions");
      result = RIL_E_INTERNAL_ERR;
    }
    else if ( res == AttachResult::GENERIC_FAILURE )
    {
      // in the event that attach list update failed due to a QMI error
      // we need to notify RIL
      Log::getInstance().d("[ProfileHandler] GENERIC_FAILURE"
                         "Sending error response");
      result = RIL_E_INTERNAL_ERR;
    }
    #ifdef QMI_RIL_UTF
    releaseQdpAttachProfile();
    #endif
  }
  else
  {
    if (!mApAssistMode && dsd_endpoint)
    {
      dsd_endpoint->setApnInfoSync(requestProfile.apn,
                                            requestProfile.supportedApnTypesBitmap);
    } else
    {
      Log::getInstance().d("[ProfileHandler] Did not update apn types.");
    }
    Log::getInstance().d("[ProfileHandler] Skipping reattach");
    result = RIL_E_SUCCESS;
  }
  sendSetInitialAttachResponse(RIL_E_SUCCESS);
}

4、如果匹配attach_list,通过函数setDefaultProfileNum更新modem对应的profile id,通过函数setAttachList更新modem apn list。

3、对应Log分析

1、RILJ Log

09-28 11:03:18.325 2765 4074 D RILJ : 0500> SET_INITIAL_ATTACH_APNDataProfile=\[ApnSetting UC_APN_VSIM_1, 3206, 46006, 3gnet, , null, , null, null, 0, supl | hipri | default | ia, IP, IP, true, 0, false, 0, 0, 0, 0, 0, imsi, 460060042315337, false, UNKNOWN, UNKNOWN, 0, -1, -1, false, -1762095381, TrafficDescriptor={mDnn=3gnet, null}, preferred=false] PHONE0

09-28 11:03:18.338 2765 3425 D RILJ : 0500< SET_INITIAL_ATTACH_APN PHONE0

2、qcril log ,过滤qcril log,检索ProfileHandler

3、QMI Log ,检索关键字WDS_GET_LTE_ATTACH_PDN_LIST|WDS_SET_LTE_ATTACH_PDN_LIST|WDS_GET_LTE_ATTACH_PARAMS|WDS_SET_DEFAULT_PROFILE_NUM

4、OTA Log,5G OTA可以检索dnn

  1. 两种场景(解释你抓包看到 "请求 DNN 和 Accept 返回 DNN 不一致")

场景 A:安卓 APN 配置正常映射,UE Request 携带 DNN

安卓选中的 APN=`cmnet` → RIL 把`cmnet`作为 DNN 写入 PDU Session Establishment Request。

  • 网络收到这个 DNN;

  • 如果签约里这个 DNN 不允许,运营商策略允许 fallback,SMF 就返回签约的默认 DNN,于是 Accept 消息里 DNN 变了。

这就是你前面遇到的现象:UE 请求 DNN(源自安卓 APN),网络返回另一个 DNN。

场景 B:UE 不携带 DNN(非常常见!)

安卓在 5G SA 下,可以不填 DNN IE 直接发 PDU 会话建立请求(URSP 规则驱动、默认数据会话):

  1. 安卓不把 APN 映射上去,PDU Session Establishment Request 里 DNN IE 不存在;

  2. SMF 查 UDM 签约,在当前 S-NSSAI 切片下取该用户默认 DNN;

  3. 在 PDU Session Establishment Accept 里把这个默认 DNN 带回给 UE;

  4. 抓包看到:请求消息没有 DNN,Accept 带回 DNN;

  5. 你拿安卓 APN 页面的 APN 名字,和 Accept 里 DNN 对比 → 自然对不上。

4、对比之前Android 4G产品分析

对应之前的4G产品,4G产品使用qcrild,5G产品使用qcrilNrd

4G使用了/vendor/qcom/proprietary/qcril-hal代码,5G产品使用了/vendor/qcom/proprietary/qcril-nr代码

其中设置IA APN时,需要deatch apn

重新Attach时,更新APN

其中qcril log处理逻和5G平台类似

相关推荐
rtu遥测终端机1 小时前
四信助力无人车远程接管与遥操作,低时延通信是安全底线
物联网·自动驾驶
a5986522 小时前
Docker多开云手机,六边云独立端口隔离访问实战
android·运维·docker·容器·智能手机·云手机
峥嵘life2 小时前
Android16 开机后立即打开相机闪退问题分析与解决总结
android·开发语言·数码相机·策略模式
用户2018792831672 小时前
从点击图标到首帧"上菜":一篇吃透 Android 启动优化原理
android
镜象科技3 小时前
职业院校AI心理健康解决方案是什么?从一台设备到全周期守护
android·人工智能
MuMuMu12234 小时前
越华环保集团碳惠小屋:物联网 + 区块链,构建碳普惠终端数据可信与隐私保护体系
物联网·区块链
码上有光4 小时前
Linux:信号的认识、信号的产生、信号的保存、信号的处理
android·linux·运维·信号