• 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 < 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 }
144 
GetMatchedApns() const145 std::vector<sptr<ApnItem>> ConnectionRetryPolicy::GetMatchedApns() const
146 {
147     return matchedApns_;
148 }
149 
OnPropChanged(const char * key,const char * value,void * context)150 void ConnectionRetryPolicy::OnPropChanged(const char *key, const char *value, void *context)
151 {
152     if ((key == nullptr) || (value == nullptr)) {
153         return;
154     }
155     if (strcmp(key, PROP_RETRY_STRATEGY_ALLOW) == 0) {
156         isPropOn_ = (strcmp(value, "true") == 0);
157     } else if ((strcmp(key, PROP_SETUP_FAIL_DELAY) == 0)) {
158         if (!ConvertStrToInt(value, defaultSetupFailDelay_)) {
159             TELEPHONY_LOGE("invalid value: %{public}s", value);
160         }
161     } else if ((strcmp(key, PROP_MODEM_DEND_DELAY) == 0)) {
162         if (!ConvertStrToInt(value, defaultModemDendDelay_)) {
163             TELEPHONY_LOGE("invalid value: %{public}s", value);
164         }
165     } else {
166         TELEPHONY_LOGI("invalid key: %{public}s", key);
167     }
168     TELEPHONY_LOGI("prop change: allow=%{public}d, delay=%{public}d,%{public}d", isPropOn_, defaultSetupFailDelay_,
169         defaultModemDendDelay_);
170 }
171 
ConvertPdpErrorToDisconnReason(int32_t reason)172 DisConnectionReason ConnectionRetryPolicy::ConvertPdpErrorToDisconnReason(int32_t reason)
173 {
174 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
175     if (isPropOn_ && TELEPHONY_EXT_WRAPPER.convertPdpError_) {
176         reason = TELEPHONY_EXT_WRAPPER.convertPdpError_(reason);
177     }
178 #endif
179     switch (reason) {
180         case PdpErrorReason::PDP_ERR_TO_NORMAL:
181             return DisConnectionReason::REASON_NORMAL;
182         case PdpErrorReason::PDP_ERR_TO_GSM_AND_CALLING_ONLY:
183             return DisConnectionReason::REASON_GSM_AND_CALLING_ONLY;
184         case PdpErrorReason::PDP_ERR_TO_CLEAR_CONNECTION:
185             return DisConnectionReason::REASON_CLEAR_CONNECTION;
186         case PdpErrorReason::PDP_ERR_TO_CHANGE_CONNECTION:
187             return DisConnectionReason::REASON_CHANGE_CONNECTION;
188         case PdpErrorReason::PDP_ERR_TO_PERMANENT_REJECT:
189         case PdpErrorReason::PDP_ERR_OPERATOR_DETERMINED_BARRING:
190         case PdpErrorReason::PDP_ERR_MISSING_OR_UNKNOWN_APN:
191         case PdpErrorReason::PDP_ERR_UNKNOWN_PDP_ADDR_OR_TYPE:
192         case PdpErrorReason::PDP_ERR_USER_VERIFICATION:
193         case PdpErrorReason::PDP_ERR_ACTIVATION_REJECTED_GGSN:
194         case PdpErrorReason::PDP_ERR_SERVICE_OPTION_NOT_SUPPORTED:
195         case PdpErrorReason::PDP_ERR_REQUESTED_SERVICE_OPTION_NOT_SUBSCRIBED:
196         case PdpErrorReason::PDP_ERR_NSAPI_ALREADY_USED:
197         case PdpErrorReason::PDP_ERR_IPV4_ONLY_ALLOWED:
198         case PdpErrorReason::PDP_ERR_IPV6_ONLY_ALLOWED:
199         case PdpErrorReason::PDP_ERR_PROTOCOL_ERRORS:
200             return DisConnectionReason::REASON_PERMANENT_REJECT;
201         default:
202             return DisConnectionReason::REASON_RETRY_CONNECTION;
203     }
204 }
205 
IsAllBadApn() const206 bool ConnectionRetryPolicy::IsAllBadApn() const
207 {
208     for (const auto &apn : matchedApns_) {
209         if (!apn->IsBadApn()) {
210             return false;
211         }
212     }
213     return true;
214 }
215 
GetRandomDelay()216 int64_t ConnectionRetryPolicy::GetRandomDelay()
217 {
218     std::random_device rd;
219     std::mt19937 gen(rd());
220     std::uniform_int_distribution<> dis(MIN_RANDOM_DELAY, MAX_RANDOM_DELAY);
221     return dis(gen);
222 }
223 
ConvertStrToInt(const std::string & str,int32_t & value)224 bool ConnectionRetryPolicy::ConvertStrToInt(const std::string& str, int32_t& value)
225 {
226     auto [ptr, ec] = std::from_chars(str.data(), str.data() + str.size(), value, BASE_10);
227     return ec == std::errc{} && ptr == str.data() + str.size();
228 }
229 
RestartRadioIfRequired(int32_t failCause,int32_t slotId)230 void ConnectionRetryPolicy::RestartRadioIfRequired(int32_t failCause, int32_t slotId)
231 {
232 #ifdef OHOS_BUILD_ENABLE_TELEPHONY_EXT
233     if (isPropOn_ && TELEPHONY_EXT_WRAPPER.restartRadioIfRequired_) {
234         TELEPHONY_EXT_WRAPPER.restartRadioIfRequired_(failCause, slotId);
235     }
236 #endif
237 }
238 } // namespace Telephony
239 } // namespace OHOS