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 "BackgroundCloudFileProcessor"
17 
18 #include "background_cloud_file_processor.h"
19 
20 #include <sys/statvfs.h>
21 
22 #include "abs_rdb_predicates.h"
23 #include "cloud_sync_manager.h"
24 #include "common_timer_errors.h"
25 #include "media_column.h"
26 #include "media_file_utils.h"
27 #include "media_log.h"
28 #include "medialibrary_errno.h"
29 #include "medialibrary_db_const.h"
30 #include "medialibrary_rdb_utils.h"
31 #include "medialibrary_rdbstore.h"
32 #include "medialibrary_unistore_manager.h"
33 #include "metadata_extractor.h"
34 #include "mimetype_utils.h"
35 #include "rdb_store.h"
36 #include "rdb_utils.h"
37 #include "result_set_utils.h"
38 #include "userfile_manager_types.h"
39 #include "values_bucket.h"
40 
41 namespace OHOS {
42 namespace Media {
43 using namespace FileManagement::CloudSync;
44 
45 static constexpr int32_t DOWNLOAD_BATCH_SIZE = 2;
46 static constexpr int32_t UPDATE_BATCH_CLOUD_SIZE = 2;
47 static constexpr int32_t UPDATE_BATCH_LOCAL_VIDEO_SIZE = 50;
48 static constexpr int32_t UPDATE_BATCH_LOCAL_IMAGE_SIZE = 200;
49 static constexpr int32_t MAX_RETRY_COUNT = 2;
50 
51 // The task can be performed only when the ratio of available storage capacity reaches this value
52 static constexpr double PROPER_DEVICE_STORAGE_CAPACITY_RATIO = 0.55;
53 
54 int32_t BackgroundCloudFileProcessor::processInterval_ = PROCESS_INTERVAL;  // 5 minute
55 int32_t BackgroundCloudFileProcessor::downloadDuration_ = DOWNLOAD_DURATION; // 10 seconds
56 recursive_mutex BackgroundCloudFileProcessor::mutex_;
57 Utils::Timer BackgroundCloudFileProcessor::timer_("background_cloud_file_processor");
58 uint32_t BackgroundCloudFileProcessor::startTimerId_ = 0;
59 uint32_t BackgroundCloudFileProcessor::stopTimerId_ = 0;
60 std::vector<std::string> BackgroundCloudFileProcessor::curDownloadPaths_;
61 bool BackgroundCloudFileProcessor::isUpdating_ = true;
62 int32_t BackgroundCloudFileProcessor::cloudUpdateOffset_ = 0;
63 int32_t BackgroundCloudFileProcessor::localImageUpdateOffset_ = 0;
64 int32_t BackgroundCloudFileProcessor::localVideoUpdateOffset_ = 0;
65 int32_t BackgroundCloudFileProcessor::cloudRetryCount_ = 0;
66 bool BackgroundCloudFileProcessor::isDownload_ = false;
67 
DownloadCloudFiles()68 void BackgroundCloudFileProcessor::DownloadCloudFiles()
69 {
70     if (!isDownload_) {
71         MEDIA_DEBUG_LOG("download task is closed");
72         return;
73     }
74     MEDIA_DEBUG_LOG("Start downloading cloud files task");
75     if (IsStorageInsufficient()) {
76         MEDIA_WARN_LOG("Insufficient storage space, stop downloading cloud files");
77         return;
78     }
79 
80     auto resultSet = QueryCloudFiles();
81     if (resultSet == nullptr) {
82         MEDIA_ERR_LOG("Failed to query cloud files!");
83         return;
84     }
85 
86     DownloadFiles downloadFiles;
87     ParseDownloadFiles(resultSet, downloadFiles);
88     if (downloadFiles.paths.empty()) {
89         MEDIA_DEBUG_LOG("No cloud files need to be downloaded");
90         return;
91     }
92 
93     int32_t ret = AddDownloadTask(downloadFiles);
94     if (ret != E_OK) {
95         MEDIA_ERR_LOG("Failed to add download task! err: %{public}d", ret);
96     }
97 }
98 
UpdateCloudData()99 void BackgroundCloudFileProcessor::UpdateCloudData()
100 {
101     MEDIA_DEBUG_LOG("Start update cloud data task");
102     std::vector<QueryOption> queryList = {{false, true}, {false, false}, {true, true}};
103     std::shared_ptr<NativeRdb::ResultSet> resultSet;
104     int32_t count = 0;
105     UpdateData updateData;
106     for (auto option : queryList) {
107         resultSet = QueryUpdateData(option.isCloud, option.isVideo);
108         if (resultSet == nullptr || resultSet->GetRowCount(count) != NativeRdb::E_OK) {
109             MEDIA_ERR_LOG("Failed to query data, %{public}d, %{public}d", option.isCloud, option.isVideo);
110             continue;
111         }
112         if (count == 0) {
113             MEDIA_DEBUG_LOG("no need to update, %{public}d, %{public}d", option.isCloud, option.isVideo);
114             continue;
115         }
116         ParseUpdateData(resultSet, updateData, option.isCloud, option.isVideo);
117         break;
118     }
119 
120     if (updateData.abnormalData.empty()) {
121         MEDIA_DEBUG_LOG("No data need to update");
122         return;
123     }
124     int32_t ret = AddUpdateDataTask(updateData);
125     if (ret != E_OK) {
126         MEDIA_ERR_LOG("Failed to add update task! err: %{public}d", ret);
127     }
128 }
129 
ProcessCloudData()130 void BackgroundCloudFileProcessor::ProcessCloudData()
131 {
132     UpdateCloudData();
133     DownloadCloudFiles();
134 }
135 
IsStorageInsufficient()136 bool BackgroundCloudFileProcessor::IsStorageInsufficient()
137 {
138     struct statvfs diskInfo;
139     int ret = statvfs("/data", &diskInfo);
140     if (ret != 0) {
141         MEDIA_ERR_LOG("Get file system status information failed, err: %{public}d", ret);
142         return true;
143     }
144 
145     double totalSize = static_cast<double>(diskInfo.f_bsize) * static_cast<double>(diskInfo.f_blocks);
146     if (totalSize < 1e-9) {
147         MEDIA_ERR_LOG("Get file system total size failed, totalSize=%{public}f", totalSize);
148         return true;
149     }
150 
151     double freeSize = static_cast<double>(diskInfo.f_bsize) * static_cast<double>(diskInfo.f_bfree);
152     double freeRatio = freeSize / totalSize;
153 
154     return freeRatio < PROPER_DEVICE_STORAGE_CAPACITY_RATIO;
155 }
156 
QueryCloudFiles()157 std::shared_ptr<NativeRdb::ResultSet> BackgroundCloudFileProcessor::QueryCloudFiles()
158 {
159     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
160     if (uniStore == nullptr) {
161         MEDIA_ERR_LOG("uniStore is nullptr!");
162         return nullptr;
163     }
164 
165     const string sql = "SELECT " + PhotoColumn::MEDIA_FILE_PATH + ", " + PhotoColumn::MEDIA_TYPE +
166         " FROM(SELECT COUNT(*) AS count, " + PhotoColumn::MEDIA_FILE_PATH + ", " + PhotoColumn::MEDIA_TYPE + ", " +
167         MediaColumn::MEDIA_DATE_MODIFIED + " FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " +
168         PhotoColumn::PHOTO_CLEAN_FLAG + " = " + std::to_string(static_cast<int32_t>(CleanType::TYPE_NOT_CLEAN)) +
169         " AND " + PhotoColumn::PHOTO_POSITION + " = " + std::to_string(POSITION_CLOUD) + " AND " +
170         PhotoColumn::MEDIA_FILE_PATH + " IS NOT NULL AND " + PhotoColumn::MEDIA_FILE_PATH + " != '' AND " +
171         MediaColumn::MEDIA_SIZE + " > 0 AND(" + PhotoColumn::MEDIA_TYPE + " = " + std::to_string(MEDIA_TYPE_IMAGE) +
172         " OR " + PhotoColumn::MEDIA_TYPE + " = " + std::to_string(MEDIA_TYPE_VIDEO) + ") GROUP BY " +
173         PhotoColumn::MEDIA_FILE_PATH + " HAVING count = 1) ORDER BY " + PhotoColumn::MEDIA_TYPE + " DESC, " +
174         MediaColumn::MEDIA_DATE_MODIFIED + " DESC LIMIT " + std::to_string(DOWNLOAD_BATCH_SIZE);
175 
176     return uniStore->QuerySql(sql);
177 }
178 
ParseDownloadFiles(std::shared_ptr<NativeRdb::ResultSet> & resultSet,DownloadFiles & downloadFiles)179 void BackgroundCloudFileProcessor::ParseDownloadFiles(std::shared_ptr<NativeRdb::ResultSet> &resultSet,
180     DownloadFiles &downloadFiles)
181 {
182     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
183         std::string path =
184             get<std::string>(ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_FILE_PATH, resultSet, TYPE_STRING));
185         if (path.empty()) {
186             MEDIA_WARN_LOG("Failed to get cloud file uri!");
187             continue;
188         }
189         int32_t mediaType =
190             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_TYPE, resultSet, TYPE_INT32));
191         if (mediaType == static_cast<int32_t>(MEDIA_TYPE_VIDEO)) {
192             downloadFiles.paths.clear();
193             downloadFiles.paths.push_back(path);
194             downloadFiles.mediaType = MEDIA_TYPE_VIDEO;
195             return;
196         }
197         downloadFiles.paths.push_back(path);
198     }
199     downloadFiles.mediaType = MEDIA_TYPE_IMAGE;
200 }
201 
AddDownloadTask(const DownloadFiles & downloadFiles)202 int32_t BackgroundCloudFileProcessor::AddDownloadTask(const DownloadFiles &downloadFiles)
203 {
204     auto asyncWorker = MediaLibraryAsyncWorker::GetInstance();
205     if (asyncWorker == nullptr) {
206         MEDIA_ERR_LOG("Failed to get async worker instance!");
207         return E_FAIL;
208     }
209 
210     auto *taskData = new (std::nothrow) DownloadCloudFilesData(downloadFiles);
211     if (taskData == nullptr) {
212         MEDIA_ERR_LOG("Failed to alloc async data for downloading cloud files!");
213         return E_NO_MEMORY;
214     }
215 
216     auto asyncTask = std::make_shared<MediaLibraryAsyncTask>(DownloadCloudFilesExecutor, taskData);
217     asyncWorker->AddTask(asyncTask, false);
218     return E_OK;
219 }
220 
DownloadCloudFilesExecutor(AsyncTaskData * data)221 void BackgroundCloudFileProcessor::DownloadCloudFilesExecutor(AsyncTaskData *data)
222 {
223     auto *taskData = static_cast<DownloadCloudFilesData *>(data);
224     auto downloadFiles = taskData->downloadFiles_;
225 
226     MEDIA_DEBUG_LOG("Try to download %{public}zu cloud files.", downloadFiles.paths.size());
227     for (const auto &path : downloadFiles.paths) {
228         int32_t ret = CloudSyncManager::GetInstance().StartDownloadFile(path);
229         if (ret != E_OK) {
230             MEDIA_ERR_LOG("Failed to download cloud file, err: %{public}d, path: %{public}s", ret, path.c_str());
231         }
232     }
233 
234     lock_guard<recursive_mutex> lock(mutex_);
235     curDownloadPaths_ = downloadFiles.paths;
236     if (downloadFiles.mediaType == MEDIA_TYPE_VIDEO) {
237         if (stopTimerId_ > 0) {
238             timer_.Unregister(stopTimerId_);
239         }
240         stopTimerId_ = timer_.Register(StopDownloadFiles, downloadDuration_, true);
241     }
242 }
243 
StopDownloadFiles()244 void BackgroundCloudFileProcessor::StopDownloadFiles()
245 {
246     for (const auto &path : curDownloadPaths_) {
247         MEDIA_INFO_LOG("Try to Stop downloading cloud file, the path is %{public}s", path.c_str());
248         int32_t ret = CloudSyncManager::GetInstance().StopDownloadFile(path);
249         if (ret != E_OK) {
250             MEDIA_ERR_LOG("Stop downloading cloud file failed, err: %{public}d, path: %{public}s", ret, path.c_str());
251         }
252     }
253     curDownloadPaths_.clear();
254 }
255 
SetPredicates(NativeRdb::RdbPredicates & predicates,bool isCloud,bool isVideo)256 void BackgroundCloudFileProcessor::SetPredicates(NativeRdb::RdbPredicates &predicates, bool isCloud, bool isVideo)
257 {
258     if (isCloud) {
259         predicates.EqualTo(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::CLOUD))
260             ->OrderByAsc(MediaColumn::MEDIA_ID)
261             ->Limit(cloudUpdateOffset_, UPDATE_BATCH_CLOUD_SIZE);
262     } else {
263         if (isVideo) {
264             predicates.NotEqualTo(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::CLOUD))->And()
265                 ->BeginWrap()
266                 ->EqualTo(MediaColumn::MEDIA_TYPE, static_cast<int32_t>(MEDIA_TYPE_VIDEO))->And()
267                 ->BeginWrap()
268                 ->EqualTo(MediaColumn::MEDIA_DURATION, 0)->Or()
269                 ->IsNull(MediaColumn::MEDIA_DURATION)
270                 ->EndWrap()
271                 ->EndWrap()
272                 ->OrderByAsc(MediaColumn::MEDIA_ID)
273                 ->Limit(localVideoUpdateOffset_, UPDATE_BATCH_LOCAL_VIDEO_SIZE);
274         } else {
275             predicates.NotEqualTo(PhotoColumn::PHOTO_POSITION, static_cast<int32_t>(PhotoPositionType::CLOUD))->And()
276                 ->NotEqualTo(MediaColumn::MEDIA_TYPE, static_cast<int32_t>(MEDIA_TYPE_VIDEO))
277                 ->OrderByAsc(MediaColumn::MEDIA_ID)
278                 ->Limit(localImageUpdateOffset_, UPDATE_BATCH_LOCAL_IMAGE_SIZE);
279         }
280     }
281 }
282 
QueryUpdateData(bool isCloud,bool isVideo)283 std::shared_ptr<NativeRdb::ResultSet> BackgroundCloudFileProcessor::QueryUpdateData(bool isCloud, bool isVideo)
284 {
285     const std::vector<std::string> columns = { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_FILE_PATH,
286         MediaColumn::MEDIA_TYPE, MediaColumn::MEDIA_SIZE,
287         PhotoColumn::PHOTO_WIDTH, PhotoColumn::PHOTO_HEIGHT,
288         MediaColumn::MEDIA_MIME_TYPE, MediaColumn::MEDIA_DURATION };
289 
290     NativeRdb::RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
291     predicates.BeginWrap()
292         ->EqualTo(MediaColumn::MEDIA_SIZE, 0)
293         ->Or()
294         ->IsNull(MediaColumn::MEDIA_SIZE)
295         ->Or()
296         ->EqualTo(PhotoColumn::PHOTO_WIDTH, 0)
297         ->Or()
298         ->IsNull(PhotoColumn::PHOTO_WIDTH)
299         ->Or()
300         ->EqualTo(PhotoColumn::PHOTO_HEIGHT, 0)
301         ->Or()
302         ->IsNull(PhotoColumn::PHOTO_HEIGHT)
303         ->Or()
304         ->EqualTo(MediaColumn::MEDIA_MIME_TYPE, "")
305         ->Or()
306         ->IsNull(MediaColumn::MEDIA_MIME_TYPE)
307         ->Or()
308         ->BeginWrap()
309         ->EqualTo(MediaColumn::MEDIA_TYPE, static_cast<int32_t>(MEDIA_TYPE_VIDEO))
310         ->And()
311         ->BeginWrap()
312         ->EqualTo(MediaColumn::MEDIA_DURATION, 0)
313         ->Or()
314         ->IsNull(MediaColumn::MEDIA_DURATION)
315         ->EndWrap()
316         ->EndWrap()
317         ->EndWrap()
318         ->And()
319         ->EqualTo(MediaColumn::MEDIA_TIME_PENDING, 0)
320         ->And()
321         ->EqualTo(PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE))
322         ->And()
323         ->EqualTo(PhotoColumn::PHOTO_CLEAN_FLAG, static_cast<int32_t>(CleanType::TYPE_NOT_CLEAN))
324         ->And();
325     SetPredicates(predicates, isCloud, isVideo);
326     return MediaLibraryRdbStore::Query(predicates, columns);
327 }
328 
ParseUpdateData(std::shared_ptr<NativeRdb::ResultSet> & resultSet,UpdateData & updateData,bool isCloud,bool isVideo)329 void BackgroundCloudFileProcessor::ParseUpdateData(std::shared_ptr<NativeRdb::ResultSet> &resultSet,
330     UpdateData &updateData, bool isCloud, bool isVideo)
331 {
332     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
333         int32_t fileId =
334             get<int32_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_ID, resultSet, TYPE_INT32));
335         int64_t size =
336             get<int64_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_SIZE, resultSet, TYPE_INT64));
337         int32_t width =
338             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_WIDTH, resultSet, TYPE_INT32));
339         int32_t height =
340             get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_HEIGHT, resultSet, TYPE_INT32));
341         int32_t duration =
342             get<int32_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_DURATION, resultSet, TYPE_INT32));
343         std::string path =
344             get<std::string>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_FILE_PATH, resultSet, TYPE_STRING));
345         if (path.empty()) {
346             MEDIA_WARN_LOG("Failed to get data path");
347             continue;
348         }
349         std::string mimeType =
350             get<std::string>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_MIME_TYPE, resultSet, TYPE_STRING));
351         int32_t mediaType =
352             get<int32_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_TYPE, resultSet, TYPE_INT32));
353 
354         AbnormalData abnormalData;
355         abnormalData.fileId = fileId;
356         abnormalData.path = path;
357         abnormalData.size = size;
358         abnormalData.width = width;
359         abnormalData.height = height;
360         abnormalData.duration = duration;
361         abnormalData.mimeType = mimeType;
362         abnormalData.isCloud = isCloud;
363         abnormalData.isVideo = isVideo;
364 
365         if (isCloud && mediaType == static_cast<int32_t>(MEDIA_TYPE_VIDEO)) {
366             updateData.abnormalData.clear();
367             abnormalData.mediaType = MEDIA_TYPE_VIDEO;
368             updateData.abnormalData.push_back(abnormalData);
369             return;
370         }
371         abnormalData.mediaType = static_cast<MediaType>(mediaType);
372         updateData.abnormalData.push_back(abnormalData);
373     }
374 }
375 
AddUpdateDataTask(const UpdateData & updateData)376 int32_t BackgroundCloudFileProcessor::AddUpdateDataTask(const UpdateData &updateData)
377 {
378     auto asyncWorker = MediaLibraryAsyncWorker::GetInstance();
379     if (asyncWorker == nullptr) {
380         MEDIA_ERR_LOG("Failed to get async worker instance!");
381         return E_FAIL;
382     }
383 
384     auto *taskData = new (std::nothrow) UpdateAbnormalData(updateData);
385     if (taskData == nullptr) {
386         MEDIA_ERR_LOG("Failed to alloc async data for update cloud data!");
387         return E_NO_MEMORY;
388     }
389 
390     auto asyncTask = std::make_shared<MediaLibraryAsyncTask>(UpdateCloudDataExecutor, taskData);
391     asyncWorker->AddTask(asyncTask, false);
392     return E_OK;
393 }
394 
UpdateCurrentOffset(bool isCloud,bool isVideo)395 void BackgroundCloudFileProcessor::UpdateCurrentOffset(bool isCloud, bool isVideo)
396 {
397     if (isCloud) {
398         if (cloudRetryCount_ >= MAX_RETRY_COUNT) {
399             cloudUpdateOffset_ += 1;
400             cloudRetryCount_ = 0;
401         } else {
402             cloudRetryCount_ += 1;
403         }
404         MEDIA_INFO_LOG("cloudUpdateOffset_ is %{public}d, cloudRetryCount_ is %{public}d",
405             cloudUpdateOffset_, cloudRetryCount_);
406         return;
407     }
408     if (isVideo) {
409         localVideoUpdateOffset_++;
410         MEDIA_INFO_LOG("localVideoUpdateOffset_ is %{public}d", localVideoUpdateOffset_);
411     } else {
412         localImageUpdateOffset_++;
413         MEDIA_INFO_LOG("localImageUpdateOffset_ is %{public}d", localImageUpdateOffset_);
414     }
415 }
416 
UpdateCloudDataExecutor(AsyncTaskData * data)417 void BackgroundCloudFileProcessor::UpdateCloudDataExecutor(AsyncTaskData *data)
418 {
419     auto *taskData = static_cast<UpdateAbnormalData *>(data);
420     auto updateData = taskData->updateData_;
421 
422     MEDIA_INFO_LOG("start update %{public}zu cloud files.", updateData.abnormalData.size());
423     for (const auto &abnormalData : updateData.abnormalData) {
424         if (!isUpdating_) {
425             MEDIA_INFO_LOG("stop update data, isUpdating_ is %{public}d.", isUpdating_);
426             return;
427         }
428         std::unique_ptr<Metadata> metadata = make_unique<Metadata>();
429         metadata->SetFilePath(abnormalData.path);
430         metadata->SetFileMediaType(abnormalData.mediaType);
431         metadata->SetFileId(abnormalData.fileId);
432         metadata->SetFileDuration(abnormalData.duration);
433         metadata->SetFileHeight(abnormalData.height);
434         metadata->SetFileWidth(abnormalData.width);
435         metadata->SetFileSize(abnormalData.size);
436         metadata->SetFileMimeType(abnormalData.mimeType);
437         GetSizeAndMimeType(metadata);
438         if (abnormalData.size == 0 || abnormalData.mimeType.empty()) {
439             int64_t fileSize = metadata->GetFileSize();
440             string mimeType =  metadata->GetFileMimeType();
441             metadata->SetFileSize(fileSize == 0 ? -1: fileSize);
442             metadata->SetFileMimeType(mimeType.empty() ? DEFAULT_IMAGE_MIME_TYPE : mimeType);
443         }
444         if (abnormalData.width == 0 || abnormalData.height == 0
445             || (abnormalData.duration == 0 && abnormalData.mediaType == MEDIA_TYPE_VIDEO)) {
446             int32_t ret = GetExtractMetadata(metadata);
447             if (ret != E_OK && MediaFileUtils::IsFileExists(abnormalData.path)) {
448                 UpdateCurrentOffset(abnormalData.isCloud, abnormalData.isVideo);
449                 MEDIA_ERR_LOG("failed to get extract metadata! err: %{public}d.", ret);
450                 continue;
451             }
452             int32_t width = metadata->GetFileWidth();
453             int32_t height = metadata->GetFileHeight();
454             int32_t duration = metadata->GetFileDuration();
455             metadata->SetFileWidth(width == 0 ? -1: width);
456             metadata->SetFileHeight(height == 0 ? -1: height);
457             metadata->SetFileDuration((duration == 0 && abnormalData.mediaType == MEDIA_TYPE_VIDEO) ? -1: duration);
458         }
459         UpdateAbnormaldata(metadata, PhotoColumn::PHOTOS_TABLE);
460         if (abnormalData.isCloud) {
461             cloudRetryCount_ = 0;
462         }
463     }
464 }
465 
SetAbnormalValuesFromMetaData(std::unique_ptr<Metadata> & metadata,NativeRdb::ValuesBucket & values)466 static void SetAbnormalValuesFromMetaData(std::unique_ptr<Metadata> &metadata, NativeRdb::ValuesBucket &values)
467 {
468     values.PutLong(MediaColumn::MEDIA_SIZE, metadata->GetFileSize());
469     values.PutInt(MediaColumn::MEDIA_DURATION, metadata->GetFileDuration());
470     values.PutInt(PhotoColumn::PHOTO_HEIGHT, metadata->GetFileHeight());
471     values.PutInt(PhotoColumn::PHOTO_WIDTH, metadata->GetFileWidth());
472     values.PutString(MediaColumn::MEDIA_MIME_TYPE, metadata->GetFileMimeType());
473 }
474 
UpdateAbnormaldata(std::unique_ptr<Metadata> & metadata,const std::string & tableName)475 void BackgroundCloudFileProcessor::UpdateAbnormaldata(std::unique_ptr<Metadata> &metadata, const std::string &tableName)
476 {
477     int32_t updateCount(0);
478     NativeRdb::ValuesBucket values;
479     string whereClause = MediaColumn::MEDIA_ID + " = ?";
480     vector<string> whereArgs = { to_string(metadata->GetFileId()) };
481     SetAbnormalValuesFromMetaData(metadata, values);
482     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
483     if (rdbStore == nullptr) {
484         MEDIA_ERR_LOG("Update operation failed. rdbStore is null");
485         return ;
486     }
487     if (!isUpdating_) {
488         MEDIA_INFO_LOG("stop update data,isUpdating_ is %{public}d.", isUpdating_);
489         return;
490     }
491     int32_t result = rdbStore->Update(updateCount, tableName, values, whereClause, whereArgs);
492     if (result != NativeRdb::E_OK || updateCount <= 0) {
493         MEDIA_ERR_LOG("Update operation failed. Result %{public}d. Updated %{public}d", result, updateCount);
494         return ;
495     }
496     MEDIA_INFO_LOG("id:%{public}d, duration:%{public}d, height:%{public}d, width:%{public}d, size:%{public}" PRId64,
497         metadata->GetFileId(), metadata->GetFileDuration(), metadata->GetFileHeight(), metadata->GetFileWidth(),
498         metadata->GetFileSize());
499 }
500 
GetSizeAndMimeType(std::unique_ptr<Metadata> & metadata)501 void BackgroundCloudFileProcessor::GetSizeAndMimeType(std::unique_ptr<Metadata> &metadata)
502 {
503     std::string path = metadata->GetFilePath();
504     struct stat statInfo {};
505     if (stat(path.c_str(), &statInfo) != 0) {
506         MEDIA_ERR_LOG("stat syscall err %{public}d", errno);
507         metadata->SetFileSize(static_cast<int64_t>(0));
508     } else {
509         metadata->SetFileSize(statInfo.st_size);
510     }
511     string extension = ScannerUtils::GetFileExtension(path);
512     string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
513     metadata->SetFileExtension(extension);
514     metadata->SetFileMimeType(mimeType);
515 }
516 
GetExtractMetadata(std::unique_ptr<Metadata> & metadata)517 int32_t BackgroundCloudFileProcessor::GetExtractMetadata(std::unique_ptr<Metadata> &metadata)
518 {
519     int32_t err = 0;
520     if (metadata->GetFileMediaType() == MEDIA_TYPE_IMAGE) {
521         err = MetadataExtractor::ExtractImageMetadata(metadata);
522     } else {
523         err = MetadataExtractor::ExtractAVMetadata(metadata);
524     }
525     if (err != E_OK) {
526         MEDIA_ERR_LOG("failed to extract data");
527         return err;
528     }
529     return E_OK;
530 }
531 
StopUpdateData()532 void BackgroundCloudFileProcessor::StopUpdateData()
533 {
534     isUpdating_ = false;
535 }
536 
StartTimer()537 void BackgroundCloudFileProcessor::StartTimer()
538 {
539     lock_guard<recursive_mutex> lock(mutex_);
540     MEDIA_INFO_LOG("Turn on the background download cloud file timer");
541 
542     if (startTimerId_ > 0) {
543         timer_.Unregister(startTimerId_);
544     }
545     uint32_t ret = timer_.Setup();
546     if (ret != Utils::TIMER_ERR_OK) {
547         MEDIA_ERR_LOG("Failed to start background download cloud files timer, err: %{public}d", ret);
548     }
549     isUpdating_ = true;
550     startTimerId_ = timer_.Register(ProcessCloudData, processInterval_);
551 }
552 
StopTimer()553 void BackgroundCloudFileProcessor::StopTimer()
554 {
555     lock_guard<recursive_mutex> lock(mutex_);
556     MEDIA_INFO_LOG("Turn off the background download cloud file timer");
557 
558     timer_.Unregister(startTimerId_);
559     timer_.Unregister(stopTimerId_);
560     timer_.Shutdown();
561     startTimerId_ = 0;
562     stopTimerId_ = 0;
563     StopUpdateData();
564     StopDownloadFiles();
565 }
566 } // namespace Media
567 } // namespace OHOS
568