1 /*
2 * Copyright (C) 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 "distributed_operation_service.h"
17
18 #include "response_box.h"
19 #include "match_box.h"
20 #include "ans_inner_errors.h"
21 #include "notification_helper.h"
22 #include "distributed_data_define.h"
23 #include "distributed_device_service.h"
24 #include "distributed_unlock_listener_oper_service.h"
25 #include "int_wrapper.h"
26 #include "string_wrapper.h"
27 #include "analytics_util.h"
28 #include "distributed_client.h"
29 #include "power_mgr_client.h"
30 #include "ans_inner_errors.h"
31 #include "distributed_operation_helper.h"
32 #include "ability_manager_helper.h"
33 #include "distributed_liveview_all_scenarios_extension_wrapper.h"
34 #ifdef SCREENLOCK_MGR_ENABLE
35 #include "screenlock_manager.h"
36 #endif
37 #include "distributed_send_adapter.h"
38
39 namespace OHOS {
40 namespace Notification {
41
42 static const std::string DISTRIBUTED_LABEL = "ans_distributed";
43
GetInstance()44 DistributedOperationService& DistributedOperationService::GetInstance()
45 {
46 static DistributedOperationService distributedOperationService;
47 return distributedOperationService;
48 }
49
HandleNotificationOperation(const std::shared_ptr<TlvBox> & boxMessage)50 void DistributedOperationService::HandleNotificationOperation(const std::shared_ptr<TlvBox>& boxMessage)
51 {
52 int32_t operationType = 0;
53 int32_t jumpType = 0;
54 int32_t matchType = 0;
55 int32_t peerDeviceType = DistributedHardware::DmDeviceType::DEVICE_TYPE_WATCH;
56 std::string hashCode;
57 NotificationResponseBox responseBox = NotificationResponseBox(boxMessage);
58 responseBox.GetOperationType(operationType);
59 responseBox.GetOperationJumpType(jumpType);
60 responseBox.GetMatchType(matchType);
61 responseBox.GetNotificationHashCode(hashCode);
62 ANS_LOGI("handle response, hashCode: %{public}s, operationType: %{public}d, matchType: %{public}d, \
63 jumpType: %{public}d.", hashCode.c_str(), operationType, matchType, jumpType);
64 #ifdef DISTRIBUTED_FEATURE_MASTER
65 if (matchType != MatchType::MATCH_SYN) {
66 return;
67 }
68 std::string deviceId;
69 DistributedDeviceInfo device;
70 if (responseBox.GetLocalDeviceId(deviceId)) {
71 if (DistributedDeviceService::GetInstance().GetDeviceInfo(deviceId, device)) {
72 peerDeviceType = device.deviceType_;
73 }
74 }
75 if (static_cast<OperationType>(operationType) == DISTRIBUTE_OPERATION_JUMP_BY_TYPE) {
76 int32_t btnIndex;
77 responseBox.GetOperationBtnIndex(btnIndex);
78 #ifdef SCREENLOCK_MGR_ENABLE
79 if (ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) {
80 UnlockListenerOperService::GetInstance().AddDelayTask(hashCode, jumpType, peerDeviceType, btnIndex);
81 return;
82 }
83 #endif
84 UnlockListenerOperService::GetInstance().TriggerByJumpType(hashCode, jumpType, peerDeviceType, btnIndex);
85 return;
86 }
87 TriggerByOperationType(hashCode, peerDeviceType, operationType, responseBox);
88 #else
89 if (matchType == MatchType::MATCH_ACK) {
90 ResponseOperationResult(hashCode, responseBox);
91 }
92 #endif
93 }
94
95 #ifdef DISTRIBUTED_FEATURE_MASTER
GetCurrentTime()96 static int64_t GetCurrentTime()
97 {
98 auto now = std::chrono::system_clock::now();
99 auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch());
100 return duration.count();
101 }
102
TriggerReplyWantAgent(const sptr<NotificationRequest> request,std::string actionName,int32_t errorCode,std::string desc)103 static void TriggerReplyWantAgent(const sptr<NotificationRequest> request,
104 std::string actionName, int32_t errorCode, std::string desc)
105 {
106 AAFwk::WantParams extraInfo;
107 extraInfo.SetParam("desc", AAFwk::String::Box(desc));
108 extraInfo.SetParam("errorCode", AAFwk::Integer::Box(errorCode));
109 extraInfo.SetParam("actionName", AAFwk::String::Box(actionName));
110 DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->TriggerPushWantAgent(request,
111 OperationType::DISTRIBUTE_OPERATION_REPLY, extraInfo);
112 }
113
GetNotificationButtonWantPtr(const std::string & hashCode,const std::string & actionName,std::shared_ptr<AAFwk::Want> & wantPtr,sptr<NotificationRequest> & request,std::string & userInputKey)114 static ErrCode GetNotificationButtonWantPtr(const std::string& hashCode, const std::string& actionName,
115 std::shared_ptr<AAFwk::Want>& wantPtr, sptr<NotificationRequest>& request, std::string& userInputKey)
116 {
117 sptr<NotificationRequest> notificationRequest = nullptr;
118 auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
119 if (result != ERR_OK || notificationRequest == nullptr) {
120 ANS_LOGE("Check notificationRequest is null.");
121 return ERR_ANS_NOTIFICATION_NOT_EXISTS;
122 }
123
124 request = notificationRequest;
125 auto actionButtons = notificationRequest->GetActionButtons();
126 if (actionButtons.empty()) {
127 ANS_LOGE("Check actionButtons is null.");
128 return ERR_ANS_INVALID_PARAM;
129 }
130
131 std::shared_ptr<NotificationActionButton> button = nullptr;
132 for (std::shared_ptr<NotificationActionButton> buttonItem : actionButtons) {
133 if (buttonItem != nullptr && buttonItem->GetUserInput() != nullptr &&
134 buttonItem->GetTitle() == actionName) {
135 button = buttonItem;
136 break;
137 }
138 }
139
140 if (button == nullptr) {
141 ANS_LOGE("Check user input is null %{public}s.", actionName.c_str());
142 return ERR_ANS_INVALID_PARAM;
143 }
144 if (button->GetUserInput() != nullptr) {
145 userInputKey = button->GetUserInput()->GetInputKey();
146 }
147 if (userInputKey.empty()) {
148 ANS_LOGE("Check userInputKey is null.");
149 return ERR_ANS_INVALID_PARAM;
150 }
151 std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr = button->GetWantAgent();
152 if (wantAgentPtr == nullptr) {
153 ANS_LOGE("Check wantAgentPtr is null.");
154 return ERR_ANS_INVALID_PARAM;
155 }
156
157 std::shared_ptr<AbilityRuntime::WantAgent::PendingWant> pendingWantPtr = wantAgentPtr->GetPendingWant();
158 if (pendingWantPtr == nullptr) {
159 ANS_LOGE("Check pendingWantPtr is null.");
160 return ERR_ANS_INVALID_PARAM;
161 }
162
163 wantPtr = pendingWantPtr->GetWant(pendingWantPtr->GetTarget());
164 if (wantPtr == nullptr) {
165 ANS_LOGE("Check wantPtr is null.");
166 return ERR_ANS_INVALID_PARAM;
167 }
168 return ERR_OK;
169 }
170
GetNotificationWantPtr(const std::string & hashCode)171 static std::shared_ptr<AAFwk::Want> GetNotificationWantPtr(const std::string& hashCode)
172 {
173 sptr<NotificationRequest> notificationRequest = nullptr;
174 auto result = NotificationHelper::GetNotificationRequestByHashCode(hashCode, notificationRequest);
175 if (result != ERR_OK || notificationRequest == nullptr) {
176 ANS_LOGE("Check notificationRequest is null.");
177 return nullptr;
178 }
179
180 std::shared_ptr<AbilityRuntime::WantAgent::WantAgent> wantAgentPtr = notificationRequest->GetWantAgent();
181 if (wantAgentPtr == nullptr) {
182 ANS_LOGE("Check wantAgentPtr is null.");
183 return nullptr;
184 }
185
186 std::shared_ptr<AbilityRuntime::WantAgent::PendingWant> pendingWantPtr = wantAgentPtr->GetPendingWant();
187 if (pendingWantPtr == nullptr) {
188 ANS_LOGE("Check pendingWantPtr is null.");
189 return nullptr;
190 }
191
192 return pendingWantPtr->GetWant(pendingWantPtr->GetTarget());
193 }
194
ReplyOperationResponse(const std::string & hashCode,const NotificationResponseBox & responseBox,OperationType operationType,uint32_t result)195 void DistributedOperationService::ReplyOperationResponse(const std::string& hashCode,
196 const NotificationResponseBox& responseBox, OperationType operationType, uint32_t result)
197 {
198 std::string eventId;
199 std::string deviceId;
200 responseBox.GetOperationEventId(eventId);
201 responseBox.GetLocalDeviceId(deviceId);
202
203 DistributedDeviceInfo device;
204 if (!DistributedDeviceService::GetInstance().GetDeviceInfo(deviceId, device)) {
205 ANS_LOGI("Dans get deviceId unknonw %{public}s.", StringAnonymous(deviceId).c_str());
206 return;
207 }
208
209 std::shared_ptr<NotificationResponseBox> replyBox = std::make_shared<NotificationResponseBox>();
210 replyBox->SetResponseResult(result);
211 replyBox->SetNotificationHashCode(hashCode);
212 replyBox->SetOperationEventId(eventId);
213 replyBox->SetMatchType(MatchType::MATCH_ACK);
214 replyBox->SetOperationType(operationType);
215
216 if (!replyBox->Serialize()) {
217 ANS_LOGW("dans OnResponse reply serialize failed");
218 return;
219 }
220
221 auto packageInfo = std::make_shared<PackageInfo>(replyBox, device,
222 TransDataType::DATA_TYPE_MESSAGE, MODIFY_ERROR_EVENT_CODE);
223 DistributedSendAdapter::GetInstance().SendPackage(packageInfo);
224 ANS_LOGI("Dans reply operation %{public}s.", StringAnonymous(deviceId).c_str());
225 }
226
TriggerReplyApplication(const std::string & hashCode,const int32_t deviceType,const NotificationResponseBox & responseBox)227 int32_t DistributedOperationService::TriggerReplyApplication(const std::string& hashCode,
228 const int32_t deviceType, const NotificationResponseBox& responseBox)
229 {
230 std::string actionName;
231 std::string userInput;
232 std::string userInputKey;
233 responseBox.GetActionName(actionName);
234 responseBox.GetUserInput(userInput);
235
236 std::shared_ptr<AAFwk::Want> wantPtr = nullptr;
237 sptr<NotificationRequest> request = nullptr;
238 auto result = GetNotificationButtonWantPtr(hashCode, actionName, wantPtr, request, userInputKey);
239 if (result != ERR_OK || wantPtr == nullptr) {
240 AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, result,
241 BRANCH4_ID, "reply get button failed");
242 TriggerReplyWantAgent(request, actionName, result, "reply get button failed");
243 return result;
244 }
245
246 if (wantPtr->GetBoolParam(AAFwk::Want::PARAM_RESV_CALL_TO_FOREGROUND, false)) {
247 ANS_LOGE("Not support foreground.");
248 AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, ERR_ANS_DISTRIBUTED_OPERATION_FAILED,
249 BRANCH4_ID, "reply foreground failed");
250 TriggerReplyWantAgent(request, actionName, ERR_ANS_DISTRIBUTED_OPERATION_FAILED, "reply foreground failed");
251 return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
252 }
253
254 auto ret = AbilityManagerHelper::GetInstance().ConnectAbility(hashCode, *wantPtr, userInputKey, userInput);
255 ANS_LOGI("StartAbility result:%{public}d", ret);
256 if (ret == ERR_OK) {
257 TriggerReplyWantAgent(request, actionName, ERR_OK, "");
258 AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_REPLY,
259 NotificationConstant::SlotType::SOCIAL_COMMUNICATION);
260 } else {
261 TriggerReplyWantAgent(request, actionName, ret, "ability reply failed");
262 AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, ret,
263 BRANCH4_ID, "ability reply failed");
264 return ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
265 }
266 return ERR_OK;
267 }
268
TriggerJumpApplication(const std::string & hashCode,const int32_t deviceType)269 void DistributedOperationService::TriggerJumpApplication(const std::string& hashCode, const int32_t deviceType)
270 {
271 auto wantPtr = GetNotificationWantPtr(hashCode);
272 if (wantPtr == nullptr) {
273 ANS_LOGE("Get pendingWantPtr is null.");
274 return;
275 }
276
277 if (!PowerMgr::PowerMgrClient::GetInstance().IsScreenOn()) {
278 auto ret = PowerMgr::PowerMgrClient::GetInstance().WakeupDevice();
279 if (ret != PowerMgr::PowerErrors::ERR_OK) {
280 ANS_LOGW("Wake up device %{public}d", ret);
281 return;
282 }
283 }
284
285 #ifdef SCREENLOCK_MGR_ENABLE
286 if (ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked()) {
287 OperationInfo info;
288 info.deviceTypeId = deviceType;
289 info.type = OperationType::DISTRIBUTE_OPERATION_JUMP;
290 info.eventId = std::to_string(GetCurrentTime());
291 sptr<UnlockScreenCallback> listener = new (std::nothrow) UnlockScreenCallback(info.eventId);
292 int32_t unlockResult =
293 ScreenLock::ScreenLockManager::GetInstance()->Unlock(ScreenLock::Action::UNLOCKSCREEN, listener);
294 ANS_LOGI("unlock result:%{public}d", unlockResult);
295 if (unlockResult != ERR_OK) {
296 AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, unlockResult,
297 BRANCH6_ID, "unlock failed");
298 }
299 info.want = *wantPtr;
300 OperationService::GetInstance().AddOperation(info);
301 return;
302 }
303 #endif
304 auto ret = AAFwk::AbilityManagerClient::GetInstance()->StartAbility(*wantPtr);
305 ANS_LOGI("StartAbility result:%{public}d", ret);
306 if (ret == ERR_OK) {
307 AnalyticsUtil::GetInstance().OperationalReporting(deviceType, HaOperationType::COLLABORATE_JUMP,
308 NotificationConstant::SlotType::LIVE_VIEW);
309 } else {
310 AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, 0, ret, "pull up failed");
311 }
312 AnalyticsUtil::GetInstance().AbnormalReporting(MODIFY_ERROR_EVENT_CODE, ret, BRANCH9_ID, "pull up success");
313 }
314
TriggerByOperationType(const std::string & hashCode,const int32_t deviceType,const int32_t operationType,const NotificationResponseBox & responseBox)315 void DistributedOperationService::TriggerByOperationType(const std::string& hashCode, const int32_t deviceType,
316 const int32_t operationType, const NotificationResponseBox& responseBox)
317 {
318 if (static_cast<OperationType>(operationType) == OperationType::DISTRIBUTE_OPERATION_JUMP) {
319 TriggerJumpApplication(hashCode, deviceType);
320 } else if (static_cast<OperationType>(operationType) == OperationType::DISTRIBUTE_OPERATION_REPLY) {
321 ErrCode result = TriggerReplyApplication(hashCode, deviceType, responseBox);
322 ReplyOperationResponse(hashCode, responseBox, OperationType::DISTRIBUTE_OPERATION_REPLY, result);
323 }
324 }
325 #else
326
OnOperationResponse(const std::shared_ptr<NotificationOperationInfo> & operationInfo,const DistributedDeviceInfo & device)327 int32_t DistributedOperationService::OnOperationResponse(
328 const std::shared_ptr<NotificationOperationInfo>& operationInfo, const DistributedDeviceInfo& device)
329 {
330 std::shared_ptr<NotificationResponseBox> responseBox = std::make_shared<NotificationResponseBox>();
331 ANS_LOGI("dans OnResponse %{public}s", operationInfo->Dump().c_str());
332 if (operationInfo == nullptr) {
333 return ERR_ANS_INVALID_PARAM;
334 }
335 auto hashCode = operationInfo->GetHashCode();
336 if (hashCode.find(DISTRIBUTED_LABEL) == 0) {
337 hashCode.erase(0, DISTRIBUTED_LABEL.length());
338 }
339
340 OperationType type = operationInfo->GetOperationType();
341 if (type == OperationType::DISTRIBUTE_OPERATION_REPLY) {
342 if (!responseBox->SetMessageType(NOTIFICATION_RESPONSE_REPLY_SYNC)) {
343 ANS_LOGW("dans OnResponse SetMessageType failed");
344 return ERR_ANS_TASK_ERR;
345 }
346 responseBox->SetActionName(operationInfo->GetActionName());
347 responseBox->SetUserInput(operationInfo->GetUserInput());
348 }
349
350 if (type == OperationType::DISTRIBUTE_OPERATION_JUMP_BY_TYPE) {
351 responseBox->SetOperationJumpType(operationInfo->GetJumpType());
352 if (operationInfo->GetBtnIndex() >= 0 && operationInfo->GetBtnIndex() < NotificationConstant::MAX_BTN_NUM) {
353 responseBox->SetOperationBtnIndex(operationInfo->GetBtnIndex());
354 }
355 }
356 auto localDevice = DistributedDeviceService::GetInstance().GetLocalDevice();
357 responseBox->SetMatchType(MatchType::MATCH_SYN);
358 responseBox->SetOperationType(static_cast<int32_t>(type));
359 responseBox->SetNotificationHashCode(hashCode);
360 responseBox->SetOperationEventId(operationInfo->GetEventId());
361 responseBox->SetLocalDeviceId(localDevice.deviceId_);
362 if (!responseBox->Serialize()) {
363 ANS_LOGW("dans OnResponse serialize failed");
364 return ERR_ANS_TASK_ERR;
365 }
366
367 LaunchProjectionApp(device, localDevice);
368 auto result = DistributedClient::GetInstance().SendMessage(responseBox, TransDataType::DATA_TYPE_MESSAGE,
369 device.deviceId_, MODIFY_ERROR_EVENT_CODE);
370 if (result != ERR_OK) {
371 ANS_LOGE("dans OnResponse send message failed result: %{public}d", result);
372 result = ERR_ANS_DISTRIBUTED_OPERATION_FAILED;
373 }
374 return result;
375 }
376
ResponseOperationResult(const std::string & hashCode,const NotificationResponseBox & responseBox)377 void DistributedOperationService::ResponseOperationResult(const std::string& hashCode,
378 const NotificationResponseBox& responseBox)
379 {
380 int32_t result = 0;
381 std::string eventId;
382 responseBox.GetOperationEventId(eventId);
383 responseBox.GetResponseResult(result);
384 auto ret = NotificationHelper::ReplyDistributeOperation(DISTRIBUTED_LABEL + hashCode + eventId, result);
385 ANS_LOGI("HandleOperationResponse hashcode %{public}s, result:%{public}d %{public}d",
386 hashCode.c_str(), result, ret);
387 }
388
LaunchProjectionApp(const DistributedDeviceInfo & peerDevice,const DistributedDeviceInfo & localDevice)389 void DistributedOperationService::LaunchProjectionApp(
390 const DistributedDeviceInfo& peerDevice, const DistributedDeviceInfo& localDevice)
391 {
392 if ((localDevice.deviceType_ != DistributedHardware::DmDeviceType::DEVICE_TYPE_PAD &&
393 localDevice.deviceType_ != DistributedHardware::DmDeviceType::DEVICE_TYPE_PC) ||
394 peerDevice.deviceType_ != DistributedHardware::DmDeviceType::DEVICE_TYPE_PHONE) {
395 ANS_LOGI("Can not launch projectionApp");
396 return;
397 }
398 int32_t result =
399 DISTRIBUTED_LIVEVIEW_ALL_SCENARIOS_EXTENTION_WRAPPER->RestoreCollaborationWindow(peerDevice.networkId_);
400 ANS_LOGI("RestoreCollaborationWindow result: %{public}d, networkId: %{public}s",
401 result, StringAnonymous(peerDevice.networkId_).c_str());
402 }
403 #endif
404 }
405 }
406