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