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