• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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