• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "connection_retry_policy.h"
17 
18 #include <charconv>
19 #include <random>
20 #include "parameter.h"
21 
22 #include "telephony_log_wrapper.h"
23 #include "cellular_data_utils.h"
24 #include "telephony_ext_wrapper.h"
25 
26 namespace OHOS {
27 namespace Telephony {
28 static const char* PROP_RETRY_STRATEGY_ALLOW = "persist.telephony.retrystrategy.allow";
29 static const char* PROP_SETUP_FAIL_DELAY = "persist.telephony.setupfail.delay";
30 static const char* PROP_MODEM_DEND_DELAY = "persist.telephony.modemdend.delay";
31 static const char* DEFAULT_DELAY = "3000";
32 static const char* DEFAULT_RETRY_STRATEGY_ALLOW = "false";
33 static constexpr int16_t BASE_10 = 10;
34 static constexpr int32_t SYSPARA_SIZE = 8;
35 static constexpr int64_t DEFAULT_DELAY_FOR_INTERNAL_DEFAULT_APN_L = 60 * 1000;
36 static constexpr int64_t DEFAULT_DELAY_FOR_INTERNAL_DEFAULT_APN_S = 5 * 1000;
37 static constexpr int64_t DEFAULT_DELAY_FOR_OTHER_APN = 2 * 1000;
38 static constexpr int32_t MIN_RANDOM_DELAY = 0;
39 static constexpr int32_t MAX_RANDOM_DELAY = 2000;
40 
ConnectionRetryPolicy()41 ConnectionRetryPolicy::ConnectionRetryPolicy()
42 {
43     char retryStrategyAllow[SYSPARA_SIZE] = { 0 };
44     GetParameter(PROP_RETRY_STRATEGY_ALLOW, DEFAULT_RETRY_STRATEGY_ALLOW, retryStrategyAllow, SYSPARA_SIZE);
45     isPropOn_ = (strcmp(retryStrategyAllow, "true") == 0);
46     char setupFailDelay[SYSPARA_SIZE] = { 0 };
47     GetParameter(PROP_SETUP_FAIL_DELAY, DEFAULT_DELAY, setupFailDelay, SYSPARA_SIZE);
48     if (!ConvertStrToInt(setupFailDelay, defaultSetupFailDelay_)) {
49         TELEPHONY_LOGE("setupFailDelay is invalid: %{public}s", setupFailDelay);
50     }
51     char modemDendDelay[SYSPARA_SIZE] = { 0 };
52     GetParameter(PROP_MODEM_DEND_DELAY, DEFAULT_DELAY, modemDendDelay, SYSPARA_SIZE);
53     if (!ConvertStrToInt(modemDendDelay, defaultModemDendDelay_)) {
54         TELEPHONY_LOGE("modemDendDelay is invalid: %{public}s", modemDendDelay);
55     }
56     WatchParameter(PROP_RETRY_STRATEGY_ALLOW, OnPropChanged, this);
57     WatchParameter(PROP_SETUP_FAIL_DELAY, OnPropChanged, this);
58     WatchParameter(PROP_MODEM_DEND_DELAY, OnPropChanged, this);
59 }
60 
GetNextRetryApnItem() const61 sptr<ApnItem> ConnectionRetryPolicy::GetNextRetryApnItem() const
62 {
63     if ((matchedApns_.empty()) || IsAllBadApn()) {
64         TELEPHONY_LOGE("matchedApns is null, or all bad apns");
65         return nullptr;
66     }
67     if (currentApnIndex_ >= static_cast<int32_t>(matchedApns_.size()) || currentApnIndex_ < 0) {
68         currentApnIndex_ = 0;
69         tryCount_ = 0;
70     }
71     sptr<ApnItem> apnItem = matchedApns_[currentApnIndex_];
72     tryCount_++;
73     if ((apnItem != nullptr && apnItem->IsBadApn()) || (tryCount_ > maxCount_)) {
74         TELEPHONY_LOGI("try next non-bad apn");
75         tryCount_ = 0;
76         currentApnIndex_++;
77         return GetNextRetryApnItem();
78     }
79     return apnItem;
80 }
81 
SetMatchedApns(std::vector<sptr<ApnItem>> & apns)82 void ConnectionRetryPolicy::SetMatchedApns(std::vector<sptr<ApnItem>> &apns)
83 {
84     if (matchedApns_.size() != apns.size()) {
85         TELEPHONY_LOGI("reset currentApnIndex");
86         currentApnIndex_ = 0;
87     } else {
88         for (int32_t i = 0; i < static_cast<int32_t>(apns.size()); i++) {
89             if (apns[i]->attr_.profileId_ != matchedApns_[i]->attr_.profileId_) {
90                 TELEPHONY_LOGI("reset currentApnIndex");
91                 currentApnIndex_ = 0;
92                 break;
93             }
94         }
95     }
96     matchedApns_ = apns;
97 }
98 
ClearRetryApns()99 void ConnectionRetryPolicy::ClearRetryApns()
100 {
101     matchedApns_.clear();
102 }
103 
MarkBadApn(ApnItem & apn)104 void ConnectionRetryPolicy::MarkBadApn(ApnItem &apn)
105 {
106     // The APN that fails after multiple retries is true
107     apn.MarkBadApn(true);
108 }
109 
GetNextRetryDelay(std::string apnType,int32_t cause,int64_t suggestTime,RetryScene scene,bool isDefaultApnRetrying)110 int64_t ConnectionRetryPolicy::GetNextRetryDelay(std::string apnType, int32_t cause, int64_t suggestTime,
111     RetryScene scene, bool isDefaultApnRetrying)
112 {
113     int64_t retryDelay = GetRandomDelay();
114     if (apnType == DATA_CONTEXT_ROLE_INTERNAL_DEFAULT) {
115         retryDelay += isDefaultApnRetrying ? DEFAULT_DELAY_FOR_INTERNAL_DEFAULT_APN_L :
116             DEFAULT_DELAY_FOR_INTERNAL_DEFAULT_APN_S;
117     } else if (apnType == DATA_CONTEXT_ROLE_DEFAULT) {
118         if (scene == RetryScene::RETRY_SCENE_MODEM_DEACTIVATE) {
119             retryDelay += defaultModemDendDelay_;
120         } else {
121             retryDelay += defaultSetupFailDelay_;
122         }
123 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
124         int64_t updatedDelay = 0;
125         if (isPropOn_ && TELEPHONY_EXT_WRAPPER.handleDendFailcause_) {
126             updatedDelay = TELEPHONY_EXT_WRAPPER.handleDendFailcause_(cause, suggestTime);
127         }
128         if (updatedDelay > 0) {
129             retryDelay = updatedDelay;
130         }
131 #endif
132     } else {
133         retryDelay += DEFAULT_DELAY_FOR_OTHER_APN;
134     }
135     TELEPHONY_LOGI("%{public}s: cause=%{public}d, suggestTime=%{public}lld, tryCnt=%{public}d, delay=%{public}lld",
136         apnType.c_str(), cause, static_cast<long long>(suggestTime), tryCount_, static_cast<long long>(retryDelay));
137     return retryDelay;
138 }
139 
InitialRetryCountValue()140 void ConnectionRetryPolicy::InitialRetryCountValue()
141 {
142     tryCount_ = 0;
143 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
144     if (isPropOn_ && TELEPHONY_EXT_WRAPPER.handleDendFailcause_) {
145         TELEPHONY_EXT_WRAPPER.handleDendFailcause_(0, 0);
146     }
147 #endif
148 }
149 
GetMatchedApns() const150 std::vector<sptr<ApnItem>> ConnectionRetryPolicy::GetMatchedApns() const
151 {
152     return matchedApns_;
153 }
154 
OnPropChanged(const char * key,const char * value,void * context)155 void ConnectionRetryPolicy::OnPropChanged(const char *key, const char *value, void *context)
156 {
157     if ((key == nullptr) || (value == nullptr)) {
158         return;
159     }
160     if (strcmp(key, PROP_RETRY_STRATEGY_ALLOW) == 0) {
161         isPropOn_ = (strcmp(value, "true") == 0);
162     } else if ((strcmp(key, PROP_SETUP_FAIL_DELAY) == 0)) {
163         if (!ConvertStrToInt(value, defaultSetupFailDelay_)) {
164             TELEPHONY_LOGE("invalid value: %{public}s", value);
165         }
166     } else if ((strcmp(key, PROP_MODEM_DEND_DELAY) == 0)) {
167         if (!ConvertStrToInt(value, defaultModemDendDelay_)) {
168             TELEPHONY_LOGE("invalid value: %{public}s", value);
169         }
170     } else {
171         TELEPHONY_LOGI("invalid key: %{public}s", key);
172     }
173     TELEPHONY_LOGI("prop change: allow=%{public}d, delay=%{public}d,%{public}d", isPropOn_, defaultSetupFailDelay_,
174         defaultModemDendDelay_);
175 }
176 
ConvertPdpErrorToDisconnReason(int32_t reason)177 DisConnectionReason ConnectionRetryPolicy::ConvertPdpErrorToDisconnReason(int32_t reason)
178 {
179 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
180     if (isPropOn_ && TELEPHONY_EXT_WRAPPER.convertPdpError_) {
181         reason = TELEPHONY_EXT_WRAPPER.convertPdpError_(reason);
182     }
183 #endif
184     switch (reason) {
185         case PdpErrorReason::PDP_ERR_TO_NORMAL:
186             return DisConnectionReason::REASON_NORMAL;
187         case PdpErrorReason::PDP_ERR_TO_GSM_AND_CALLING_ONLY:
188             return DisConnectionReason::REASON_GSM_AND_CALLING_ONLY;
189         case PdpErrorReason::PDP_ERR_TO_CLEAR_CONNECTION:
190             return DisConnectionReason::REASON_CLEAR_CONNECTION;
191         case PdpErrorReason::PDP_ERR_TO_CHANGE_CONNECTION:
192             return DisConnectionReason::REASON_CHANGE_CONNECTION;
193         case PdpErrorReason::PDP_ERR_TO_PERMANENT_REJECT:
194         case PdpErrorReason::PDP_ERR_OPERATOR_DETERMINED_BARRING:
195         case PdpErrorReason::PDP_ERR_MISSING_OR_UNKNOWN_APN:
196         case PdpErrorReason::PDP_ERR_UNKNOWN_PDP_ADDR_OR_TYPE:
197         case PdpErrorReason::PDP_ERR_USER_VERIFICATION:
198         case PdpErrorReason::PDP_ERR_ACTIVATION_REJECTED_GGSN:
199         case PdpErrorReason::PDP_ERR_SERVICE_OPTION_NOT_SUPPORTED:
200         case PdpErrorReason::PDP_ERR_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED:
201         case PdpErrorReason::PDP_ERR_NSAPI_ALREADY_USED:
202         case PdpErrorReason::PDP_ERR_IPV4_ONLY_ALLOWED:
203         case PdpErrorReason::PDP_ERR_IPV6_ONLY_ALLOWED:
204         case PdpErrorReason::PDP_ERR_PROTOCOL_ERRORS:
205             return DisConnectionReason::REASON_PERMANENT_REJECT;
206         default:
207             return DisConnectionReason::REASON_RETRY_CONNECTION;
208     }
209 }
210 
IsAllBadApn() const211 bool ConnectionRetryPolicy::IsAllBadApn() const
212 {
213     for (const auto &apn : matchedApns_) {
214         if (!apn->IsBadApn()) {
215             return false;
216         }
217     }
218     return true;
219 }
220 
GetRandomDelay()221 int64_t ConnectionRetryPolicy::GetRandomDelay()
222 {
223     std::random_device rd;
224     std::mt19937 gen(rd());
225     std::uniform_int_distribution<> dis(MIN_RANDOM_DELAY, MAX_RANDOM_DELAY);
226     return dis(gen);
227 }
228 
ConvertStrToInt(const std::string & str,int32_t & value)229 bool ConnectionRetryPolicy::ConvertStrToInt(const std::string& str, int32_t& value)
230 {
231     auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value, BASE_10);
232     return ec == std::errc{} && ptr == str.data() + str.size();
233 }
234 
RestartRadioIfRequired(int32_t failCause,int32_t slotId)235 void ConnectionRetryPolicy::RestartRadioIfRequired(int32_t failCause, int32_t slotId)
236 {
237 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
238     if (isPropOn_ && TELEPHONY_EXT_WRAPPER.restartRadioIfRequired_) {
239         TELEPHONY_EXT_WRAPPER.restartRadioIfRequired_(failCause, slotId);
240     }
241 #endif
242 }
243 } // namespace Telephony
244 } // namespace OHOS