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