1 /*
2 * Copyright (C) 2024-2025 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 "spam_call_adapter.h"
17
18 #include "call_manager_base.h"
19 #include "call_manager_info.h"
20 #include "extension_manager_client.h"
21 #include "ipc_skeleton.h"
22 #include "nlohmann/json.hpp"
23 #include "telephony_log_wrapper.h"
24 #include "cJSON.h"
25 #include <securec.h>
26 #include "time_wait_helper.h"
27 #include "spam_call_connection.h"
28 #include "common_event_manager.h"
29 #include "common_event_support.h"
30 #include "telephony_permission.h"
31
32 namespace OHOS {
33 namespace Telephony {
34 constexpr int32_t DEFAULT_USER_ID = -1;
35 constexpr int16_t INCOMING_CALL_MISSED_CODE = 0;
36 constexpr char REMINDER_RESULT[] = "reminderResult";
37 constexpr char SLOT_ID[] = "slotId";
38 constexpr char DETECT_RESULT[] = "detectResult";
39 constexpr char DECISION_REASON[] = "decisionReason";
40 constexpr char MARK_TYPE[] = "markType";
41 constexpr char MARK_COUNT[] = "markCount";
42 constexpr char MARK_SOURCE[] = "markSource";
43 constexpr char MARK_CONTENT[] = "markContent";
44 constexpr char IS_CLOUD[] = "isCloud";
45 sptr<SpamCallConnection> connection_ = nullptr;
46
SpamCallAdapter()47 SpamCallAdapter::SpamCallAdapter()
48 {
49 timeWaitHelper_ = std::make_unique<TimeWaitHelper>(WAIT_TIME_FIVE_SECOND);
50 }
51
~SpamCallAdapter()52 SpamCallAdapter::~SpamCallAdapter()
53 {
54 TELEPHONY_LOGI("~SpamCallAdapter");
55 }
56
DetectSpamCall(const std::string & phoneNumber,const int32_t & slotId)57 bool SpamCallAdapter::DetectSpamCall(const std::string &phoneNumber, const int32_t &slotId)
58 {
59 TELEPHONY_LOGI("DetectSpamCall start");
60 phoneNumber_ = phoneNumber;
61 AAFwk::Want want;
62 std::string bundleName = "com.spamshield";
63 std::string abilityName = "SpamShieldServiceExtAbility";
64 want.SetElementName(bundleName, abilityName);
65 bool connectResult = ConnectSpamCallAbility(want, phoneNumber, slotId);
66 if (!connectResult) {
67 TELEPHONY_LOGE("DetectSpamCall failed!");
68 return false;
69 }
70 return true;
71 }
72
ConnectSpamCallAbility(const AAFwk::Want & want,const std::string & phoneNumber,const int32_t & slotId)73 bool SpamCallAdapter::ConnectSpamCallAbility(const AAFwk::Want &want, const std::string &phoneNumber,
74 const int32_t &slotId)
75 {
76 std::lock_guard<ffrt::mutex> lock(mutex_);
77 TELEPHONY_LOGI("ConnectSpamCallAbility start");
78 connection_ = new (std::nothrow) SpamCallConnection(phoneNumber, slotId,
79 shared_from_this());
80 if (connection_ == nullptr) {
81 TELEPHONY_LOGE("connection_ is nullptr");
82 return false;
83 }
84 std::string identity = IPCSkeleton::ResetCallingIdentity();
85 auto connectResult = AAFwk::ExtensionManagerClient::GetInstance().ConnectServiceExtensionAbility(want,
86 connection_, nullptr, DEFAULT_USER_ID);
87 IPCSkeleton::SetCallingIdentity(identity);
88 if (connectResult != 0) {
89 TELEPHONY_LOGE("ConnectServiceExtensionAbility Failed!");
90 return false;
91 }
92 return true;
93 }
94
DisconnectSpamCallAbility()95 void SpamCallAdapter::DisconnectSpamCallAbility()
96 {
97 std::lock_guard<ffrt::mutex> lock(mutex_);
98 TELEPHONY_LOGI("DisconnectSpamCallAbility start");
99 if (connection_ == nullptr) {
100 TELEPHONY_LOGE("connection_ is nullptr");
101 return;
102 }
103 auto disconnectResult = AAFwk::ExtensionManagerClient::GetInstance().DisconnectAbility(connection_);
104 connection_.clear();
105 if (disconnectResult != 0) {
106 TELEPHONY_LOGE("DisconnectAbility failed! %d", disconnectResult);
107 }
108 }
109
JsonGetNumberValue(cJSON * json,const std::string key,int32_t & out)110 bool SpamCallAdapter::JsonGetNumberValue(cJSON *json, const std::string key, int32_t &out)
111 {
112 do {
113 cJSON *cursor = cJSON_GetObjectItem(json, key.c_str());
114 if (!cJSON_IsNumber(cursor)) {
115 TELEPHONY_LOGE("ParseNumberValue failed to get %{public}s", key.c_str());
116 if (key == "detectResult" || key == "decisionReason") {
117 return false;
118 }
119 }
120 out = static_cast<int32_t>(cJSON_GetNumberValue(cursor));
121 } while (0);
122 return true;
123 }
124
JsonGetStringValue(cJSON * json,const std::string key,std::string & out)125 bool SpamCallAdapter::JsonGetStringValue(cJSON *json, const std::string key, std::string &out)
126 {
127 do {
128 cJSON *cursor = cJSON_GetObjectItem(json, key.c_str());
129 if (!cJSON_IsString(cursor)) {
130 TELEPHONY_LOGE("ParseStringValue failed to get %{public}s", key.c_str());
131 }
132 char *value = cJSON_GetStringValue(cursor);
133 if (value != nullptr) {
134 out = value;
135 }
136 } while (0);
137 return true;
138 }
139
JsonGetBoolValue(cJSON * json,const std::string key)140 bool SpamCallAdapter::JsonGetBoolValue(cJSON *json, const std::string key)
141 {
142 cJSON *cursor = cJSON_GetObjectItem(json, key.c_str());
143 bool value = cJSON_IsTrue(cursor);
144 TELEPHONY_LOGI("ParseBoolValue %{public}s: %{public}d", key.c_str(), value);
145 return value;
146 }
147
ParseNeedNotifyResult(const std::string & jsonData)148 void SpamCallAdapter::ParseNeedNotifyResult(const std::string &jsonData)
149 {
150 if (jsonData.empty()) {
151 return;
152 }
153 const char *data = jsonData.c_str();
154 cJSON *root = cJSON_Parse(data);
155 if (root == nullptr) {
156 TELEPHONY_LOGE("ParseNeedNotifyResult failed to parse JSON");
157 return;
158 }
159 int32_t slotId = 0;
160 if (!JsonGetNumberValue(root, SLOT_ID, slotId)) {
161 cJSON_Delete(root);
162 return;
163 }
164 bool result = JsonGetBoolValue(root, REMINDER_RESULT);
165 TELEPHONY_LOGI("result: %{public}d, slotId: %{public}d", result, slotId);
166 if (result) {
167 TELEPHONY_LOGI("send notify to contacts");
168 AAFwk::Want want;
169 want.SetParam("isHarassmentGuidance", true);
170 want.SetParam("slotId", slotId);
171 want.SetAction(EventFwk::CommonEventSupport::COMMON_EVENT_INCOMING_CALL_MISSED);
172 EventFwk::CommonEventData eventData;
173 eventData.SetWant(want);
174 EventFwk::CommonEventPublishInfo publishInfo;
175 std::vector<std::string> callPermissions;
176 callPermissions.emplace_back(Permission::GET_TELEPHONY_STATE);
177 publishInfo.SetSubscriberPermissions(callPermissions);
178 if (!EventFwk::CommonEventManager::PublishCommonEvent(eventData, publishInfo, nullptr)) {
179 TELEPHONY_LOGE("PublishCommonEvent fail.");
180 }
181 }
182 }
183
ParseDetectResult(const std::string & jsonData,bool & isBlock,NumberMarkInfo & info,int32_t & blockReason)184 void SpamCallAdapter::ParseDetectResult(const std::string &jsonData, bool &isBlock,
185 NumberMarkInfo &info, int32_t &blockReason)
186 {
187 if (jsonData.empty()) {
188 return;
189 }
190 const char *data = jsonData.c_str();
191 cJSON *root = cJSON_Parse(data);
192 if (root == nullptr) {
193 TELEPHONY_LOGE("ParseDetectResult failed to parse JSON");
194 return;
195 }
196 int32_t numberValue = 0;
197 if (!JsonGetNumberValue(root, DETECT_RESULT, numberValue)) {
198 TELEPHONY_LOGE("ParseDetectResult no detectResult");
199 cJSON_Delete(root);
200 return;
201 }
202 isBlock = numberValue == 1;
203 TELEPHONY_LOGI("DetectSpamCall detectResult: %{public}d", isBlock);
204 if (!JsonGetNumberValue(root, DECISION_REASON, numberValue)) {
205 TELEPHONY_LOGE("ParseDetectResult no decisionReason");
206 cJSON_Delete(root);
207 return;
208 }
209 blockReason = numberValue;
210 TELEPHONY_LOGI("DetectSpamCall decisionReason: %{public}d", blockReason);
211 ParseMarkResults(info, root, isBlock);
212 cJSON_Delete(root);
213 }
214
ParseMarkResults(NumberMarkInfo & info,cJSON * root,bool isBlock)215 void SpamCallAdapter::ParseMarkResults(NumberMarkInfo &info, cJSON *root, bool isBlock)
216 {
217 int32_t numberValue = 0;
218 std::string stringValue = "";
219 JsonGetNumberValue(root, MARK_TYPE, numberValue);
220 info.markType = static_cast<MarkType>(numberValue);
221 TELEPHONY_LOGI("DetectSpamCall markType: %{public}d", info.markType);
222 if (!isBlock && (info.markType == MarkType::MARK_TYPE_CRANK || info.markType == MarkType::MARK_TYPE_FRAUD ||
223 info.markType == MarkType::MARK_TYPE_PROMOTE_SALES || info.markType == MarkType::MARK_TYPE_HOUSE_AGENT)) {
224 connection_->RequireCallReminder();
225 }
226 JsonGetNumberValue(root, MARK_COUNT, numberValue);
227 info.markCount = numberValue;
228 JsonGetStringValue(root, MARK_SOURCE, stringValue);
229 if (strcpy_s(info.markSource, sizeof(info.markSource), stringValue.c_str()) != EOK) {
230 TELEPHONY_LOGE("strcpy_s markSource fail.");
231 }
232 JsonGetStringValue(root, MARK_CONTENT, stringValue);
233 if (strcpy_s(info.markContent, sizeof(info.markContent), stringValue.c_str()) != EOK) {
234 TELEPHONY_LOGE("strcpy_s markContent fail.");
235 }
236 info.isCloud = JsonGetBoolValue(root, IS_CLOUD);
237 }
238
GetDetectResult(int32_t & errCode,std::string & result)239 void SpamCallAdapter::GetDetectResult(int32_t &errCode, std::string &result)
240 {
241 errCode = errCode_;
242 result = result_;
243 }
244
SetDetectResult(int32_t & errCode,std::string & result)245 void SpamCallAdapter::SetDetectResult(int32_t &errCode, std::string &result)
246 {
247 errCode_ = errCode;
248 result_ = result;
249 }
250
GetParseResult(bool & isBlock,NumberMarkInfo & info,int32_t & blockReason)251 void SpamCallAdapter::GetParseResult(bool &isBlock, NumberMarkInfo &info, int32_t &blockReason)
252 {
253 isBlock = isBlock_;
254 info = info_;
255 blockReason = blockReason_;
256 }
257
SetParseResult(bool & isBlock,NumberMarkInfo & info,int32_t & blockReason)258 void SpamCallAdapter::SetParseResult(bool &isBlock, NumberMarkInfo &info, int32_t &blockReason)
259 {
260 isBlock_ = isBlock;
261 info_ = info;
262 blockReason_ = blockReason;
263 }
264
GetDetectPhoneNum()265 std::string SpamCallAdapter::GetDetectPhoneNum()
266 {
267 return phoneNumber_;
268 }
269
NotifyAll()270 void SpamCallAdapter::NotifyAll()
271 {
272 if (timeWaitHelper_ == nullptr) {
273 TELEPHONY_LOGE("timeWaitHelper_ is null");
274 return;
275 }
276 timeWaitHelper_->NotifyAll();
277 }
278
WaitForDetectResult()279 bool SpamCallAdapter::WaitForDetectResult()
280 {
281 if (!timeWaitHelper_->WaitForResult()) {
282 DisconnectSpamCallAbility();
283 return false;
284 }
285 DisconnectSpamCallAbility();
286 return true;
287 }
288 } // namespace Telephony
289 } // namespace OHOS
290