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 "mission/notification/dms_continue_recommend_manager.h"
17
18 #include <sys/prctl.h>
19
20 #include "bundle/bundle_manager_internal.h"
21 #include "dfx/dms_hianalytics_report.h"
22 #include "distributed_sched_utils.h"
23 #include "dtbschedmgr_device_info_storage.h"
24 #include "dtbschedmgr_log.h"
25 #include "mission/distributed_bm_storage.h"
26
27 namespace OHOS {
28 namespace DistributedSchedule {
29 namespace {
30 const std::string TAG = "DMSContinueRecomMgr";
31 constexpr int32_t STATE_ACTIVE = 0;
32 constexpr int32_t STATE_INACTIVE = 1;
33 }
34
Init(int32_t currentAccountId)35 void DMSContinueRecomMgr::Init(int32_t currentAccountId)
36 {
37 HILOGI("Init start");
38 {
39 std::unique_lock<std::mutex> lock(hasInitMutex_);
40 if (hasInit_) {
41 HILOGW("DMSContinueRecomMgr has inited");
42 return;
43 }
44 hasInit_ = true;
45 }
46 if (eventHandler_ != nullptr) {
47 HILOGI("Already inited, end.");
48 return;
49 }
50 {
51 accountId_ = currentAccountId;
52 eventThread_ = std::thread(&DMSContinueRecomMgr::StartEvent, this);
53 std::unique_lock<std::mutex> lock(eventMutex_);
54 eventCon_.wait(lock, [this] {
55 return eventHandler_ != nullptr;
56 });
57 }
58 HILOGI("Init end");
59 }
60
StartEvent()61 void DMSContinueRecomMgr::StartEvent()
62 {
63 HILOGI("StartEvent start");
64 prctl(PR_SET_NAME, TAG.c_str());
65 auto runner = AppExecFwk::EventRunner::Create(false);
66 {
67 std::lock_guard<std::mutex> lock(eventMutex_);
68 eventHandler_ = std::make_shared<OHOS::AppExecFwk::EventHandler>(runner);
69 }
70 eventCon_.notify_one();
71 CHECK_POINTER_RETURN(runner, "runner");
72 runner->Run();
73 HILOGI("StartEvent end");
74 }
75
~DMSContinueRecomMgr()76 DMSContinueRecomMgr::~DMSContinueRecomMgr()
77 {
78 HILOGI("~DMSContinueRecomMgr, accountId: %{public}d.", accountId_);
79 UnInit();
80 }
81
UnInit()82 void DMSContinueRecomMgr::UnInit()
83 {
84 HILOGI("UnInit start");
85 {
86 std::unique_lock<std::mutex> lock(hasInitMutex_);
87 if (!hasInit_) {
88 HILOGW("DMSContinueRecomMgr has uninited");
89 return;
90 }
91 hasInit_ = false;
92 }
93 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
94 if (eventHandler_->GetEventRunner() != nullptr) {
95 eventHandler_->GetEventRunner()->Stop();
96 if (eventThread_.joinable()) {
97 eventThread_.join();
98 }
99 eventHandler_ = nullptr;
100 }
101 HILOGI("UnInit end");
102 }
103
OnDeviceChanged()104 void DMSContinueRecomMgr::OnDeviceChanged()
105 {
106 HILOGI("OnDeviceChanged called");
107 int32_t missionId = GetCurrentMissionId();
108 if (missionId <= 0) {
109 HILOGW("GetCurrentMissionId failed, ret %{public}d", missionId);
110 return;
111 }
112 OnMissionStatusChanged(missionId, MISSION_EVENT_FOCUSED);
113 }
114
OnMissionStatusChanged(int32_t missionId,MissionEventType type)115 void DMSContinueRecomMgr::OnMissionStatusChanged(int32_t missionId, MissionEventType type)
116 {
117 MissionStatus status;
118 int32_t ret = DmsContinueConditionMgr::GetInstance().GetMissionStatus(accountId_, missionId, status);
119 if (ret != ERR_OK) {
120 HILOGE("GetMissionStatus failed, ret: %{public}d, missionId %{public}d, type: %{public}s",
121 ret, missionId, DmsContinueConditionMgr::GetInstance().TypeEnumToString(type).c_str());
122 return;
123 }
124
125 auto feedfunc = [this, status, type]() {
126 PublishContinueRecommend(status, type);
127 };
128 CHECK_POINTER_RETURN(eventHandler_, "eventHandler_");
129 eventHandler_->PostTask(feedfunc);
130 }
131
PublishContinueRecommend(const MissionStatus & status,MissionEventType type)132 void DMSContinueRecomMgr::PublishContinueRecommend(const MissionStatus& status, MissionEventType type)
133 {
134 auto typeStr = DmsContinueConditionMgr::GetInstance().TypeEnumToString(type);
135 HILOGI("start, missionId: %{public}d, type: %{public}s", status.missionId, typeStr.c_str());
136
137 if (!DmsContinueConditionMgr::GetInstance().CheckSystemSendCondition() ||
138 !DmsContinueConditionMgr::GetInstance().CheckMissionSendCondition(status, type)) {
139 HILOGE("CheckBroadcastCondition %{public}s failed! status: %{public}s",
140 typeStr.c_str(), status.ToString().c_str());
141 return;
142 }
143
144 ContinueRecommendInfo info;
145 if (!GetRecommendInfo(status, type, info)) {
146 HILOGE("GetRecommendInfo failed, status: %{public}s", status.ToString().c_str());
147 return;
148 }
149
150 int32_t ret = DmsHiAnalyticsReport::PublishRecommendInfo(info);
151 if (ret != ERR_OK) {
152 HILOGE("PublishRecommendInfo failed, ret: %{public}d, status: %{public}s", ret, status.ToString().c_str());
153 }
154 HILOGI("end, info: %{public}s", info.ToString().c_str());
155 return;
156 }
157
GetRecommendInfo(const MissionStatus & status,MissionEventType type,ContinueRecommendInfo & info)158 bool DMSContinueRecomMgr::GetRecommendInfo(
159 const MissionStatus& status, MissionEventType type, ContinueRecommendInfo& info)
160 {
161 HILOGD("start, missionId: %{public}d", status.missionId);
162 info.state_ = (type == MISSION_EVENT_FOCUSED || type == MISSION_EVENT_ACTIVE) ? STATE_ACTIVE : STATE_INACTIVE;
163 info.srcBundleName_ = status.bundleName;
164 info.userId_ = accountId_;
165
166 AppExecFwk::AbilityInfo abilityInfo;
167 int32_t result = BundleManagerInternal::GetLocalAbilityInfo(
168 status.bundleName, status.moduleName, status.abilityName, abilityInfo);
169 if (result != ERR_OK) {
170 HILOGW("GetLocalAbilityInfo failed.");
171 return false;
172 }
173 if (!abilityInfo.continueType.empty()) {
174 info.continueType_ = abilityInfo.continueType[0];
175 }
176
177 std::map<std::string, DmsBundleInfo> availableList;
178 bool ret = GetAvailableRecommendList(status.bundleName, availableList);
179 if (ret && info.state_ == STATE_ACTIVE) {
180 for (auto iter = availableList.begin(); iter != availableList.end(); iter++) {
181 ContinueCandidate candidate;
182 candidate.deviceId_ = iter->first;
183 candidate.dstBundleName_ = iter->second.bundleName;
184 info.candidates_.push_back(candidate);
185 }
186 }
187 HILOGD("end");
188 return true;
189 }
190
GetAvailableRecommendList(const std::string & bundleName,std::map<std::string,DmsBundleInfo> & availableList)191 bool DMSContinueRecomMgr::GetAvailableRecommendList(const std::string& bundleName,
192 std::map<std::string, DmsBundleInfo>& availableList)
193 {
194 HILOGD("called, bundleName: %{public}s", bundleName.c_str());
195 std::vector<std::string> networkIdList = DtbschedmgrDeviceInfoStorage::GetInstance().GetNetworkIdList();
196 for (const std::string& networkId : networkIdList) {
197 DmsBundleInfo sameBundleInfo;
198 if (DmsBmStorage::GetInstance()->GetDistributedBundleInfo(networkId, bundleName, sameBundleInfo) &&
199 sameBundleInfo.bundleName == bundleName) {
200 availableList[networkId] = sameBundleInfo;
201 continue;
202 }
203
204 HILOGW("get same bundle %{public}s on networkId %{public}s failed, try diff bundle.",
205 bundleName.c_str(), GetAnonymStr(networkId).c_str());
206
207 AppExecFwk::AppProvisionInfo appProvisionInfo;
208 std::string localDeveloperId;
209 if (BundleManagerInternal::GetAppProvisionInfo4CurrentUser(bundleName, appProvisionInfo)) {
210 localDeveloperId = appProvisionInfo.developerId;
211 }
212 std::vector<DmsBundleInfo> bundleInfoList;
213 if (!DmsBmStorage::GetInstance()->GetDistributeInfosByNetworkId(networkId, bundleInfoList)) {
214 HILOGW("get bundle list on networkId %{public}s failed.", GetAnonymStr(networkId).c_str());
215 continue;
216 }
217 for (const auto& diffBundleInfo : bundleInfoList) {
218 if (diffBundleInfo.developerId == localDeveloperId &&
219 IsContinuableWithDiffBundle(bundleName, diffBundleInfo)) {
220 availableList[networkId] = diffBundleInfo;
221 break;
222 }
223 }
224 }
225 return true;
226 }
227
IsContinuableWithDiffBundle(const std::string & bundleName,const DmsBundleInfo & info)228 bool DMSContinueRecomMgr::IsContinuableWithDiffBundle(const std::string& bundleName, const DmsBundleInfo& info)
229 {
230 for (const auto& abilityInfo: info.dmsAbilityInfos) {
231 auto contiName = abilityInfo.continueBundleName;
232 if (std::find(contiName.begin(), contiName.end(), bundleName) != contiName.end()) {
233 return true;
234 }
235 }
236 return false;
237 }
238 } // namespace DistributedSchedule
239 } // namespace OHOS
240