1 /*
2 * Copyright (c) 2023-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 "photo_job_repository.h"
17
18 #include "deferred_photo_job.h"
19 #include "dp_log.h"
20 #include "dp_utils.h"
21 #include "dps.h"
22 #include "dps_event_report.h"
23 #include "events_monitor.h"
24 #include "notify_job_changed_command.h"
25
26 namespace OHOS {
27 namespace CameraStandard {
28 namespace DeferredProcessing {
PhotoJobStateListener(const std::weak_ptr<PhotoJobRepository> & repository)29 PhotoJobStateListener::PhotoJobStateListener(const std::weak_ptr<PhotoJobRepository>& repository)
30 : repository_(repository) {}
31
UpdateRunningJob(const std::string & imageId,bool running)32 void PhotoJobStateListener::UpdateRunningJob(const std::string& imageId, bool running)
33 {
34 DP_ERR_LOG("UpdateRunningJob: %{public}s, running state: %{public}d", imageId.c_str(), running);
35 auto repository = repository_.lock();
36 DP_CHECK_ERROR_RETURN_LOG(repository == nullptr, "PhotoJobRepository is nullptr.");
37 repository->UpdateRunningJobUnLocked(imageId, running);
38 }
39
UpdatePriorityJob(JobPriority cur,JobPriority pre)40 void PhotoJobStateListener::UpdatePriorityJob(JobPriority cur, JobPriority pre)
41 {
42 DP_ERR_LOG("UpdatePriorityJob cur: %{public}d, pre: %{public}d", cur, pre);
43 auto repository = repository_.lock();
44 DP_CHECK_ERROR_RETURN_LOG(repository == nullptr, "PhotoJobRepository is nullptr.");
45 repository->UpdatePriotyNumUnLocked(cur, pre);
46 }
47
UpdateJobSize()48 void PhotoJobStateListener::UpdateJobSize()
49 {
50 DP_ERR_LOG("UpdateJobSize");
51 auto repository = repository_.lock();
52 DP_CHECK_ERROR_RETURN_LOG(repository == nullptr, "PhotoJobRepository is nullptr.");
53 repository->UpdateJobSizeUnLocked();
54 }
55
TryDoNextJob(const std::string & imageId,bool isTyrDo)56 void PhotoJobStateListener::TryDoNextJob(const std::string& imageId, bool isTyrDo)
57 {
58 DP_ERR_LOG("TryDoNextJob");
59 auto repository = repository_.lock();
60 DP_CHECK_ERROR_RETURN_LOG(repository == nullptr, "PhotoJobRepository is nullptr.");
61 repository->NotifyJobChanged(imageId, isTyrDo);
62 }
63
PhotoJobRepository(const int32_t userId)64 PhotoJobRepository::PhotoJobRepository(const int32_t userId) : userId_(userId)
65 {
66 DP_DEBUG_LOG("entered, userId: %{public}d", userId_);
67 offlineJobQueue_ = std::make_unique<PhotoJobQueue>(
68 [] (const DeferredPhotoJobPtr& a, const DeferredPhotoJobPtr& b) {return *a > *b;});
69 }
70
~PhotoJobRepository()71 PhotoJobRepository::~PhotoJobRepository()
72 {
73 DP_INFO_LOG("entered, userId: %{public}d", userId_);
74 backgroundJobMap_.clear();
75 priotyToNum_.clear();
76 offlineJobQueue_->Clear();
77 runningJob_.clear();
78 }
79
Initialize()80 int32_t PhotoJobRepository::Initialize()
81 {
82 jobChangeListener_ = std::make_shared<PhotoJobStateListener>(weak_from_this());
83 return DP_OK;
84 }
85
AddDeferredJob(const std::string & imageId,bool discardable,DpsMetadata & metadata)86 void PhotoJobRepository::AddDeferredJob(const std::string& imageId, bool discardable, DpsMetadata& metadata)
87 {
88 DeferredPhotoJobPtr jobPtrFind = GetJobUnLocked(imageId);
89 DP_CHECK_RETURN_LOG(jobPtrFind != nullptr, "DPS_PHOTO: already existed, imageId: %{public}s", imageId.c_str());
90 int32_t type;
91 metadata.Get(DEFERRED_PROCESSING_TYPE_KEY, type);
92 auto jobPtr =
93 std::make_shared<DeferredPhotoJob>(imageId, static_cast<PhotoJobType>(type), discardable, jobChangeListener_);
94 DP_INFO_LOG("DPS_PHOTO: AddJob imageId: %{public}s, type: %{public}d, discardable: %{public}d",
95 imageId.c_str(), type, discardable);
96 if (jobPtr->GetPhotoJobType() == PhotoJobType::BACKGROUND) {
97 backgroundJobMap_.emplace(imageId, jobPtr);
98 } else {
99 offlineJobQueue_->Push(jobPtr);
100 }
101 jobPtr->Prepare();
102 ReportEvent(jobPtr, IDeferredPhotoProcessingSessionIpcCode::COMMAND_ADD_IMAGE);
103 }
104
RemoveDeferredJob(const std::string & imageId,bool restorable)105 void PhotoJobRepository::RemoveDeferredJob(const std::string& imageId, bool restorable)
106 {
107 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
108 DP_CHECK_ERROR_RETURN_LOG(jobPtr == nullptr, "Does not existed, imageId: %{public}s", imageId.c_str());
109 DP_INFO_LOG("DPS_PHOTO: RemoveJob imageId: %{public}s, type: %{public}d, restorable: %{public}d",
110 imageId.c_str(), jobPtr->GetPhotoJobType(), restorable);
111 if (restorable) {
112 jobPtr->SetJobPriority(JobPriority::LOW);
113 offlineJobQueue_->Update(jobPtr);
114 return;
115 }
116
117 if (jobPtr->GetPhotoJobType() == PhotoJobType::BACKGROUND) {
118 backgroundJobMap_.erase(imageId);
119 } else {
120 offlineJobQueue_->Remove(jobPtr);
121 }
122 jobPtr->Delete();
123 ReportEvent(jobPtr, IDeferredPhotoProcessingSessionIpcCode::COMMAND_REMOVE_IMAGE);
124 }
125
RequestJob(const std::string & imageId)126 bool PhotoJobRepository::RequestJob(const std::string& imageId)
127 {
128 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
129 DP_CHECK_ERROR_RETURN_RET_LOG(jobPtr == nullptr, false, "Does not existed, imageId: %{public}s", imageId.c_str());
130 DP_INFO_LOG("DPS_PHOTO: RequestJob imageId: %{public}s", imageId.c_str());
131 jobPtr->SetJobPriority(JobPriority::HIGH);
132 DP_CHECK_EXECUTE(jobPtr->GetCurStatus() == JobState::FAILED, jobPtr->Prepare());
133 NotifyJobChanged(imageId, true);
134 return true;
135 }
136
CancelJob(const std::string & imageId)137 void PhotoJobRepository::CancelJob(const std::string& imageId)
138 {
139 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
140 DP_CHECK_ERROR_RETURN_LOG(jobPtr == nullptr, "Does not existed, imageId: %{public}s", imageId.c_str());
141 DP_INFO_LOG("DPS_PHOTO: CancelJob imageId: %{public}s", imageId.c_str());
142 jobPtr->SetJobPriority(JobPriority::NORMAL);
143 NotifyJobChanged(imageId, false);
144 ReportEvent(jobPtr, IDeferredPhotoProcessingSessionIpcCode::COMMAND_CANCEL_PROCESS_IMAGE);
145 }
146
RestoreJob(const std::string & imageId)147 void PhotoJobRepository::RestoreJob(const std::string& imageId)
148 {
149 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
150 DP_CHECK_ERROR_RETURN_LOG(jobPtr == nullptr, "Does not existed, imageId: %{public}s", imageId.c_str());
151 DP_INFO_LOG("DPS_PHOTO: RestoreJob imageId: %{public}s", imageId.c_str());
152 jobPtr->SetJobPriority(JobPriority::NORMAL);
153 NotifyJobChanged(imageId, true);
154 ReportEvent(jobPtr, IDeferredPhotoProcessingSessionIpcCode::COMMAND_RESTORE_IMAGE);
155 }
156
GetJobState(const std::string & imageId)157 JobState PhotoJobRepository::GetJobState(const std::string& imageId)
158 {
159 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
160 if (jobPtr == nullptr) {
161 DP_INFO_LOG("Does not existed, imageId: %{public}s", imageId.c_str());
162 return JobState::NONE;
163 } else {
164 return jobPtr->GetCurStatus();
165 }
166 }
167
GetJob()168 DeferredPhotoJobPtr PhotoJobRepository::GetJob()
169 {
170 DP_INFO_LOG("DPS_PHOTO: offline size: %{public}d, background size: %{public}zu, running job: %{public}zu",
171 offlineJobQueue_->GetSize(), backgroundJobMap_.size(), runningJob_.size());
172 DeferredPhotoJobPtr jobPtr = offlineJobQueue_->Peek();
173 DP_CHECK_RETURN_RET(jobPtr == nullptr || jobPtr->GetCurStatus() >= JobState::RUNNING, nullptr);
174 return jobPtr;
175 }
176
GetJobPriority(const std::string & imageId)177 JobPriority PhotoJobRepository::GetJobPriority(const std::string& imageId)
178 {
179 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
180 DP_CHECK_RETURN_RET(jobPtr == nullptr, JobPriority::NONE);
181 return jobPtr->GetCurPriority();
182 }
183
GetJobRunningPriority(const std::string & imageId)184 JobPriority PhotoJobRepository::GetJobRunningPriority(const std::string& imageId)
185 {
186 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
187 DP_CHECK_RETURN_RET(jobPtr == nullptr, JobPriority::NONE);
188 return jobPtr->GetRunningPriority();
189 }
190
GetJobTimerId(const std::string & imageId)191 uint32_t PhotoJobRepository::GetJobTimerId(const std::string& imageId)
192 {
193 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
194 DP_CHECK_RETURN_RET(jobPtr == nullptr, INVALID_TIMERID);
195 return jobPtr->GetTimerId();
196 }
197
NotifyJobChanged(const std::string & imageId,bool isTyrDo)198 void PhotoJobRepository::NotifyJobChanged(const std::string& imageId, bool isTyrDo)
199 {
200 offlineJobQueue_->UpdateById(imageId);
201 DP_CHECK_RETURN(!isTyrDo);
202 DP_INFO_LOG("DPS_PHOTO: NotifyJobChanged imageId %{public}s", imageId.c_str());
203 auto ret = DPS_SendCommand<NotifyJobChangedCommand>(userId_);
204 DP_CHECK_ERROR_RETURN_LOG(ret != DP_OK, "NotifyJobChanged failed, ret: %{public}d", ret);
205 }
206
UpdateRunningJobUnLocked(const std::string & imageId,bool running)207 void PhotoJobRepository::UpdateRunningJobUnLocked(const std::string& imageId, bool running)
208 {
209 if (running) {
210 runningJob_.emplace(imageId);
211 ReportEvent(GetJobUnLocked(imageId), IDeferredPhotoProcessingSessionIpcCode::COMMAND_PROCESS_IMAGE);
212 } else {
213 runningJob_.erase(imageId);
214 }
215 DP_INFO_LOG("DPS_PHOTO: running job: %{public}s, total size: %{public}zu", imageId.c_str(), runningJob_.size());
216 }
217
UpdatePriotyNumUnLocked(JobPriority cur,JobPriority pre)218 void PhotoJobRepository::UpdatePriotyNumUnLocked(JobPriority cur, JobPriority pre)
219 {
220 auto it = priotyToNum_.find(cur);
221 if (it != priotyToNum_.end()) {
222 (it->second)++;
223 }
224 it = priotyToNum_.find(pre);
225 if (it != priotyToNum_.end()) {
226 (it->second)--;
227 }
228 }
229
UpdateJobSizeUnLocked()230 void PhotoJobRepository::UpdateJobSizeUnLocked()
231 {
232 EventsMonitor::GetInstance().NotifyPhotoProcessSize(offlineJobQueue_->GetSize(), backgroundJobMap_.size());
233 }
234
GetJobUnLocked(const std::string & imageId)235 DeferredPhotoJobPtr PhotoJobRepository::GetJobUnLocked(const std::string& imageId)
236 {
237 auto jobPtr = offlineJobQueue_->GetJobById(imageId);
238 if (jobPtr) {
239 DP_DEBUG_LOG("DPS_PHOTO: offline job, imageId: %{public}s", imageId.c_str());
240 return jobPtr;
241 }
242
243 auto item = backgroundJobMap_.find(imageId);
244 if (item != backgroundJobMap_.end()) {
245 DP_DEBUG_LOG("DPS_PHOTO: background job, imageId: %{public}s", imageId.c_str());
246 return item->second;
247 }
248
249 return nullptr;
250 }
251
GetBackgroundJobSize()252 int32_t PhotoJobRepository::GetBackgroundJobSize()
253 {
254 int32_t size = static_cast<int32_t>(backgroundJobMap_.size());
255 DP_DEBUG_LOG("background job size: %{public}d", size);
256 return size;
257 }
258
GetBackgroundIdleJobSize()259 int32_t PhotoJobRepository::GetBackgroundIdleJobSize()
260 {
261 int32_t size = std::count_if(backgroundJobMap_.begin(), backgroundJobMap_.end(), [](const auto& item) {
262 return item.second->GetCurStatus() < JobState::COMPLETED;
263 });
264 DP_DEBUG_LOG("background idle job size: %{public}d", size);
265 return size;
266 }
267
GetOfflineJobSize()268 int32_t PhotoJobRepository::GetOfflineJobSize()
269 {
270 DP_DEBUG_LOG("offline job size: %{public}d", offlineJobQueue_->GetSize());
271 return offlineJobQueue_->GetSize();
272 }
273
GetOfflineIdleJobSize()274 int32_t PhotoJobRepository::GetOfflineIdleJobSize()
275 {
276 auto list = offlineJobQueue_->GetAllElements();
277 int32_t size = std::count_if(list.begin(), list.end(), [](const auto& jobPtr) {
278 return jobPtr->GetCurStatus() < JobState::COMPLETED;
279 });
280 DP_DEBUG_LOG("offline idle job size: %{public}d", size);
281 return size;
282 }
283
IsBackgroundJob(const std::string & imageId)284 bool PhotoJobRepository::IsBackgroundJob(const std::string& imageId)
285 {
286 return backgroundJobMap_.find(imageId) != backgroundJobMap_.end();
287 }
288
HasUnCompletedBackgroundJob()289 bool PhotoJobRepository::HasUnCompletedBackgroundJob()
290 {
291 auto it = std::find_if(backgroundJobMap_.begin(), backgroundJobMap_.end(), [](auto& ptr) {
292 return ptr.second->GetCurStatus() == JobState::PENDING;
293 });
294 return it != backgroundJobMap_.end();
295 }
296
IsNeedInterrupt()297 bool PhotoJobRepository::IsNeedInterrupt()
298 {
299 return std::any_of(runningJob_.begin(), runningJob_.end(), [&](const auto& imageId) {
300 auto jobPtr = GetJobUnLocked(imageId);
301 DP_CHECK_RETURN_RET(jobPtr == nullptr, false);
302 return jobPtr->GetCurPriority() != JobPriority::HIGH;
303 });
304 }
305
IsHighJob(const std::string & imageId)306 bool PhotoJobRepository::IsHighJob(const std::string& imageId)
307 {
308 DeferredPhotoJobPtr jobPtr = GetJobUnLocked(imageId);
309 DP_CHECK_RETURN_RET(jobPtr == nullptr, false);
310
311 return jobPtr->GetCurPriority() == JobPriority::HIGH;
312 }
313
HasRunningJob()314 bool PhotoJobRepository::HasRunningJob()
315 {
316 return !runningJob_.empty();
317 }
318
IsRunningJob(const std::string & imageId)319 bool PhotoJobRepository::IsRunningJob(const std::string& imageId)
320 {
321 return runningJob_.find(imageId) != runningJob_.end();
322 }
323
ReportEvent(const DeferredPhotoJobPtr & jobPtr,IDeferredPhotoProcessingSessionIpcCode event)324 void PhotoJobRepository::ReportEvent(const DeferredPhotoJobPtr& jobPtr, IDeferredPhotoProcessingSessionIpcCode event)
325 {
326 DP_CHECK_ERROR_RETURN_LOG(jobPtr == nullptr, "DeferredPhotoJob is nullptr.");
327 int32_t highJobNum = priotyToNum_.find(JobPriority::HIGH)->second;
328 int32_t normalJobNum = priotyToNum_.find(JobPriority::NORMAL)->second;
329 int32_t lowJobNum = priotyToNum_.find(JobPriority::LOW)->second;
330 std::string imageId = jobPtr->GetImageId();
331 DPSEventInfo dpsEventInfo;
332 dpsEventInfo.imageId = imageId;
333 dpsEventInfo.userId = userId_;
334 dpsEventInfo.lowJobNum = lowJobNum;
335 dpsEventInfo.normalJobNum = normalJobNum;
336 dpsEventInfo.highJobNum = highJobNum;
337 dpsEventInfo.discardable = jobPtr->GetDiscardable();
338 dpsEventInfo.photoJobType = jobPtr->GetPhotoJobType();
339 dpsEventInfo.operatorStage = static_cast<uint32_t>(event);
340 uint64_t endTime = GetTimestampMilli();
341 switch (static_cast<int32_t>(event)) {
342 case static_cast<int32_t>(IDeferredPhotoProcessingSessionIpcCode::COMMAND_ADD_IMAGE): {
343 dpsEventInfo.dispatchTimeEndTime = endTime;
344 break;
345 }
346 case static_cast<int32_t>(IDeferredPhotoProcessingSessionIpcCode::COMMAND_REMOVE_IMAGE): {
347 dpsEventInfo.removeTimeBeginTime = endTime;
348 break;
349 }
350 case static_cast<int32_t>(IDeferredPhotoProcessingSessionIpcCode::COMMAND_RESTORE_IMAGE): {
351 dpsEventInfo.restoreTimeBeginTime = endTime;
352 break;
353 }
354 case static_cast<int32_t>(IDeferredPhotoProcessingSessionIpcCode::COMMAND_PROCESS_IMAGE): {
355 dpsEventInfo.processTimeBeginTime = endTime;
356 break;
357 }
358 }
359 DPSEventReport::GetInstance().ReportOperateImage(imageId, userId_, dpsEventInfo);
360 }
361 } // namespace DeferredProcessing
362 } // namespace CameraStandard
363 } // namespace OHOS