• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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