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 "notification_operation_service.h"
17
18 #include "ans_log_wrapper.h"
19 #include "notification_analytics_util.h"
20 #include "time_service_client.h"
21 #include "ans_inner_errors.h"
22 #include "distributed_extension_service.h"
23
24 namespace OHOS {
25 namespace Notification {
26 namespace {
27 static const int64_t OPERATION_TIMEOUT = 3000;
28 }
OnTrigger()29 void OperationTimerInfo::OnTrigger()
30 {
31 DistributedOperationService::GetInstance().HandleOperationTimeOut(timerHashCode_);
32 }
33
GetInstance()34 DistributedOperationService& DistributedOperationService::GetInstance()
35 {
36 static DistributedOperationService distributedOperationService;
37 return distributedOperationService;
38 }
39
DistributedOperationService()40 DistributedOperationService::DistributedOperationService()
41 {
42 operationQueue_ = std::make_shared<ffrt::queue>("ans_operation");
43 if (operationQueue_ == nullptr) {
44 ANS_LOGE("ffrt create failed!");
45 return;
46 }
47 ANS_LOGI("Operation service init successfully.");
48 }
49
AddOperation(const std::string & hashCode,const sptr<IAnsOperationCallback> & callback)50 void DistributedOperationService::AddOperation(const std::string& hashCode,
51 const sptr<IAnsOperationCallback> &callback)
52 {
53 int32_t timeout = DistributedExtensionService::GetInstance().GetOperationReplyTimeout();
54 int64_t expiredTime = NotificationAnalyticsUtil::GetCurrentTime() + timeout;
55 std::shared_ptr<OperationTimerInfo> timerInfo = std::make_shared<OperationTimerInfo>(hashCode);
56 sptr<MiscServices::TimeServiceClient> timer = MiscServices::TimeServiceClient::GetInstance();
57 if (timer == nullptr) {
58 ANS_LOGE("Failed to start timer due to get TimeServiceClient is null.");
59 return;
60 }
61 uint64_t timerId = timer->CreateTimer(timerInfo);
62 timer->StartTimer(timerId, expiredTime);
63 std::lock_guard<ffrt::mutex> lock(mapLock_);
64 auto iterCallback = callbackMap_.find(hashCode);
65 if (iterCallback != callbackMap_.end()) {
66 ANS_LOGW("Operation callback has same key %{public}s.", hashCode.c_str());
67 callbackMap_.erase(iterCallback);
68 }
69 callbackMap_.insert_or_assign(hashCode, callback);
70
71 auto iterTimer = timerMap_.find(hashCode);
72 if (iterTimer != timerMap_.end()) {
73 ANS_LOGW("Operation timer has same key %{public}s.", hashCode.c_str());
74 if (iterTimer->second == NotificationConstant::INVALID_TIMER_ID) {
75 return;
76 }
77 MiscServices::TimeServiceClient::GetInstance()->StopTimer(iterTimer->second);
78 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(iterTimer->second);
79 timerMap_.erase(iterTimer);
80 }
81 timerMap_.insert_or_assign(hashCode, timerId);
82 ANS_LOGI("Operation add key %{public}s.", hashCode.c_str());
83 }
84
RemoveOperationResponse(const std::string & hashCode)85 void DistributedOperationService::RemoveOperationResponse(const std::string& hashCode)
86 {
87 std::lock_guard<ffrt::mutex> lock(mapLock_);
88 auto iterCallback = callbackMap_.find(hashCode);
89 if (iterCallback != callbackMap_.end()) {
90 callbackMap_.erase(iterCallback);
91 ANS_LOGI("Operation callback erase %{public}s", hashCode.c_str());
92 }
93
94 auto iterTimer = timerMap_.find(hashCode);
95 if (iterTimer != timerMap_.end()) {
96 if (iterTimer->second == NotificationConstant::INVALID_TIMER_ID) {
97 return;
98 }
99 ANS_LOGI("Operation timer erase %{public}s %{public}s", hashCode.c_str(),
100 std::to_string(iterTimer->second).c_str());
101 MiscServices::TimeServiceClient::GetInstance()->StopTimer(iterTimer->second);
102 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(iterTimer->second);
103 timerMap_.erase(iterTimer);
104 }
105 }
106
ReplyOperationResponse(const std::string & hashCode,int32_t result)107 void DistributedOperationService::ReplyOperationResponse(const std::string& hashCode, int32_t result)
108 {
109 std::lock_guard<ffrt::mutex> lock(mapLock_);
110 auto iterCallback = callbackMap_.find(hashCode);
111 if (iterCallback != callbackMap_.end()) {
112 iterCallback->second->OnOperationCallback(result);
113 callbackMap_.erase(iterCallback);
114 ANS_LOGI("Operation callback erase %{public}s", hashCode.c_str());
115 }
116
117 auto iterTimer = timerMap_.find(hashCode);
118 if (iterTimer != timerMap_.end()) {
119 if (iterTimer->second == NotificationConstant::INVALID_TIMER_ID) {
120 return;
121 }
122 ANS_LOGI("Operation timer erase %{public}s %{public}s", hashCode.c_str(),
123 std::to_string(iterTimer->second).c_str());
124 MiscServices::TimeServiceClient::GetInstance()->StopTimer(iterTimer->second);
125 MiscServices::TimeServiceClient::GetInstance()->DestroyTimer(iterTimer->second);
126 timerMap_.erase(iterTimer);
127 }
128 ANS_LOGI("Operation reply key %{public}s %{public}u.", hashCode.c_str(), result);
129 }
130
HandleOperationTimeOut(const std::string & hashCode)131 void DistributedOperationService::HandleOperationTimeOut(const std::string& hashCode)
132 {
133 if (operationQueue_ == nullptr) {
134 ANS_LOGE("Operation queue is invalid.");
135 return;
136 }
137
138 operationQueue_->submit_h([&, hashCode]() {
139 ReplyOperationResponse(hashCode, ERR_ANS_OPERATION_TIMEOUT);
140 });
141 }
142 }
143 }
144
145