1 /*
2 * Copyright (C) 2024 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 #define MLOG_TAG "PictureDataOperations"
17
18 #include "picture_data_operations.h"
19
20 #include "file_utils.h"
21 #include "media_column.h"
22 #include "media_log.h"
23 #include "medialibrary_data_manager_utils.h"
24 #include "medialibrary_unistore_manager.h"
25 #include "parameter.h"
26 #include "parameters.h"
27 #include "result_set_utils.h"
28 #include "medialibrary_tracer.h"
29
30 using namespace std;
31 namespace OHOS {
32 namespace Media {
33 int32_t PictureDataOperations::taskSize = 0;
34 const int32_t SAVE_PICTURE_TIMEOUT_SEC = 20;
35
PictureDataOperations()36 PictureDataOperations::PictureDataOperations() {}
37
~PictureDataOperations()38 PictureDataOperations::~PictureDataOperations()
39 {
40 lowQualityPictureMap_.clear();
41 highQualityPictureMap_.clear();
42 highQualityPictureImageId.clear();
43 }
44
IsPictureTempAndEdited(const string & photoId,bool & isTemp,bool & isEdited)45 static int32_t IsPictureTempAndEdited(const string &photoId, bool &isTemp, bool &isEdited)
46 {
47 MediaLibraryTracer tracer;
48 tracer.Start("IsPictureTempAndEdited " + photoId);
49 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
50 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_ERR, "Failed to get rdbStore");
51 NativeRdb::AbsRdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
52 predicates.EqualTo(PhotoColumn::PHOTO_ID, photoId);
53 vector<string> columns { PhotoColumn::PHOTO_IS_TEMP, PhotoColumn::PHOTO_EDIT_TIME };
54 auto resultSet = rdbStore->Query(predicates, columns);
55 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK,
56 E_ERR, "resultSet is empty");
57 isTemp = (GetInt32Val(PhotoColumn::PHOTO_IS_TEMP, resultSet) == 1);
58 isEdited = (GetInt64Val(PhotoColumn::PHOTO_EDIT_TIME, resultSet) > 0);
59 return E_OK;
60 }
61
CleanPictureMapData(std::map<std::string,sptr<PicturePair>> & pictureMap,PictureType pictureType)62 void PictureDataOperations::CleanPictureMapData(std::map<std::string, sptr<PicturePair>>& pictureMap,
63 PictureType pictureType)
64 {
65 MEDIA_INFO_LOG("enter CleanPictureMapData, pictureMap size: %{public}d, pictureType: %{public}d",
66 static_cast<int32_t>(pictureMap.size()), static_cast<int32_t>(pictureType));
67 auto iter = pictureMap.begin();
68 while (iter != pictureMap.end()) {
69 time_t now = time(nullptr);
70 bool isNeedDeletePicture = ((iter->second)->expireTime_ < now) && ((iter->second)->isCleanImmediately_);
71 if (isNeedDeletePicture || ((iter->second)->expireTime_ + SAVE_PICTURE_TIMEOUT_SEC) < now) {
72 bool isTemp = false;
73 bool isEdited = false;
74 IsPictureTempAndEdited(iter->first, isTemp, isEdited);
75 bool isLowQualityPicture = (pictureType != HIGH_QUALITY_PICTURE);
76 if (isTemp) {
77 FileUtils::SavePicture(iter->first, (iter->second)->picture_, isEdited, isLowQualityPicture);
78 MEDIA_INFO_LOG("end SavePicture, photoId: %{public}s, isEdited: %{public}d",
79 (iter->first).c_str(), static_cast<int32_t>(isEdited));
80 }
81 MEDIA_INFO_LOG("enter CleanDateByPictureMap %{public}s enter", (iter->first).c_str());
82 iter->second = nullptr;
83 iter = pictureMap.erase(iter);
84 } else {
85 iter++;
86 }
87 }
88 MEDIA_INFO_LOG("end CleanPictureMapData, pictureMap size: %{public}d, pictureType: %{public}d",
89 static_cast<int32_t>(pictureMap.size()), static_cast<int32_t>(pictureType));
90 }
91
CleanDateForPeriodical()92 void PictureDataOperations::CleanDateForPeriodical()
93 {
94 MEDIA_INFO_LOG("enter CleanDateForPeriodical.");
95 lock_guard<mutex> lock(pictureMapMutex_);
96 enum PictureType pictureType;
97 for (pictureType = LOW_QUALITY_PICTURE; pictureType <= HIGH_QUALITY_PICTURE;
98 pictureType = (PictureType)(pictureType + 1)) {
99 switch (pictureType) {
100 case LOW_QUALITY_PICTURE:
101 CleanPictureMapData(lowQualityPictureMap_, pictureType);
102 break;
103 case HIGH_QUALITY_PICTURE:
104 CleanPictureMapData(highQualityPictureMap_, pictureType);
105 break;
106 default:
107 break;
108 }
109 }
110 MEDIA_INFO_LOG("end CleanDateForPeriodical.");
111 }
112
InsertPictureData(const std::string & imageId,sptr<PicturePair> & picturePair,PictureType pictureType)113 void PictureDataOperations::InsertPictureData(const std::string& imageId, sptr<PicturePair>& picturePair,
114 PictureType pictureType)
115 {
116 MEDIA_INFO_LOG("enter InsertPictureData, imageId: %{public}s, pictureType: %{public}d", imageId.c_str(),
117 static_cast<int32_t>(pictureType));
118 switch (pictureType) {
119 case LOW_QUALITY_PICTURE:{
120 lock_guard<mutex> lock(pictureMapMutex_);
121 auto iter = lowQualityPictureMap_.find(imageId);
122 if (iter != lowQualityPictureMap_.end()) {
123 iter->second = nullptr;
124 lowQualityPictureMap_.erase(iter);
125 }
126 lowQualityPictureMap_[imageId] = picturePair;
127 }
128 break;
129 case HIGH_QUALITY_PICTURE:
130 if (highQualityPictureMap_.find(imageId) == highQualityPictureMap_.end()) {
131 highQualityPictureImageId.push_back(imageId);
132 }
133 CleanHighQualityPictureDataInternal(imageId, picturePair, highQualityPictureImageId);
134 break;
135 default:
136 break;
137 }
138
139 MEDIA_INFO_LOG("end InsertPictureData, lowQualityPictureMap: %{public}d, highQualityPictureMap: %{public}d",
140 static_cast<int32_t>(lowQualityPictureMap_.size()), static_cast<int32_t>(highQualityPictureMap_.size()));
141 }
142
CleanHighQualityPictureDataInternal(const std::string & imageId,sptr<PicturePair> & picturePair,std::list<std::string> & pictureImageIdList)143 void PictureDataOperations::CleanHighQualityPictureDataInternal(const std::string& imageId,
144 sptr<PicturePair>& picturePair,
145 std::list<std::string>& pictureImageIdList)
146 {
147 MEDIA_INFO_LOG("enter CleanHighQualityPictureDataInternal, %{public}zu, %{public}zu",
148 lowQualityPictureMap_.size(), highQualityPictureMap_.size());
149 lock_guard<mutex> lock(pictureMapMutex_);
150 // 清理低质量图
151 auto iterPicture = lowQualityPictureMap_.find(imageId);
152 if (iterPicture != lowQualityPictureMap_.end() && (iterPicture->second)->isCleanImmediately_) {
153 lowQualityPictureMap_.erase(iterPicture);
154 }
155 // 存储高质量图
156 iterPicture = highQualityPictureMap_.find(imageId);
157 if (iterPicture != highQualityPictureMap_.end() && (iterPicture->second)->isCleanImmediately_) {
158 highQualityPictureMap_.erase(iterPicture);
159 }
160 highQualityPictureMap_[imageId] = picturePair;
161
162 // 删除至最大值,高质量不用落盘
163 for (auto iter = pictureImageIdList.begin(); iter != pictureImageIdList.end();) {
164 if ((int)(highQualityPictureMap_.size()) <= max_capibilty) {
165 return;
166 }
167 std::string imageId = *iter;
168 std::map<std::string, sptr<PicturePair>>::iterator iterPicture = highQualityPictureMap_.find(imageId);
169 if (iterPicture != highQualityPictureMap_.end() && (iterPicture->second)->isCleanImmediately_) {
170 bool isTemp = false;
171 bool isEdited = false;
172 IsPictureTempAndEdited(iterPicture->first, isTemp, isEdited);
173 if (isTemp) {
174 FileUtils::SavePicture(iterPicture->first, (iterPicture->second)->picture_, isEdited, false);
175 MEDIA_INFO_LOG("end SavePicture, photoId: %{public}s, isEdited: %{public}d",
176 (iterPicture->first).c_str(), static_cast<int32_t>(isEdited));
177 }
178 highQualityPictureMap_.erase(iterPicture);
179 iter = pictureImageIdList.erase(iter);
180 } else {
181 iter++;
182 }
183 }
184 MEDIA_DEBUG_LOG("end");
185 }
186
GetDataWithImageId(const std::string & imageId,bool & isHighQualityPicture,bool & isTakeEffect,bool isCleanImmediately)187 std::shared_ptr<Media::Picture> PictureDataOperations::GetDataWithImageId(const std::string& imageId,
188 bool &isHighQualityPicture, bool &isTakeEffect, bool isCleanImmediately)
189 {
190 MEDIA_DEBUG_LOG("enter %{public}s enter", imageId.c_str());
191 enum PictureType pictureType;
192 std::shared_ptr<Media::Picture> picture;
193 isHighQualityPicture = false;
194 for (pictureType = HIGH_QUALITY_PICTURE; pictureType >= LOW_QUALITY_PICTURE;
195 pictureType = (PictureType)(pictureType - 1)) {
196 picture = GetDataWithImageIdAndPictureType(imageId, pictureType, isTakeEffect, isCleanImmediately);
197 if (picture != nullptr && picture->GetMainPixel() != nullptr) {
198 MEDIA_INFO_LOG("GetDataWithImageId is founded, pictureType:%{public}d", static_cast<int32_t>(pictureType));
199 isHighQualityPicture = (pictureType == HIGH_QUALITY_PICTURE);
200 return picture;
201 } else {
202 MEDIA_INFO_LOG("GetDataWithImageId not found, pictureType:%{public}d", static_cast<int32_t>(pictureType));
203 }
204 }
205 return picture;
206 }
207
208
SavePictureWithImageId(const std::string & imageId)209 void PictureDataOperations::SavePictureWithImageId(const std::string& imageId)
210 {
211 MEDIA_DEBUG_LOG("enter ");
212 enum PictureType pictureType;
213 bool isSuccess = false;
214 for (pictureType = HIGH_QUALITY_PICTURE; pictureType >= LOW_QUALITY_PICTURE;
215 pictureType = (PictureType)(pictureType - 1)) {
216 switch (pictureType) {
217 case LOW_QUALITY_PICTURE:
218 isSuccess = SavePicture(imageId, lowQualityPictureMap_, true);
219 break;
220 case HIGH_QUALITY_PICTURE:
221 isSuccess = SavePicture(imageId, highQualityPictureMap_, false);
222 break;
223 default:
224 break;
225 }
226 }
227 if (isSuccess) { // 高质量提前返回
228 return;
229 }
230 MEDIA_DEBUG_LOG("end ");
231 }
232
GetDataWithImageIdAndPictureType(const std::string & imageId,PictureType pictureType,bool & isTakeEffect,bool isCleanImmediately)233 std::shared_ptr<Media::Picture> PictureDataOperations::GetDataWithImageIdAndPictureType(const std::string& imageId,
234 PictureType pictureType, bool &isTakeEffect, bool isCleanImmediately)
235 {
236 MEDIA_DEBUG_LOG("enter ");
237 lock_guard<mutex> lock(pictureMapMutex_);
238 std::map<std::string, sptr<PicturePair>>::iterator iter;
239 std::shared_ptr<Media::Picture> picture;
240 switch (pictureType) {
241 case LOW_QUALITY_PICTURE:
242 iter = lowQualityPictureMap_.find(imageId);
243 if (iter != lowQualityPictureMap_.end()) {
244 (iter->second)->isCleanImmediately_ = isCleanImmediately;
245 picture = (iter->second)->picture_;
246 }
247 break;
248 case HIGH_QUALITY_PICTURE:
249 iter = highQualityPictureMap_.find(imageId);
250 if (iter != highQualityPictureMap_.end()) {
251 (iter->second)->isCleanImmediately_ = isCleanImmediately;
252 picture = (iter->second)->picture_;
253 isTakeEffect = (iter->second)->isTakeEffect_;
254 }
255 break;
256 default:
257 break;
258 }
259 return picture;
260 }
261
IsExsitDataForPictureType(PictureType pictureType)262 bool PictureDataOperations::IsExsitDataForPictureType(PictureType pictureType)
263 {
264 MEDIA_DEBUG_LOG("enter ");
265 lock_guard<mutex> lock(pictureMapMutex_);
266 bool isExsit = false;
267 switch (pictureType) {
268 case LOW_QUALITY_PICTURE:
269 isExsit = lowQualityPictureMap_.size() >= 1;
270 break;
271 case HIGH_QUALITY_PICTURE:
272 isExsit = highQualityPictureMap_.size() >= 1;
273 break;
274 default:
275 break;
276 }
277 return isExsit;
278 }
279
IsExsitDataForPictureType(const std::string & imageId,PictureType pictureType)280 bool PictureDataOperations::IsExsitDataForPictureType(const std::string& imageId, PictureType pictureType)
281 {
282 MEDIA_DEBUG_LOG("enter ");
283 lock_guard<mutex> lock(pictureMapMutex_);
284 bool isExsit = false;
285 switch (pictureType) {
286 case LOW_QUALITY_PICTURE:
287 isExsit = lowQualityPictureMap_.size() >= 0 &&
288 lowQualityPictureMap_.find(imageId) != lowQualityPictureMap_.end();
289 break;
290 case HIGH_QUALITY_PICTURE:
291 isExsit = highQualityPictureMap_.size() > 0 &&
292 highQualityPictureMap_.find(imageId) != highQualityPictureMap_.end();
293 break;
294 default:
295 break;
296 }
297 return isExsit;
298 }
299
300 // 落盘低质量图,包括低质量裸图/低质量
SaveLowQualityPicture(const std::string & imageId)301 void PictureDataOperations::SaveLowQualityPicture(const std::string& imageId)
302 {
303 MEDIA_DEBUG_LOG("enter ");
304 enum PictureType pictureType;
305 bool isSuccess = SavePicture(imageId, lowQualityPictureMap_, true);
306 }
307
308 // 落盘低质量图,包括低质量裸图
SavePicture(const std::string & imageId,std::map<std::string,sptr<PicturePair>> & pictureMap,bool isLowQualityPicture)309 bool PictureDataOperations::SavePicture(const std::string& imageId,
310 std::map<std::string, sptr<PicturePair>>& pictureMap, bool isLowQualityPicture)
311 {
312 MEDIA_INFO_LOG("enter photoId: %{public}s, isLowQualityPicture: %{public}d", imageId.c_str(), isLowQualityPicture);
313 lock_guard<mutex> lock(pictureMapMutex_);
314 bool isSuccess = false;
315 CHECK_AND_RETURN_RET_LOG(pictureMap.size() != 0, false, "pictureMap is null.");
316
317 std::map<std::string, sptr<PicturePair>>::iterator iter;
318 if (imageId == "default") {
319 iter = pictureMap.begin();
320 } else {
321 iter = pictureMap.find(imageId);
322 }
323 if (iter != pictureMap.end()) {
324 FileUtils::SavePicture(iter->first, (iter->second)->picture_, false, isLowQualityPicture);
325 MEDIA_INFO_LOG("SavePicture, photoId: %{public}s, isLowQualityPicture: %{public}d",
326 imageId.c_str(), isLowQualityPicture);
327 // 落盘后清除缓存数据
328 pictureMap.erase(iter);
329 isSuccess = true;
330 }
331 MEDIA_INFO_LOG("SavePicture end, isSuccess: %{public}d, map size: %{public}zu", isSuccess, pictureMap.size());
332 return isSuccess;
333 }
334
SavePictureExecutor(AsyncTaskData * data)335 void PictureDataOperations::SavePictureExecutor(AsyncTaskData *data)
336 {
337 auto *taskData = static_cast<SavePictureData *>(data);
338 auto picturePair = taskData->picturePair_;
339
340 MEDIA_DEBUG_LOG("SavePictureExecutor %{public}d ", taskSize);
341 FileUtils::SavePicture(picturePair->photoId_, picturePair->picture_, false, true);
342 picturePair->isCleanImmediately_ = true;
343 taskSize --;
344 }
345
AddSavePictureTask(sptr<PicturePair> & picturePair)346 int32_t PictureDataOperations::AddSavePictureTask(sptr<PicturePair>& picturePair)
347 {
348 auto asyncWorker = MediaLibraryAsyncWorker::GetInstance();
349 if (asyncWorker == nullptr) {
350 MEDIA_DEBUG_LOG("Failed to get async worker instance!");
351 return -1;
352 }
353
354 auto *taskData = new (std::nothrow) SavePictureData(picturePair);
355 CHECK_AND_RETURN_RET_LOG(taskData != nullptr, -1,
356 "Failed to alloc async data for downloading cloud files!");
357
358 auto asyncTask = std::make_shared<MediaLibraryAsyncTask>(SavePictureExecutor, taskData);
359 asyncWorker->AddTask(asyncTask, true);
360 taskSize ++;
361 return 0;
362 }
363
GetPendingTaskSize()364 int32_t PictureDataOperations::GetPendingTaskSize()
365 {
366 lock_guard<mutex> lock(pictureMapMutex_);
367 MEDIA_INFO_LOG("GetPendingTaskSize, lowQualityPictureMap: %{public}d, highQualityPictureMap: %{public}d",
368 static_cast<int32_t>(lowQualityPictureMap_.size()), static_cast<int32_t>(highQualityPictureMap_.size()));
369 return lowQualityPictureMap_.size() + highQualityPictureMap_.size();
370 }
371
DeleteDataWithImageId(const std::string & imageId,PictureType pictureType)372 void PictureDataOperations::DeleteDataWithImageId(const std::string& imageId, PictureType pictureType)
373 {
374 MEDIA_DEBUG_LOG("enter ");
375 lock_guard<mutex> lock(pictureMapMutex_);
376 MEDIA_INFO_LOG("DeleteDataWithImageId start, imageId: %{public}s, pictureType: %{public}d",
377 imageId.c_str(), static_cast<int32_t>(pictureType));
378 std::map<std::string, sptr<PicturePair>>::iterator iter;
379 switch (pictureType) {
380 case LOW_QUALITY_PICTURE:
381 iter = lowQualityPictureMap_.find(imageId);
382 if (iter != lowQualityPictureMap_.end()) {
383 (iter->second)->picture_ = nullptr;
384 lowQualityPictureMap_.erase(iter);
385 }
386 break;
387 case HIGH_QUALITY_PICTURE:
388 iter = highQualityPictureMap_.find(imageId);
389 if (iter != highQualityPictureMap_.end()) {
390 (iter->second)->picture_ = nullptr;
391 highQualityPictureMap_.erase(iter);
392 }
393 break;
394 default:
395 break;
396 }
397 MEDIA_DEBUG_LOG("DeleteDataWithImageId end: %{public}s", imageId.c_str());
398 }
399
FinishAccessingPicture(const std::string & imageId,PictureType pictureType)400 void PictureDataOperations::FinishAccessingPicture(const std::string& imageId, PictureType pictureType)
401 {
402 lock_guard<mutex> lock(pictureMapMutex_);
403 MEDIA_INFO_LOG("FinishAccessingPicture start, imageId: %{public}s, pictureType: %{public}d",
404 imageId.c_str(), static_cast<int32_t>(pictureType));
405 std::map<std::string, sptr<PicturePair>>::iterator iter;
406 switch (pictureType) {
407 case LOW_QUALITY_PICTURE:
408 iter = lowQualityPictureMap_.find(imageId);
409 if (iter != lowQualityPictureMap_.end()) {
410 (iter->second)->isCleanImmediately_ = true;
411 }
412 break;
413 case HIGH_QUALITY_PICTURE:
414 iter = highQualityPictureMap_.find(imageId);
415 if (iter != highQualityPictureMap_.end()) {
416 (iter->second)->isCleanImmediately_ = true;
417 }
418 break;
419 default:
420 break;
421 }
422 MEDIA_DEBUG_LOG("FinishAccessingPicture end: %{public}s", imageId.c_str());
423 }
424 } // namespace Media
425 } // namespace OHOS