1 /*
2 * Copyright (C) 2022 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 #define MLOG_TAG "Thumbnail"
16
17 #include "thumbnail_generate_helper.h"
18
19 #include <fcntl.h>
20
21 #include "acl.h"
22 #include "dfx_const.h"
23 #include "dfx_manager.h"
24 #include "dfx_timer.h"
25 #include "dfx_utils.h"
26 #include "ffrt.h"
27 #include "ffrt_inner.h"
28 #include "directory_ex.h"
29 #include "ithumbnail_helper.h"
30 #include "medialibrary_errno.h"
31 #include "medialibrary_kvstore_manager.h"
32 #include "medialibrary_photo_operations.h"
33 #include "medialibrary_type_const.h"
34 #include "media_file_utils.h"
35 #include "media_log.h"
36 #include "thumbnail_const.h"
37 #include "thumbnail_generate_worker_manager.h"
38 #include "thumbnail_source_loading.h"
39 #include "thumbnail_utils.h"
40
41 using namespace std;
42 using namespace OHOS::DistributedKv;
43 using namespace OHOS::NativeRdb;
44
45 namespace OHOS {
46 namespace Media {
47 const int FFRT_MAX_RESTORE_ASTC_THREADS = 4;
48 const std::string SQL_REFRESH_THUMBNAIL_READY =
49 " Update " + PhotoColumn::PHOTOS_TABLE + " SET " + PhotoColumn::PHOTO_THUMBNAIL_READY + " = 7 " +
50 " WHERE " + PhotoColumn::PHOTO_THUMBNAIL_READY + " != 0; END;";
51
CreateThumbnailFileScaned(ThumbRdbOpt & opts,bool isSync)52 int32_t ThumbnailGenerateHelper::CreateThumbnailFileScaned(ThumbRdbOpt &opts, bool isSync)
53 {
54 ThumbnailData thumbnailData;
55 ThumbnailUtils::GetThumbnailInfo(opts, thumbnailData);
56 thumbnailData.needResizeLcd = true;
57 thumbnailData.loaderOpts.loadingStates = SourceLoader::LOCAL_SOURCE_LOADING_STATES;
58 ThumbnailUtils::RecordStartGenerateStats(thumbnailData.stats, GenerateScene::LOCAL, LoadSourceType::LOCAL_PHOTO);
59 if (ThumbnailUtils::DeleteThumbExDir(thumbnailData)) {
60 MEDIA_ERR_LOG("Delete THM_EX directory, path: %{public}s, id: %{public}s",
61 DfxUtils::GetSafePath(thumbnailData.path).c_str(), thumbnailData.id.c_str());
62 }
63
64 if (isSync) {
65 WaitStatus status;
66 bool isSuccess = IThumbnailHelper::DoCreateLcdAndThumbnail(opts, thumbnailData, status);
67 if (status == WaitStatus::INSERT) {
68 IThumbnailHelper::UpdateThumbnailState(opts, thumbnailData, isSuccess);
69 }
70 ThumbnailUtils::RecordCostTimeAndReport(thumbnailData.stats);
71 } else {
72 IThumbnailHelper::AddThumbnailGenerateTask(IThumbnailHelper::CreateLcdAndThumbnail,
73 opts, thumbnailData, ThumbnailTaskType::FOREGROUND, ThumbnailTaskPriority::HIGH);
74 }
75 return E_OK;
76 }
77
CreateThumbnailBackground(ThumbRdbOpt & opts)78 int32_t ThumbnailGenerateHelper::CreateThumbnailBackground(ThumbRdbOpt &opts)
79 {
80 if (opts.store == nullptr) {
81 MEDIA_ERR_LOG("rdbStore is not init");
82 return E_ERR;
83 }
84 CHECK_AND_RETURN_RET_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
85 E_FREE_SIZE_NOT_ENOUGH, "Free size is not enough");
86
87 vector<ThumbnailData> infos;
88 int32_t err = GetNoThumbnailData(opts, infos);
89 if (err != E_OK) {
90 MEDIA_ERR_LOG("Failed to GetNoLThumbnailData %{private}d", err);
91 return err;
92 }
93
94 if (infos.empty()) {
95 MEDIA_DEBUG_LOG("No need generate thumbnail.");
96 return E_OK;
97 }
98 auto createThumbnailBackgroundTask = [](std::shared_ptr<ThumbnailTaskData> &data) {
99 CHECK_AND_RETURN_LOG(data != nullptr, "Data is null");
100 auto &thumbnailData = data->thumbnailData_;
101 CHECK_AND_RETURN_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
102 "CreateThumbnailBackgroundTask free size is not enough, id:%{public}s, path:%{public}s",
103 thumbnailData.id.c_str(), DfxUtils::GetSafePath(thumbnailData.path).c_str());
104 IThumbnailHelper::CreateThumbnail(data);
105 };
106
107 for (uint32_t i = 0; i < infos.size(); i++) {
108 opts.row = infos[i].id;
109 infos[i].loaderOpts.loadingStates = infos[i].isLocalFile ? SourceLoader::LOCAL_SOURCE_LOADING_STATES :
110 SourceLoader::CLOUD_SOURCE_LOADING_STATES;
111 IThumbnailHelper::AddThumbnailGenerateTask(createThumbnailBackgroundTask,
112 opts, infos[i], ThumbnailTaskType::BACKGROUND, ThumbnailTaskPriority::LOW);
113 }
114
115 return E_OK;
116 }
117
CreateAstcBackground(ThumbRdbOpt & opts)118 int32_t ThumbnailGenerateHelper::CreateAstcBackground(ThumbRdbOpt &opts)
119 {
120 if (opts.store == nullptr) {
121 MEDIA_ERR_LOG("rdbStore is not init");
122 return E_ERR;
123 }
124
125 CheckMonthAndYearKvStoreValid(opts);
126 CHECK_AND_RETURN_RET_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
127 E_FREE_SIZE_NOT_ENOUGH, "Free size is not enough");
128 vector<ThumbnailData> infos;
129 int32_t err = GetNoAstcData(opts, infos);
130 if (err != E_OK) {
131 MEDIA_ERR_LOG("Failed to GetNoAstcData %{private}d", err);
132 return err;
133 }
134
135 auto kvStore = MediaLibraryKvStoreManager::GetInstance()
136 .GetKvStore(KvStoreRoleType::OWNER, KvStoreValueType::MONTH_ASTC);
137 if (infos.empty() || kvStore == nullptr) {
138 MEDIA_DEBUG_LOG("No need create Astc.");
139 return E_OK;
140 }
141
142 auto createAstcBackgroundTask = [](std::shared_ptr<ThumbnailTaskData> &data) {
143 CHECK_AND_RETURN_LOG(data != nullptr, "Data is null");
144 auto &thumbnailData = data->thumbnailData_;
145 CHECK_AND_RETURN_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
146 "CreateAstcBackgroundTask free size is not enough, id:%{public}s, path:%{public}s",
147 thumbnailData.id.c_str(), DfxUtils::GetSafePath(thumbnailData.path).c_str());
148 if (thumbnailData.isLocalFile) {
149 thumbnailData.loaderOpts.loadingStates = SourceLoader::LOCAL_SOURCE_LOADING_STATES;
150 IThumbnailHelper::CreateThumbnail(data);
151 } else {
152 thumbnailData.loaderOpts.loadingStates = thumbnailData.orientation != 0 ?
153 SourceLoader::CLOUD_LCD_SOURCE_LOADING_STATES : SourceLoader::CLOUD_SOURCE_LOADING_STATES;
154 thumbnailData.orientation != 0 ? IThumbnailHelper::CreateAstcEx(data) : IThumbnailHelper::CreateAstc(data);
155 }
156 };
157
158 MEDIA_INFO_LOG("no astc data size: %{public}d", static_cast<int>(infos.size()));
159 for (uint32_t i = 0; i < infos.size(); i++) {
160 opts.row = infos[i].id;
161 ThumbnailUtils::RecordStartGenerateStats(infos[i].stats, GenerateScene::BACKGROUND,
162 LoadSourceType::LOCAL_PHOTO);
163 IThumbnailHelper::AddThumbnailGenerateTask(createAstcBackgroundTask,
164 opts, infos[i], ThumbnailTaskType::BACKGROUND, ThumbnailTaskPriority::LOW);
165 }
166 return E_OK;
167 }
168
CreateAstcCloudDownload(ThumbRdbOpt & opts,bool isCloudInsertTaskPriorityHigh)169 int32_t ThumbnailGenerateHelper::CreateAstcCloudDownload(ThumbRdbOpt &opts, bool isCloudInsertTaskPriorityHigh)
170 {
171 ThumbnailData data;
172 ThumbnailUtils::RecordStartGenerateStats(data.stats, GenerateScene::CLOUD, LoadSourceType::LOCAL_PHOTO);
173 int err = 0;
174 ThumbnailUtils::QueryThumbnailDataFromFileId(opts, opts.fileId, data, err);
175 if (err != E_OK) {
176 MEDIA_ERR_LOG("QueryThumbnailDataFromFileId failed, path: %{public}s",
177 DfxUtils::GetSafePath(data.path).c_str());
178 return err;
179 }
180 ValuesBucket values;
181 Size lcdSize;
182 if (data.mediaType == MEDIA_TYPE_VIDEO && ThumbnailUtils::GetLocalThumbSize(data, ThumbnailType::LCD, lcdSize)) {
183 ThumbnailUtils::SetThumbnailSizeValue(values, lcdSize, PhotoColumn::PHOTO_LCD_SIZE);
184 int changedRows;
185 int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
186 vector<string> { data.id });
187 if (err != NativeRdb::E_OK) {
188 MEDIA_ERR_LOG("RdbStore lcd size failed! %{public}d", err);
189 }
190 }
191
192 data.loaderOpts.loadingStates = data.orientation != 0 ?
193 SourceLoader::CLOUD_LCD_SOURCE_LOADING_STATES : SourceLoader::CLOUD_SOURCE_LOADING_STATES;
194 if (isCloudInsertTaskPriorityHigh) {
195 IThumbnailHelper::AddThumbnailGenerateTask(data.orientation != 0 ?
196 IThumbnailHelper::CreateAstcEx : IThumbnailHelper::CreateAstc,
197 opts, data, ThumbnailTaskType::FOREGROUND, ThumbnailTaskPriority::MID);
198 return E_OK;
199 }
200
201 auto lowPriorityCreateAstcCloudDownloadTask = [](std::shared_ptr<ThumbnailTaskData> &data) {
202 CHECK_AND_RETURN_LOG(data != nullptr, "Data is null");
203 auto &thumbnailData = data->thumbnailData_;
204 CHECK_AND_RETURN_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
205 "LowPriorityCreateAstcCloudDownloadTask free size is not enough, id:%{public}s, path:%{public}s",
206 thumbnailData.id.c_str(), DfxUtils::GetSafePath(thumbnailData.path).c_str());
207 thumbnailData.orientation != 0 ? IThumbnailHelper::CreateAstcEx(data) : IThumbnailHelper::CreateAstc(data);
208 };
209 IThumbnailHelper::AddThumbnailGenerateTask(lowPriorityCreateAstcCloudDownloadTask,
210 opts, data, ThumbnailTaskType::BACKGROUND, ThumbnailTaskPriority::LOW);
211 return E_OK;
212 }
213
CreateAstcBatchOnDemand(ThumbRdbOpt & opts,NativeRdb::RdbPredicates & predicate,int32_t requestId)214 int32_t ThumbnailGenerateHelper::CreateAstcBatchOnDemand(
215 ThumbRdbOpt &opts, NativeRdb::RdbPredicates &predicate, int32_t requestId)
216 {
217 if (opts.store == nullptr) {
218 MEDIA_ERR_LOG("rdbStore is not init");
219 return E_ERR;
220 }
221
222 vector<ThumbnailData> infos;
223 int32_t err = 0;
224 if (!ThumbnailUtils::QueryNoAstcInfosOnDemand(opts, infos, predicate, err)) {
225 MEDIA_ERR_LOG("Failed to QueryNoAstcInfos %{public}d", err);
226 return err;
227 }
228 if (infos.empty()) {
229 MEDIA_DEBUG_LOG("No need create Astc.");
230 return E_THUMBNAIL_ASTC_ALL_EXIST;
231 }
232
233 MEDIA_INFO_LOG("no astc data size: %{public}d, requestId: %{public}d", static_cast<int>(infos.size()), requestId);
234 for (auto& info : infos) {
235 opts.row = info.id;
236 ThumbnailUtils::RecordStartGenerateStats(info.stats, GenerateScene::FOREGROUND, LoadSourceType::LOCAL_PHOTO);
237 if (info.isLocalFile) {
238 info.loaderOpts.loadingStates = SourceLoader::LOCAL_SOURCE_LOADING_STATES;
239 IThumbnailHelper::AddThumbnailGenBatchTask(IThumbnailHelper::CreateThumbnail, opts, info, requestId);
240 continue;
241 }
242 if (info.orientation != 0) {
243 info.loaderOpts.loadingStates = SourceLoader::CLOUD_LCD_SOURCE_LOADING_STATES;
244 } else if (info.mediaType == MEDIA_TYPE_VIDEO) {
245 info.loaderOpts.loadingStates = SourceLoader::ALL_SOURCE_LOADING_CLOUD_VIDEO_STATES;
246 } else {
247 info.loaderOpts.loadingStates = SourceLoader::ALL_SOURCE_LOADING_STATES;
248 }
249 IThumbnailHelper::AddThumbnailGenBatchTask(info.orientation == 0 ?
250 IThumbnailHelper::CreateAstc : IThumbnailHelper::CreateAstcEx, opts, info, requestId);
251 }
252 return E_OK;
253 }
254
NeedGenerateLocalLcd(ThumbnailData & data)255 bool NeedGenerateLocalLcd(ThumbnailData &data)
256 {
257 std::string lcdLocalPath = GetLocalThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX);
258 size_t lcdSize = -1;
259
260 // Local LCD exist, and its size is less than upload limit
261 if (access(lcdLocalPath.c_str(), F_OK) == 0 && MediaFileUtils::GetFileSize(lcdLocalPath, lcdSize) &&
262 lcdSize < LCD_UPLOAD_LIMIT_SIZE) {
263 return false;
264 }
265 MEDIA_INFO_LOG("Local file Lcd need to be generate, size: %{public}d, path: %{public}s",
266 static_cast<int>(lcdSize), DfxUtils::GetSafePath(data.path).c_str());
267 return true;
268 }
269
CreateLcdBackground(ThumbRdbOpt & opts)270 int32_t ThumbnailGenerateHelper::CreateLcdBackground(ThumbRdbOpt &opts)
271 {
272 if (opts.store == nullptr) {
273 return E_ERR;
274 }
275 CHECK_AND_RETURN_RET_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
276 E_FREE_SIZE_NOT_ENOUGH, "Free size is not enough");
277
278 vector<ThumbnailData> infos;
279 int32_t err = GetNoLcdData(opts, infos);
280 if (err != E_OK) {
281 MEDIA_ERR_LOG("Failed to GetNoLcdData %{private}d", err);
282 return err;
283 }
284 if (infos.empty()) {
285 MEDIA_DEBUG_LOG("No need create Lcd.");
286 return E_THUMBNAIL_LCD_ALL_EXIST;
287 }
288 auto createLcdBackgroundTask = [](std::shared_ptr<ThumbnailTaskData> &data) {
289 CHECK_AND_RETURN_LOG(data != nullptr, "CreateLcd failed, data is null");
290 auto &thumbnailData = data->thumbnailData_;
291 CHECK_AND_RETURN_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
292 "CreateLcdBackgroundTask free size is not enough, id:%{public}s, path:%{public}s",
293 thumbnailData.id.c_str(), DfxUtils::GetSafePath(thumbnailData.path).c_str());
294 thumbnailData.loaderOpts.loadingStates = SourceLoader::LOCAL_SOURCE_LOADING_STATES;
295 IThumbnailHelper::CreateLcd(data);
296 };
297
298 MEDIA_INFO_LOG("No lcd data size: %{public}d", static_cast<int>(infos.size()));
299 for (uint32_t i = 0; i < infos.size(); i++) {
300 opts.row = infos[i].id;
301
302 // Check whether LCD exists or is over upload limit, if it does, just update the database
303 if (!NeedGenerateLocalLcd(infos[i])) {
304 MEDIA_INFO_LOG("Skip CreateLcdBackground, lcd exists: %{public}s",
305 DfxUtils::GetSafePath(infos[i].path).c_str());
306 ThumbnailUtils::UpdateLcdReadyStatus(opts, infos[i], err, LcdReady::GENERATE_LCD_COMPLETED);
307 continue;
308 }
309 IThumbnailHelper::AddThumbnailGenerateTask(createLcdBackgroundTask,
310 opts, infos[i], ThumbnailTaskType::BACKGROUND, ThumbnailTaskPriority::LOW);
311 }
312 return E_OK;
313 }
314
CheckLcdSizeAndUpdateStatus(ThumbRdbOpt & opts)315 int32_t ThumbnailGenerateHelper::CheckLcdSizeAndUpdateStatus(ThumbRdbOpt &opts)
316 {
317 if (opts.store == nullptr) {
318 return E_ERR;
319 }
320
321 vector<ThumbnailData> infos;
322 int32_t err = GetLocalNoLcdData(opts, infos);
323 if (err != E_OK) {
324 MEDIA_ERR_LOG("Failed to CheckLcdSizeAndUpdateStatus %{public}d", err);
325 return err;
326 }
327 if (infos.empty()) {
328 MEDIA_INFO_LOG("No need CheckLcdSizeAndUpdateStatus.");
329 return E_THUMBNAIL_LCD_ALL_EXIST;
330 }
331
332 MEDIA_INFO_LOG("CheckLcdSizeAndUpdateStatus size: %{public}d", static_cast<int>(infos.size()));
333 for (uint32_t i = 0; i < infos.size(); i++) {
334 opts.row = infos[i].id;
335
336 // Check whether LCD exists or is over upload limit, if it does, just update the database
337 if (!NeedGenerateLocalLcd(infos[i])) {
338 MEDIA_INFO_LOG("Check lcd size succeeded, lcd exists: %{public}s",
339 DfxUtils::GetSafePath(infos[i].path).c_str());
340 ThumbnailUtils::UpdateLcdReadyStatus(opts, infos[i], err, LcdReady::GENERATE_LCD_COMPLETED);
341 }
342 }
343 return E_OK;
344 }
345
GetLcdCount(ThumbRdbOpt & opts,int & outLcdCount)346 int32_t ThumbnailGenerateHelper::GetLcdCount(ThumbRdbOpt &opts, int &outLcdCount)
347 {
348 int32_t err = E_ERR;
349 if (!ThumbnailUtils::QueryLcdCount(opts, outLcdCount, err)) {
350 MEDIA_ERR_LOG("Failed to QueryLcdCount %{private}d", err);
351 return err;
352 }
353 return E_OK;
354 }
355
GetNoLcdData(ThumbRdbOpt & opts,vector<ThumbnailData> & outDatas)356 int32_t ThumbnailGenerateHelper::GetNoLcdData(ThumbRdbOpt &opts, vector<ThumbnailData> &outDatas)
357 {
358 int32_t err = E_ERR;
359 if (!ThumbnailUtils::QueryNoLcdInfos(opts, outDatas, err)) {
360 MEDIA_ERR_LOG("Failed to QueryNoLcdInfos %{private}d", err);
361 return err;
362 }
363 return E_OK;
364 }
365
GetLocalNoLcdData(ThumbRdbOpt & opts,vector<ThumbnailData> & outDatas)366 int32_t ThumbnailGenerateHelper::GetLocalNoLcdData(ThumbRdbOpt &opts, vector<ThumbnailData> &outDatas)
367 {
368 int32_t err = E_ERR;
369 if (!ThumbnailUtils::QueryLocalNoLcdInfos(opts, outDatas, err)) {
370 MEDIA_ERR_LOG("Failed to QueryLocalNoLcdInfos %{private}d", err);
371 return err;
372 }
373 return E_OK;
374 }
375
GetNoThumbnailData(ThumbRdbOpt & opts,vector<ThumbnailData> & outDatas)376 int32_t ThumbnailGenerateHelper::GetNoThumbnailData(ThumbRdbOpt &opts, vector<ThumbnailData> &outDatas)
377 {
378 int32_t err = E_ERR;
379 if (!ThumbnailUtils::QueryNoThumbnailInfos(opts, outDatas, err)) {
380 MEDIA_ERR_LOG("Failed to QueryNoThumbnailInfos %{private}d", err);
381 return err;
382 }
383 return E_OK;
384 }
385
GetNoAstcData(ThumbRdbOpt & opts,vector<ThumbnailData> & outDatas)386 int32_t ThumbnailGenerateHelper::GetNoAstcData(ThumbRdbOpt &opts, vector<ThumbnailData> &outDatas)
387 {
388 int32_t err = E_ERR;
389 if (!ThumbnailUtils::QueryNoAstcInfos(opts, outDatas, err)) {
390 MEDIA_ERR_LOG("Failed to QueryNoAstcInfos %{public}d", err);
391 return err;
392 }
393 return E_OK;
394 }
395
GetNewThumbnailCount(ThumbRdbOpt & opts,const int64_t & time,int & count)396 int32_t ThumbnailGenerateHelper::GetNewThumbnailCount(ThumbRdbOpt &opts, const int64_t &time, int &count)
397 {
398 int32_t err = E_ERR;
399 if (!ThumbnailUtils::QueryNewThumbnailCount(opts, time, count, err)) {
400 MEDIA_ERR_LOG("Failed to QueryNoThumbnailInfos %{private}d", err);
401 return err;
402 }
403 return E_OK;
404 }
405
GenerateLocalThumbnail(ThumbRdbOpt & opts,ThumbnailData & data,ThumbnailType thumbType)406 bool GenerateLocalThumbnail(ThumbRdbOpt &opts, ThumbnailData &data, ThumbnailType thumbType)
407 {
408 data.loaderOpts.loadingStates = SourceLoader::LOCAL_SOURCE_LOADING_STATES;
409 WaitStatus status;
410 if (thumbType == ThumbnailType::LCD && !IThumbnailHelper::DoCreateLcd(opts, data, status)) {
411 MEDIA_ERR_LOG("Get lcd thumbnail pixelmap, doCreateLcd failed: %{public}s",
412 DfxUtils::GetSafePath(data.path).c_str());
413 return false;
414 }
415 if (thumbType != ThumbnailType::LCD) {
416 bool isSuccess = IThumbnailHelper::DoCreateThumbnail(opts, data, status);
417 if (status == WaitStatus::INSERT) {
418 IThumbnailHelper::UpdateThumbnailState(opts, data, isSuccess);
419 }
420 if (!isSuccess) {
421 MEDIA_ERR_LOG("Get default thumbnail pixelmap, doCreateThumbnail failed: %{public}s",
422 DfxUtils::GetSafePath(data.path).c_str());
423 return false;
424 }
425 }
426 return true;
427 }
428
GetAvailableFile(ThumbRdbOpt & opts,ThumbnailData & data,ThumbnailType thumbType,std::string & fileName)429 int32_t ThumbnailGenerateHelper::GetAvailableFile(ThumbRdbOpt &opts, ThumbnailData &data, ThumbnailType thumbType,
430 std::string &fileName)
431 {
432 string thumbSuffix = GetThumbSuffix(thumbType);
433 fileName = GetThumbnailPath(data.path, thumbSuffix);
434 if (thumbType == ThumbnailType::THUMB_ASTC) {
435 // Try to get jpeg thumbnail instead if there is no astc file
436 if (access(fileName.c_str(), F_OK) == 0) {
437 return E_OK;
438 } else {
439 fileName = GetThumbnailPath(data.path, GetThumbSuffix(ThumbnailType::THUMB));
440 }
441 }
442
443 // No need to create thumbnails if corresponding file exists
444 if (access(fileName.c_str(), F_OK) == 0) {
445 MEDIA_INFO_LOG("File exists, path: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
446 return E_OK;
447 }
448
449 // Check if unrotated file exists
450 string fileParentPath = MediaFileUtils::GetParentPath(fileName);
451 string tempFileName = fileParentPath + "/THM_EX" + fileName.substr(fileParentPath.length());
452 if (access(tempFileName.c_str(), F_OK) == 0) {
453 fileName = tempFileName;
454 data.isOpeningCloudFile = true;
455 MEDIA_INFO_LOG("Unrotated file exists, path: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
456 return E_OK;
457 }
458
459 MEDIA_INFO_LOG("No available file, create thumbnail, path: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
460 if (!GenerateLocalThumbnail(opts, data, thumbType)) {
461 MEDIA_ERR_LOG("GenerateLocalThumbnail failed, path: %{public}s", DfxUtils::GetSafePath(tempFileName).c_str());
462 return E_THUMBNAIL_LOCAL_CREATE_FAIL;
463 }
464 if (!opts.path.empty()) {
465 fileName = GetThumbnailPath(data.path, thumbSuffix);
466 }
467 return E_OK;
468 }
469
IsLocalThumbnailAvailable(ThumbnailData & data,ThumbnailType thumbType)470 bool IsLocalThumbnailAvailable(ThumbnailData &data, ThumbnailType thumbType)
471 {
472 string tmpPath = "";
473 switch (thumbType) {
474 case ThumbnailType::THUMB:
475 case ThumbnailType::THUMB_ASTC:
476 tmpPath = GetLocalThumbnailPath(data.path, THUMBNAIL_THUMB_SUFFIX);
477 break;
478 case ThumbnailType::LCD:
479 tmpPath = GetLocalThumbnailPath(data.path, THUMBNAIL_LCD_SUFFIX);
480 break;
481 default:
482 break;
483 }
484 return access(tmpPath.c_str(), F_OK) == 0;
485 }
486
UpdateStreamReadThumbDbStatus(ThumbRdbOpt & opts,ThumbnailData & data,ThumbnailType thumbType)487 void UpdateStreamReadThumbDbStatus(ThumbRdbOpt& opts, ThumbnailData& data, ThumbnailType thumbType)
488 {
489 ValuesBucket values;
490 Size tmpSize;
491 if (!ThumbnailUtils::GetLocalThumbSize(data, thumbType, tmpSize)) {
492 return;
493 }
494 switch (thumbType) {
495 case ThumbnailType::LCD:
496 ThumbnailUtils::SetThumbnailSizeValue(values, tmpSize, PhotoColumn::PHOTO_LCD_SIZE);
497 values.PutLong(PhotoColumn::PHOTO_LCD_VISIT_TIME, static_cast<int64_t>(LcdReady::GENERATE_LCD_COMPLETED));
498 break;
499 case ThumbnailType::THUMB:
500 case ThumbnailType::THUMB_ASTC:
501 ThumbnailUtils::SetThumbnailSizeValue(values, tmpSize, PhotoColumn::PHOTO_THUMB_SIZE);
502 break;
503 default:
504 break;
505 }
506 int changedRows = 0;
507 int32_t err = opts.store->Update(changedRows, opts.table, values, MEDIA_DATA_DB_ID + " = ?",
508 vector<string> { data.id });
509 if (err != NativeRdb::E_OK) {
510 MEDIA_ERR_LOG("UpdateStreamReadThumbDbStatus failed! %{public}d", err);
511 }
512 }
513
UpdateThumbStatus(ThumbRdbOpt & opts,ThumbnailType thumbType,ThumbnailData & thumbnailData,int & err,bool & isLocalThumbnailAvailable)514 void UpdateThumbStatus(ThumbRdbOpt &opts, ThumbnailType thumbType, ThumbnailData& thumbnailData, int& err,
515 bool& isLocalThumbnailAvailable)
516 {
517 if (!isLocalThumbnailAvailable) {
518 UpdateStreamReadThumbDbStatus(opts, thumbnailData, thumbType);
519 }
520 if (thumbType == ThumbnailType::LCD && opts.table == PhotoColumn::PHOTOS_TABLE) {
521 ThumbnailUtils::UpdateVisitTime(opts, thumbnailData, err);
522 }
523 }
524
GetThumbnailPixelMap(ThumbRdbOpt & opts,ThumbnailType thumbType)525 int32_t ThumbnailGenerateHelper::GetThumbnailPixelMap(ThumbRdbOpt &opts, ThumbnailType thumbType)
526 {
527 ThumbnailWait thumbnailWait(false);
528 thumbnailWait.CheckAndWait(opts.row, thumbType == ThumbnailType::LCD);
529 ThumbnailData thumbnailData;
530 ThumbnailUtils::GetThumbnailInfo(opts, thumbnailData);
531
532 int err;
533 ThumbnailUtils::QueryThumbnailDataFromFileId(opts, thumbnailData.id, thumbnailData, err);
534
535 string fileName;
536 err = GetAvailableFile(opts, thumbnailData, thumbType, fileName);
537 if (err != E_OK) {
538 MEDIA_ERR_LOG("GetAvailableFile failed, path: %{public}s", DfxUtils::GetSafePath(thumbnailData.path).c_str());
539 return err;
540 }
541 bool isLocalThumbnailAvailable = IsLocalThumbnailAvailable(thumbnailData, thumbType);
542 DfxTimer dfxTimer(thumbType == ThumbnailType::LCD ? DfxType::CLOUD_LCD_OPEN : DfxType::CLOUD_DEFAULT_OPEN,
543 INVALID_DFX, thumbType == ThumbnailType::LCD ? CLOUD_LCD_TIME_OUT : CLOUD_DEFAULT_TIME_OUT, false);
544
545 string absFilePath;
546 if (!PathToRealPath(fileName, absFilePath)) {
547 MEDIA_ERR_LOG("file is not real path, file path: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
548 return E_ERR;
549 }
550
551 auto fd = open(absFilePath.c_str(), O_RDONLY);
552 dfxTimer.End();
553 if (fd < 0) {
554 DfxManager::GetInstance()->HandleThumbnailError(absFilePath,
555 thumbType == ThumbnailType::LCD ? DfxType::CLOUD_LCD_OPEN : DfxType::CLOUD_DEFAULT_OPEN, -errno);
556 return -errno;
557 }
558 if (thumbnailData.isOpeningCloudFile && thumbnailData.orientation != 0) {
559 if (thumbnailData.mediaType == MEDIA_TYPE_VIDEO) {
560 MEDIA_INFO_LOG("No need to rotate video file, path: %{public}s",
561 DfxUtils::GetSafePath(thumbnailData.path).c_str());
562 thumbnailData.orientation = 0;
563 }
564 IThumbnailHelper::DoRotateThumbnailEx(opts, thumbnailData, fd, thumbType);
565 fileName = GetThumbnailPath(thumbnailData.path,
566 thumbType == ThumbnailType::LCD ? THUMBNAIL_LCD_SUFFIX : THUMBNAIL_THUMB_SUFFIX);
567 if (!PathToRealPath(fileName, absFilePath)) {
568 MEDIA_ERR_LOG("file is not real path, file path: %{public}s", DfxUtils::GetSafePath(fileName).c_str());
569 return E_ERR;
570 }
571
572 fd = open(absFilePath.c_str(), O_RDONLY);
573 if (fd < 0) {
574 MEDIA_ERR_LOG("Rotate thumb failed, path: %{public}s", DfxUtils::GetSafePath(thumbnailData.path).c_str());
575 DfxManager::GetInstance()->HandleThumbnailError(absFilePath,
576 thumbType == ThumbnailType::LCD ? DfxType::CLOUD_LCD_OPEN : DfxType::CLOUD_DEFAULT_OPEN, -errno);
577 return -errno;
578 }
579 }
580 UpdateThumbStatus(opts, thumbType, thumbnailData, err, isLocalThumbnailAvailable);
581 return fd;
582 }
583
UpgradeThumbnailBackground(ThumbRdbOpt & opts,bool isWifiConnected)584 int32_t ThumbnailGenerateHelper::UpgradeThumbnailBackground(ThumbRdbOpt &opts, bool isWifiConnected)
585 {
586 if (opts.store == nullptr) {
587 MEDIA_ERR_LOG("rdbStore is not init");
588 return E_ERR;
589 }
590 CHECK_AND_RETURN_RET_LOG(ThumbnailUtils::CheckRemainSpaceMeetCondition(THUMBNAIL_FREE_SIZE_LIMIT_10),
591 E_FREE_SIZE_NOT_ENOUGH, "Free size is not enough");
592
593 vector<ThumbnailData> infos;
594 int32_t err = GetThumbnailDataNeedUpgrade(opts, infos, isWifiConnected);
595 if (err != E_OK) {
596 MEDIA_ERR_LOG("Failed to GetThumbnailDataNeedUpgrade %{public}d", err);
597 return err;
598 }
599 if (infos.empty()) {
600 MEDIA_DEBUG_LOG("No need upgrade thumbnail.");
601 return E_OK;
602 }
603 MEDIA_INFO_LOG("Will upgrade %{public}zu photo thumbnails, wifi: %{public}d.", infos.size(), isWifiConnected);
604 for (uint32_t i = 0; i < infos.size(); i++) {
605 opts.row = infos[i].id;
606 ThumbnailUtils::RecordStartGenerateStats(infos[i].stats, GenerateScene::UPGRADE, LoadSourceType::LOCAL_PHOTO);
607 infos[i].loaderOpts.loadingStates = (infos[i].mediaType == MEDIA_TYPE_VIDEO) ?
608 SourceLoader::UPGRADE_VIDEO_SOURCE_LOADING_STATES : SourceLoader::UPGRADE_SOURCE_LOADING_STATES;
609 IThumbnailHelper::AddThumbnailGenerateTask(IThumbnailHelper::CreateLcdAndThumbnail,
610 opts, infos[i], ThumbnailTaskType::BACKGROUND, ThumbnailTaskPriority::LOW);
611 }
612 return E_OK;
613 }
614
RestoreAstcDualFrame(ThumbRdbOpt & opts)615 int32_t ThumbnailGenerateHelper::RestoreAstcDualFrame(ThumbRdbOpt &opts)
616 {
617 if (opts.store == nullptr) {
618 MEDIA_ERR_LOG("rdbStore is not init");
619 return E_ERR;
620 }
621
622 vector<ThumbnailData> infos;
623 int32_t err = 0;
624 if (!ThumbnailUtils::QueryNoAstcInfosRestored(opts, infos, err)) {
625 MEDIA_ERR_LOG("Failed to QueryNoAstcInfosRestored %{public}d", err);
626 return err;
627 }
628 if (infos.empty()) {
629 MEDIA_INFO_LOG("No photos need resotre astc.");
630 return E_OK;
631 }
632
633 MEDIA_INFO_LOG("create astc for restored dual frame photos count:%{public}zu", infos.size());
634
635 for (auto &info : infos) {
636 opts.row = info.id;
637 if (!info.isLocalFile) {
638 MEDIA_INFO_LOG("skip restoring cloud photo astc path:%{public}s", DfxUtils::GetSafePath(info.path).c_str());
639 continue;
640 }
641 info.loaderOpts.loadingStates = SourceLoader::LOCAL_SOURCE_LOADING_STATES;
642 ThumbnailUtils::RecordStartGenerateStats(info.stats, GenerateScene::RESTORE, LoadSourceType::LOCAL_PHOTO);
643 IThumbnailHelper::AddThumbnailGenerateTask(IThumbnailHelper::CreateThumbnail, opts, info,
644 ThumbnailTaskType::FOREGROUND, ThumbnailTaskPriority::MID);
645 }
646
647 MEDIA_INFO_LOG("create astc for restored dual frame photos finished");
648 return E_OK;
649 }
650
GetThumbnailDataNeedUpgrade(ThumbRdbOpt & opts,std::vector<ThumbnailData> & outDatas,bool isWifiConnected)651 int32_t ThumbnailGenerateHelper::GetThumbnailDataNeedUpgrade(ThumbRdbOpt &opts, std::vector<ThumbnailData> &outDatas,
652 bool isWifiConnected)
653 {
654 int32_t err = E_ERR;
655 if (!ThumbnailUtils::QueryUpgradeThumbnailInfos(opts, outDatas, isWifiConnected, err)) {
656 MEDIA_ERR_LOG("Failed to QueryUpgradeThumbnailInfos %{public}d", err);
657 return err;
658 }
659 return E_OK;
660 }
661
CheckMonthAndYearKvStoreValid(ThumbRdbOpt & opts)662 void ThumbnailGenerateHelper::CheckMonthAndYearKvStoreValid(ThumbRdbOpt &opts)
663 {
664 bool isMonthKvStoreValid = MediaLibraryKvStoreManager::GetInstance().IsKvStoreValid(KvStoreValueType::MONTH_ASTC);
665 bool isYearKvStoreValid = MediaLibraryKvStoreManager::GetInstance().IsKvStoreValid(KvStoreValueType::YEAR_ASTC);
666 if (isMonthKvStoreValid && isYearKvStoreValid) {
667 return;
668 }
669
670 if (opts.store == nullptr) {
671 MEDIA_ERR_LOG("rdbStore is not init");
672 return;
673 }
674
675 MEDIA_INFO_LOG("KvStore is invalid, start update rdb");
676 if (opts.store->ExecuteSql(SQL_REFRESH_THUMBNAIL_READY) != NativeRdb::E_OK) {
677 MEDIA_ERR_LOG("Update rdb failed");
678 return;
679 }
680 MEDIA_INFO_LOG("Update rdb successfully");
681
682 if (!isMonthKvStoreValid) {
683 MediaLibraryKvStoreManager::GetInstance().RebuildInvalidKvStore(KvStoreValueType::MONTH_ASTC);
684 }
685
686 if (!isYearKvStoreValid) {
687 MediaLibraryKvStoreManager::GetInstance().RebuildInvalidKvStore(KvStoreValueType::YEAR_ASTC);
688 }
689
690 Acl::AclSetDatabase();
691 MEDIA_INFO_LOG("RebuildInvalidKvStore finish, isMonthKvStoreValid: %{public}d, isYearKvStoreValid: %{public}d",
692 isMonthKvStoreValid, isYearKvStoreValid);
693 }
694 } // namespace Media
695 } // namespace OHOS
696