OpenHarmony插入电信卡无法上网问题解决
·
默认APN匹配异常问题说明
问题现象
插入正常电信 SIM 卡后,移动数据无法上网。排查发现当 apnTypes 包含 * 的 APN 被优先选中时,默认数据连接建立失败。
问题根因
ApnItem::CanDealWithType() 的设计是“能力匹配”,*(DATA_CONTEXT_ROLE_ALL)对非 IA 类型返回 true 属于兜底语义,本身并非逻辑错误。
真正问题在于 ApnManager::FilterMatchedApns():
- 仅按
CanDealWithType()过滤,不区分“精确匹配”和“兜底匹配”; - 返回顺序依赖 APN 原始列表顺序;
- 当
*APN 排在defaultAPN 前面时,连接流程会优先尝试*APN,导致默认数据连接失败。
问题解决
采用“选择策略修复”,不修改 CanDealWithType() 的通用语义:
- 在
FilterMatchedApns()中为候选 APN 增加匹配评分:- 精确匹配(如
default -> default)优先级最高; - 别名匹配(
internal_default -> default)次之; *兜底匹配最低。
- 精确匹配(如
- 对匹配结果按评分进行稳定排序(
stable_sort),保证在相同评分下仍保持原有顺序。 - 这样既能保证
default/internal_default优先选择更合适的 APN,又保留*作为兜底能力,避免影响 DUN/MMS/SUPL 等其他场景。
该方案比直接将 * 分支改为 false 更稳妥,避免引入全局功能回归。
修改的patch如下:
--- a/cellular_data/services/src/apn_manager/apn_manager.cpp
+++ b/cellular_data/services/src/apn_manager/apn_manager.cpp
@@ -15,6 +15,9 @@
#include "apn_manager.h"
+#include <algorithm>
+#include <cctype>
+
#include "cellular_data_hisysevent.h"
#include "core_manager_inner.h"
#include "telephony_ext_wrapper.h"
@@ -81,6 +84,39 @@ constexpr const char *MO_ICCID_1 = "8985302";
constexpr const char *MO_ICCID_2 = "8985307";
constexpr const char *MO_UNICOM_MCCMNC = "46001";
constexpr int32_t ICCID_LEN_MINIMUM = 7;
+
+namespace {
+constexpr int32_t APN_MATCH_SCORE_NONE = 0;
+constexpr int32_t APN_MATCH_SCORE_WILDCARD = 1;
+constexpr int32_t APN_MATCH_SCORE_ALIAS = 2;
+constexpr int32_t APN_MATCH_SCORE_EXACT = 3;
+
+std::string ToLowerCase(std::string value)
+{
+ std::transform(value.begin(), value.end(), value.begin(),
+ [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
+ return value;
+}
+
+int32_t GetApnMatchScore(const sptr<ApnItem> &apnItem, const std::string &requestApnType)
+{
+ if (apnItem == nullptr) {
+ return APN_MATCH_SCORE_NONE;
+ }
+ int32_t maxScore = APN_MATCH_SCORE_NONE;
+ for (std::string apnType : apnItem->GetApnTypes()) {
+ apnType = ToLowerCase(apnType);
+ if (requestApnType == apnType) {
+ return APN_MATCH_SCORE_EXACT;
+ }
+ if (requestApnType == DATA_CONTEXT_ROLE_INTERNAL_DEFAULT && apnType == DATA_CONTEXT_ROLE_DEFAULT) {
+ maxScore = std::max(maxScore, APN_MATCH_SCORE_ALIAS);
+ continue;
+ }
+ if (requestApnType != DATA_CONTEXT_ROLE_IA && apnType == DATA_CONTEXT_ROLE_ALL) {
+ maxScore = std::max(maxScore, APN_MATCH_SCORE_WILDCARD);
+ }
+ }
+ return maxScore;
+}
+}
ApnManager::ApnManager() = default;
@@ -458,11 +494,18 @@ std::vector<sptr<ApnItem>> ApnManager::FilterMatchedApns(const std::string &req
FetchBipApns(matchApnItemList);
return matchApnItemList;
}
+ std::vector<std::pair<int32_t, sptr<ApnItem>>> scoredApnItems;
std::shared_lock<std::shared_mutex> lock(mutex_);
for (const sptr<ApnItem> &apnItem : allApnItem_) {
- if (apnItem->CanDealWithType(requestApnType)) {
- matchApnItemList.push_back(apnItem);
+ if (apnItem != nullptr && apnItem->CanDealWithType(requestApnType)) {
+ scoredApnItems.emplace_back(GetApnMatchScore(apnItem, requestApnType), apnItem);
}
}
+ std::stable_sort(scoredApnItems.begin(), scoredApnItems.end(),
+ [](const auto &left, const auto &right) { return left.first > right.first; });
+ for (const auto &item : scoredApnItems) {
+ matchApnItemList.emplace_back(item.second);
+ }
TELEPHONY_LOGD("apn size is :%{public}zu", matchApnItemList.size());
return matchApnItemList;
}
更多推荐

所有评论(0)