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 "mission/notification/dms_continue_send_manager.h"
17
18 #include <sys/prctl.h>
19
20 #include "adapter/mmi_adapter.h"
21 #include "bundle/bundle_manager_internal.h"
22 #include "datetime_ex.h"
23 #include "distributed_sched_utils.h"
24 #include "dsched_data_buffer.h"
25 #include "dtbschedmgr_log.h"
26 #include "mission/dms_continue_condition_manager.h"
27 #include "softbus_adapter/softbus_adapter.h"
28
29 namespace OHOS {
30 namespace DistributedSchedule {
31 namespace {
32 const std::string TAG = "DMSContinueSendMgr";
33
34 constexpr int32_t INDEX_0 = 0;
35 constexpr int32_t INDEX_1 = 1;
36 constexpr int32_t INDEX_2 = 2;
37 constexpr int32_t INDEX_3 = 3;
38 constexpr int32_t FOCUS_TIMEOUT_DELAY_TIME = 60000;
39 constexpr int32_t SCREEN_LOCK_DELAY_TIME = 10000;
40 constexpr int64_t SCREEN_LOCK_EVENT_INTERVAL = 500; // determines whether normal unfocused or locked
41 const std::string TIMEOUT_UNFOCUSED_TASK = "timeout_unfocused_task";
42 }
43
Init(int32_t currentUserId)44 void DMSContinueSendMgr::Init(int32_t currentUserId)
45 {
46 HILOGI("Init start");
47 if (eventHandler_ != nullptr) {
48 HILOGI("Already inited, end.");
49 return;
50 }
51 {
52 screenLockedHandler_ = std::make_shared<ScreenLockedHandler>(shared_from_this());
53 screenLockedHandler_->ResetScreenLockedInfo();
54 accountId_ = currentUserId;
55
56 strategyMap_[MISSION_EVENT_FOCUSED] = std::make_shared<SendStrategyFocused>(shared_from_this());
57 strategyMap_[MISSION_EVENT_UNFOCUSED] = std::make_shared<SendStrategyUnfocused>(shared_from_this());
58 strategyMap_[MISSION_EVENT_DESTORYED] = std::make_shared<SendStrategyDestoryed>(shared_from_this());
59 strategyMap_[MISSION_EVENT_ACTIVE] = std::make_shared<SendStrategyActive>(shared_from_this());
60 strategyMap_[MISSION_EVENT_INACTIVE] = std::make_shared<SendStrategyInactive>(shared_from_this());
61 strategyMap_[MISSION_EVENT_TIMEOUT] = std::make_shared<SendStrategyTimeout>(shared_from_this());
62 strategyMap_[MISSION_EVENT_MMI] = std::make_shared<SendStrategyMMI>(shared_from_this());
63
64 eventThread_ = std::thread(&DMSContinueSendMgr::StartEvent, this);
65 std::unique_lock<std::mutex> lock(eventMutex_);
66 eventCon_.wait(lock, [this] {
67 return eventHandler_ != nullptr;
68 });
69 }
70 HILOGI("Init end");
71 }
72
StartEvent()73 void DMSContinueSendMgr::StartEvent()
74 {
75 HILOGI("StartEvent start");
76 prctl(PR_SET_NAME, TAG.c_str());
77 auto runner = AppExecFwk::EventRunner::Create(false);
78 {
79 std::lock_guard<std::mutex> lock(eventMutex_);
80 eventHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
81 }
82 eventCon_.notify_one();
83 CHECK_POINTER_RETURN(runner, "runner");
84 runner->Run();
85 HILOGI("StartEvent end");
86 }
87
~DMSContinueSendMgr()88 DMSContinueSendMgr::~DMSContinueSendMgr()
89 {
90 HILOGI("~DMSContinueSendMgr, accountId: %{public}d.", accountId_);
91 UnInit();
92 }
93
UnInit()94 void DMSContinueSendMgr::UnInit()
95 {
96 HILOGI("UnInit start");
97 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
98 if (eventHandler_->GetEventRunner() != nullptr) {
99 eventHandler_->GetEventRunner()->Stop();
100 if (eventThread_.joinable()) {
101 eventThread_.join();
102 }
103 eventHandler_ = nullptr;
104 }
105 HILOGI("UnInit end");
106 }
107
OnMissionStatusChanged(int32_t missionId,MissionEventType type)108 void DMSContinueSendMgr::OnMissionStatusChanged(int32_t missionId, MissionEventType type)
109 {
110 MissionStatus status;
111 int32_t ret = DmsContinueConditionMgr::GetInstance().GetMissionStatus(accountId_, missionId, status);
112 if (ret != ERR_OK) {
113 HILOGE("GetMissionStatus failed, ret: %{public}d, missionId %{public}d, type: %{public}s",
114 ret, missionId, DmsContinueConditionMgr::GetInstance().TypeEnumToString(type).c_str());
115 return;
116 }
117
118 auto feedfunc = [this, status, type]() {
119 SendContinueBroadcast(status, type);
120 };
121 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
122 eventHandler_->RemoveTask(TIMEOUT_UNFOCUSED_TASK + std::to_string(missionId));
123 eventHandler_->PostTask(feedfunc);
124 }
125
OnMMIEvent()126 void DMSContinueSendMgr::OnMMIEvent()
127 {
128 auto feedfunc = [this]() {
129 int32_t missionId = DmsContinueConditionMgr::GetInstance().GetCurrentFocusedMission(accountId_);
130
131 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
132 eventHandler_->RemoveTask(TIMEOUT_UNFOCUSED_TASK + std::to_string(missionId));
133
134 SendContinueBroadcast(missionId, MISSION_EVENT_MMI);
135 };
136 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
137 eventHandler_->PostTask(feedfunc);
138 }
139
OnDeviceOnline()140 int32_t DMSContinueSendMgr::OnDeviceOnline()
141 {
142 HILOGD("OnDeviceOnline called");
143 int32_t missionId = GetCurrentMissionId();
144 if (missionId <= 0) {
145 return INVALID_MISSION_ID;
146 }
147 OnMissionStatusChanged(missionId, MISSION_EVENT_FOCUSED);
148 return ERR_OK;
149 }
150
OnDeviceScreenLocked()151 void DMSContinueSendMgr::OnDeviceScreenLocked()
152 {
153 HILOGI("OnDeviceScreenLocked called");
154 auto feedfunc = [this]() {
155 CHECK_POINTER_RETURN(screenLockedHandler_, "screenLockedHandler_");
156 screenLockedHandler_->OnDeviceScreenLocked();
157 };
158 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
159 eventHandler_->PostTask(feedfunc);
160 }
161
OnUserSwitched()162 void DMSContinueSendMgr::OnUserSwitched()
163 {
164 HILOGI("OnUserSwitched called");
165 auto feedfunc = [this]() {
166 RemoveMMIListener();
167 SendScreenLockedEvent(DMS_UNFOCUSED_TYPE);
168 };
169 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
170 eventHandler_->PostTask(feedfunc);
171 CHECK_POINTER_RETURN(screenLockedHandler_, "screenLockedHandler_");
172 std::string timeoutTaskName = TIMEOUT_UNFOCUSED_TASK + std::to_string(screenLockedHandler_->GetMissionId());
173 eventHandler_->RemoveTask(timeoutTaskName);
174 }
175
SendContinueBroadcast(int32_t missionId,MissionEventType type)176 void DMSContinueSendMgr::SendContinueBroadcast(int32_t missionId, MissionEventType type)
177 {
178 MissionStatus status;
179 int32_t ret = DmsContinueConditionMgr::GetInstance().GetMissionStatus(accountId_, missionId, status);
180 if (ret != ERR_OK) {
181 HILOGE("GetMissionStatus failed, ret: %{public}d, missionId %{public}d, type: %{public}s",
182 ret, missionId, DmsContinueConditionMgr::GetInstance().TypeEnumToString(type).c_str());
183 return;
184 }
185 SendContinueBroadcast(status, type);
186 return;
187 }
188
SendContinueBroadcast(const MissionStatus & status,MissionEventType type)189 void DMSContinueSendMgr::SendContinueBroadcast(const MissionStatus& status, MissionEventType type)
190 {
191 auto typeStr = DmsContinueConditionMgr::GetInstance().TypeEnumToString(type);
192 HILOGI("start, missionId: %{public}d, type: %{public}s", status.missionId, typeStr.c_str());
193 // The interval between application exit and screen lock events is too short,
194 // which may result in abnormal re sending of focused broadcasts.
195 // This phenomenon is temporarily avoided here.
196 if (MissionEventType::MISSION_EVENT_DESTORYED == type) {
197 screenLockedHandler_->ResetScreenLockedInfo();
198 }
199 if (!DmsContinueConditionMgr::GetInstance().CheckSystemSendCondition() ||
200 !DmsContinueConditionMgr::GetInstance().CheckMissionSendCondition(status, type)) {
201 HILOGE("CheckBroadcastCondition %{public}s failed! status: %{public}s",
202 typeStr.c_str(), status.ToString().c_str());
203 return;
204 }
205
206 uint8_t sendType = 0;
207 int32_t ret = ExecuteSendStrategy(type, status, sendType);
208 if (ret != ERR_OK) {
209 HILOGE("ExecuteSendStrategy %{public}s failed, ret: %{public}d. status: %{public}s",
210 typeStr.c_str(), ret, status.ToString().c_str());
211 return;
212 }
213
214 uint16_t bundleNameId = 0;
215 uint8_t continueTypeId = 0;
216 ret = QueryBroadcastInfo(status, bundleNameId, continueTypeId);
217 if (ret != ERR_OK) {
218 HILOGE("QueryBroadcastInfo %{public}s failed! status: %{public}s",
219 typeStr.c_str(), status.ToString().c_str());
220 return;
221 }
222
223 SendSoftbusEvent(bundleNameId, continueTypeId, sendType);
224 HILOGI("end");
225 return;
226 }
227
ExecuteSendStrategy(MissionEventType type,const MissionStatus & status,uint8_t & sendType)228 int32_t DMSContinueSendMgr::ExecuteSendStrategy(MissionEventType type, const MissionStatus& status, uint8_t &sendType)
229 {
230 HILOGI("start, missionId: %{public}d, type: %{public}s", status.missionId,
231 DmsContinueConditionMgr::GetInstance().TypeEnumToString(type).c_str());
232
233 if (strategyMap_.count(type) == 0) {
234 HILOGE("Invalid type %{public}d!", type);
235 return INVALID_PARAMETERS_ERR;
236 }
237 ContinueSendContext context;
238 context.SetStrategy(strategyMap_[type]);
239 int32_t ret = context.ExecuteSendStrategy(status, sendType);
240 HILOGI("end, ExecuteSendStrategy ret: %{public}d", ret);
241 return ret;
242 }
243
QueryBroadcastInfo(const MissionStatus & status,uint16_t & bundleNameId,uint8_t & continueTypeId)244 int32_t DMSContinueSendMgr::QueryBroadcastInfo(
245 const MissionStatus& status, uint16_t& bundleNameId, uint8_t& continueTypeId)
246 {
247 if (status.bundleName.empty() || status.abilityName.empty()) {
248 HILOGE("bundleName or ability name is null!");
249 return INVALID_PARAMETERS_ERR;
250 }
251 HILOGI("start, bundleName: %{public}s, abilityName: %{public}s", status.bundleName.c_str(),
252 status.abilityName.c_str());
253
254 int32_t ret = BundleManagerInternal::GetBundleNameId(status.bundleName, bundleNameId);
255 if (ret != ERR_OK) {
256 HILOGE("GetBundleNameId failed, bundleName: %{public}s, ret: %{public}d", status.bundleName.c_str(), ret);
257 return ret;
258 }
259
260 ret = BundleManagerInternal::GetContinueTypeId(status.bundleName, status.abilityName, continueTypeId);
261 if (ret != ERR_OK) {
262 HILOGE("GetContinueTypeId failed, abilityName: %{public}s, ret: %{public}d", status.abilityName.c_str(), ret);
263 return ret;
264 }
265 HILOGI("success, bundleNameId: %{public}d, continueTypeId: %{public}d", bundleNameId, continueTypeId);
266 return ERR_OK;
267 }
268
SendSoftbusEvent(uint16_t & bundleNameId,uint8_t & continueTypeId,uint8_t type)269 void DMSContinueSendMgr::SendSoftbusEvent(uint16_t& bundleNameId, uint8_t& continueTypeId, uint8_t type)
270 {
271 HILOGI("bundleNameId: %{public}u, continueTypeId: %{public}u, sendType %{public}u",
272 bundleNameId, continueTypeId, type);
273
274 std::shared_ptr<DSchedDataBuffer> buffer = std::make_shared<DSchedDataBuffer>(DMS_SEND_LEN);
275 if (buffer->Data() == nullptr || buffer->Size() < DMS_SEND_LEN) {
276 HILOGE("Failed to initialize DSchedDataBuffer");
277 return;
278 }
279
280 buffer->Data()[INDEX_0] = (type << CONTINUE_SHIFT_04) | DMS_DATA_LEN;
281 buffer->Data()[INDEX_1] = (bundleNameId >> CONTINUE_SHIFT_08) & DMS_0XFF;
282 buffer->Data()[INDEX_2] = bundleNameId & DMS_0XFF;
283 buffer->Data()[INDEX_3] = continueTypeId & DMS_0XFF;
284
285 SoftbusAdapter::GetInstance().SendSoftbusEvent(buffer);
286 }
287
SendContinueBroadcastAfterDelay(int32_t missionId)288 void DMSContinueSendMgr::SendContinueBroadcastAfterDelay(int32_t missionId)
289 {
290 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
291 HILOGI("send continue broadcast for missionId: %{public}d after %{public}d delay",
292 missionId, FOCUS_TIMEOUT_DELAY_TIME);
293 auto func = [this, missionId]() {
294 SendContinueBroadcast(missionId, MISSION_EVENT_TIMEOUT);
295 };
296 std::string timeoutTaskName = TIMEOUT_UNFOCUSED_TASK + std::to_string(missionId);
297 eventHandler_->RemoveTask(timeoutTaskName);
298 eventHandler_->PostTask(func, timeoutTaskName, FOCUS_TIMEOUT_DELAY_TIME);
299 }
300
AddMMIListener()301 void DMSContinueSendMgr::AddMMIListener()
302 {
303 if (mmiMonitorId_ >= 0) {
304 HILOGD("MMI listener already exist, monitor id: %{public}d", mmiMonitorId_);
305 return;
306 }
307 mmiMonitorId_ = MMIAdapter::GetInstance().AddMMIListener();
308 if (mmiMonitorId_ < 0) {
309 HILOGW("Add MMI listener failed, ret: %{public}d", mmiMonitorId_);
310 return;
311 }
312 HILOGI("MMI listener has been added, monitor id: %{public}d", mmiMonitorId_);
313 }
314
RemoveMMIListener()315 void DMSContinueSendMgr::RemoveMMIListener()
316 {
317 if (mmiMonitorId_ < 0) {
318 HILOGI("No MMI listener to be removed, monitor id: %{public}d", mmiMonitorId_);
319 return;
320 }
321 MMIAdapter::GetInstance().RemoveMMIListener(mmiMonitorId_);
322 HILOGI("MMI listener has been removed, monitor id: %{public}d", mmiMonitorId_);
323
324 mmiMonitorId_ = INVALID_MISSION_ID;
325 return;
326 }
327
PostScreenLockedEventAfterDelay(int32_t missionId,uint8_t type,int32_t timeout)328 void DMSContinueSendMgr::PostScreenLockedEventAfterDelay(int32_t missionId, uint8_t type, int32_t timeout)
329 {
330 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
331 auto func = [this, type]() {
332 SendScreenLockedEvent(type);
333 };
334 std::string timeoutTaskName = TIMEOUT_UNFOCUSED_TASK + std::to_string(missionId);
335 eventHandler_->RemoveTask(timeoutTaskName);
336 if (timeout == 0) {
337 eventHandler_->PostTask(func);
338 return;
339 }
340 eventHandler_->PostTask(func, timeoutTaskName, timeout);
341 }
342
SendScreenLockedEvent(uint8_t type)343 int32_t DMSContinueSendMgr::SendScreenLockedEvent(uint8_t type)
344 {
345 HILOGI("start, type: %{public}u", type);
346 CHECK_POINTER_RETURN_VALUE(screenLockedHandler_, ERR_NULL_OBJECT, "screenLockedHandler_");
347
348 uint16_t bundleNameId = 0;
349 uint8_t continueTypeId = 0;
350 MissionStatus status = screenLockedHandler_->GetMissionStatus();
351 int32_t ret = QueryBroadcastInfo(status, bundleNameId, continueTypeId);
352 if (ret != ERR_OK) {
353 HILOGE("QueryBroadcastInfo failed, ret: %{public}d, status: %{public}s", ret, status.ToString().c_str());
354 return ret;
355 }
356
357 if (!DmsContinueConditionMgr::GetInstance().CheckSystemSendCondition()) {
358 HILOGE("check system send condition failed!");
359 return DMS_PERMISSION_DENIED;
360 }
361
362 if (status.continueState != AAFwk::ContinueState::CONTINUESTATE_ACTIVE) {
363 HILOGE("check ContinueState send failed, ContinueState is not CONTINUESTATE_ACTIVE.");
364 return DMS_PERMISSION_DENIED;
365 }
366
367 SendSoftbusEvent(bundleNameId, continueTypeId, type);
368 HILOGI("end");
369 return ERR_OK;
370 }
371
ScreenLockedHandler(const std::shared_ptr<DMSContinueSendMgr> & dmsContinueSendMgr)372 DMSContinueSendMgr::ScreenLockedHandler::ScreenLockedHandler
373 (const std::shared_ptr<DMSContinueSendMgr>& dmsContinueSendMgr) : dmsContinueSendMgr_(dmsContinueSendMgr)
374 {
375 }
376
GetMissionId()377 int32_t DMSContinueSendMgr::ScreenLockedHandler::GetMissionId()
378 {
379 return unfoInfo_.missionId;
380 }
381
GetMissionStatus()382 MissionStatus DMSContinueSendMgr::ScreenLockedHandler::GetMissionStatus()
383 {
384 return unfoInfo_.status;
385 }
386
OnDeviceScreenLocked()387 void DMSContinueSendMgr::ScreenLockedHandler::OnDeviceScreenLocked()
388 {
389 HILOGI("ScreenLockedHandler::OnDeviceScreenLocked called");
390 std::shared_ptr<DMSContinueSendMgr> sendMgr = dmsContinueSendMgr_.lock();
391 if (sendMgr == nullptr) {
392 HILOGW("sendMgr is nullptr.");
393 return;
394 }
395 if (unfoInfo_.missionId != INVALID_MISSION_ID
396 && (GetTickCount()- unfoInfo_.unfoTime) < SCREEN_LOCK_EVENT_INTERVAL) {
397 // handle unfocus before screen locked
398 sendMgr->PostScreenLockedEventAfterDelay(unfoInfo_.missionId, DMS_FOCUSED_TYPE, 0);
399 }
400
401 sendMgr->PostScreenLockedEventAfterDelay(
402 unfoInfo_.missionId, DMS_UNFOCUSED_TYPE, SCREEN_LOCK_DELAY_TIME);
403 }
404
ResetScreenLockedInfo()405 void DMSContinueSendMgr::ScreenLockedHandler::ResetScreenLockedInfo()
406 {
407 HILOGI("clear last unfocused info");
408 unfoInfo_.missionId = INVALID_MISSION_ID;
409 unfoInfo_.unfoTime = 0;
410 unfoInfo_.status = {};
411 }
412
SetScreenLockedInfo(LastUnfoInfo info)413 void DMSContinueSendMgr::ScreenLockedHandler::SetScreenLockedInfo(LastUnfoInfo info)
414 {
415 HILOGI("set last unfocused info, missionId: %{public}d, bundleName: %{public}s, abilityName: %{public}s",
416 info.missionId, info.status.bundleName.c_str(), info.status.abilityName.c_str());
417 unfoInfo_.missionId = info.missionId;
418 unfoInfo_.unfoTime = GetTickCount();
419 unfoInfo_.status = info.status;
420 }
421
SetMissionContinueStateInfo(const MissionStatus & status)422 void DMSContinueSendMgr::ScreenLockedHandler::SetMissionContinueStateInfo(const MissionStatus& status)
423 {
424 HILOGI("set last unfocused info, status: %{public}s", status.ToString().c_str());
425 unfoInfo_.status.continueState = status.continueState;
426 }
427 } // namespace DistributedSchedule
428 } // namespace OHOS
429