• 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_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