• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "PhotoCustomRestoreOperation"
16 
17 #include "photo_custom_restore_operation.h"
18 
19 #include <dirent.h>
20 #include <dlfcn.h>
21 #include <thread>
22 
23 #include "dfx_reporter.h"
24 #include "directory_ex.h"
25 #include "ffrt.h"
26 #include "ffrt_inner.h"
27 #include "media_column.h"
28 #include "media_file_utils.h"
29 #include "media_file_uri.h"
30 #include "media_log.h"
31 #include "media_unique_number_column.h"
32 #include "medialibrary_asset_operations.h"
33 #include "medialibrary_bundle_manager.h"
34 #include "medialibrary_notify.h"
35 #include "medialibrary_rdb_utils.h"
36 #include "medialibrary_unistore_manager.h"
37 #include "medialibrary_type_const.h"
38 #include "medialibrary_db_const.h"
39 #include "metadata_extractor.h"
40 #include "mimetype_utils.h"
41 #include "moving_photo_file_utils.h"
42 #include "photo_album_column.h"
43 #include "photo_file_utils.h"
44 #include "result_set_utils.h"
45 #include "scanner_utils.h"
46 #include "shooting_mode_column.h"
47 #include "userfile_manager_types.h"
48 #include "refresh_business_name.h"
49 
50 using namespace std;
51 namespace OHOS::Media {
52 std::shared_ptr<PhotoCustomRestoreOperation> PhotoCustomRestoreOperation::instance_ = nullptr;
53 std::mutex PhotoCustomRestoreOperation::objMutex_;
54 
GetInstance()55 PhotoCustomRestoreOperation &PhotoCustomRestoreOperation::GetInstance()
56 {
57     std::lock_guard<std::mutex> lock(PhotoCustomRestoreOperation::objMutex_);
58     if (PhotoCustomRestoreOperation::instance_ == nullptr) {
59         PhotoCustomRestoreOperation::instance_ = std::make_shared<PhotoCustomRestoreOperation>();
60     }
61     return *PhotoCustomRestoreOperation::instance_;
62 }
63 
Start()64 PhotoCustomRestoreOperation &PhotoCustomRestoreOperation::Start()
65 {
66     if (this->isRunning_.exchange(true)) {
67         MEDIA_WARN_LOG("custom restore operation is running. skip start");
68         return *this;
69     }
70     CleanTimeoutCustomRestoreTaskDir();
71     while (!this->taskQueue_.empty()) {
72         RestoreTaskInfo restoreTaskInfo = this->taskQueue_.front();
73         if (IsCancelTask(restoreTaskInfo)) {
74             CancelTaskFinish(restoreTaskInfo);
75             this->taskQueue_.pop();
76             continue;
77         }
78         DoCustomRestore(restoreTaskInfo);
79         this->taskQueue_.pop();
80     }
81     {
82         std::unique_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
83         cancelKeySet_.clear();
84     }
85     this->isRunning_.store(false);
86     return *this;
87 }
88 
CancelTask(RestoreTaskInfo restoreTaskInfo)89 void PhotoCustomRestoreOperation::CancelTask(RestoreTaskInfo restoreTaskInfo)
90 {
91     MEDIA_INFO_LOG("cancel custom restore task. keyPath: %{public}s", restoreTaskInfo.keyPath.c_str());
92     std::unique_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
93     cancelKeySet_.insert(restoreTaskInfo.keyPath);
94 }
95 
IsCancelTask(RestoreTaskInfo & restoreTaskInfo)96 bool PhotoCustomRestoreOperation::IsCancelTask(RestoreTaskInfo &restoreTaskInfo)
97 {
98     std::shared_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
99     return cancelKeySet_.count(restoreTaskInfo.keyPath) > 0;
100 }
101 
CancelTaskFinish(RestoreTaskInfo & restoreTaskInfo)102 void PhotoCustomRestoreOperation::CancelTaskFinish(RestoreTaskInfo &restoreTaskInfo)
103 {
104     UniqueNumber uniqueNumber;
105     SendNotifyMessage(restoreTaskInfo, NOTIFY_CANCEL, E_OK, 0, uniqueNumber);
106     std::unique_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
107     cancelKeySet_.erase(restoreTaskInfo.keyPath);
108 }
109 
ApplyEfficiencyQuota(int32_t fileNum)110 void PhotoCustomRestoreOperation::ApplyEfficiencyQuota(int32_t fileNum)
111 {
112 #ifdef EFFICIENCY_MANAGER_ENABLE
113     int64_t quota = fileNum * BASE_EFFICIENCY_QUOTA / BASE_FILE_NUM;
114     if (quota == 0) {
115         MEDIA_WARN_LOG("quota is zero, skip apply efficiency quota.");
116         return;
117     }
118     string module = BUNDLE_NAME;
119     string reason = "Custom Restore";
120     MEDIA_DEBUG_LOG("ApplyEfficiencyQuota. quota: %{public}" PRId64, quota);
121     void *resourceQuotaMgrHandle = dlopen(ABNORMAL_MANAGER_LIB.c_str(), RTLD_NOW);
122     CHECK_AND_RETURN_LOG(resourceQuotaMgrHandle, "Not find resource_quota_manager lib.");
123 
124     using HandleQuotaFunc = bool (*)(const std::string &, uint32_t, int64_t, const std::string &);
125     auto handleQuotaFunc =
126         reinterpret_cast<HandleQuotaFunc>(dlsym(resourceQuotaMgrHandle, "ApplyAbnormalControlQuota"));
127     if (!handleQuotaFunc) {
128         MEDIA_ERR_LOG("Not find ApplyAbnormalControlQuota func.");
129         dlclose(resourceQuotaMgrHandle);
130         return;
131     }
132     CHECK_AND_PRINT_LOG(handleQuotaFunc(module, MODULE_POWER_OVERUSED, quota, reason), "Do handleQuotaFunc failed.");
133     dlclose(resourceQuotaMgrHandle);
134 #endif
135 }
136 
AddTask(RestoreTaskInfo restoreTaskInfo)137 PhotoCustomRestoreOperation &PhotoCustomRestoreOperation::AddTask(RestoreTaskInfo restoreTaskInfo)
138 {
139     MEDIA_INFO_LOG("add custom restore task. keyPath: %{public}s", restoreTaskInfo.keyPath.c_str());
140     this->taskQueue_.push(restoreTaskInfo);
141     return *this;
142 }
143 
DoCustomRestore(RestoreTaskInfo & restoreTaskInfo)144 void PhotoCustomRestoreOperation::DoCustomRestore(RestoreTaskInfo &restoreTaskInfo)
145 {
146     ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_RESTORE_THREAD_NUM);
147     vector<string> files;
148     GetDirFiles(restoreTaskInfo.sourceDir, files);
149     InitRestoreTask(restoreTaskInfo, files.size());
150     bool isFirstRestoreSuccess = false;
151     int32_t firstRestoreIndex = 0;
152     int32_t total = static_cast<int32_t>(files.size());
153     MEDIA_INFO_LOG("DoCustomRestore files count: %{public}d", total);
154     int32_t lastIndex = total - 1;
155     for (int32_t index = 0; index < total; index++) {
156         if (IsCancelTask(restoreTaskInfo)) {
157             break;
158         }
159         if (index == 0 || !isFirstRestoreSuccess) {
160             isFirstRestoreSuccess = HandleFirstRestoreFile(restoreTaskInfo, files, index, firstRestoreIndex);
161             if (!isFirstRestoreSuccess && index == lastIndex) {
162                 break;
163             }
164             continue;
165         }
166         // Remainder and multiple of MAX_RESTORE_FILE_NUM
167         int32_t remainder = (index + 1) % MAX_RESTORE_FILE_NUM;
168         int32_t multiples = (index + 1) / MAX_RESTORE_FILE_NUM;
169         if (remainder == 0 || index == lastIndex) {
170             int32_t fileNum = remainder == 0 && multiples > 0 ? MAX_RESTORE_FILE_NUM : remainder;
171             int32_t beginOffset = index - fileNum + 1;
172             if (beginOffset <= firstRestoreIndex) {
173                 // not contain first restore file
174                 beginOffset = firstRestoreIndex + 1;
175                 fileNum = index - beginOffset + 1;
176             }
177             int32_t notifyType = index == lastIndex ? NOTIFY_LAST : NOTIFY_PROGRESS;
178             vector<string> subFiles(files.begin() + beginOffset, files.begin() + index + 1);
179             ffrt::submit(
180                 [this, &restoreTaskInfo, notifyType, subFiles]() {
181                     HandleBatchCustomRestore(restoreTaskInfo, notifyType, subFiles);
182                 },
183                 {},
184                 {},
185                 ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
186         }
187     }
188     ffrt::wait();
189     ReleaseCustomRestoreTask(restoreTaskInfo);
190 }
191 
ReleaseCustomRestoreTask(RestoreTaskInfo & restoreTaskInfo)192 void PhotoCustomRestoreOperation::PhotoCustomRestoreOperation::ReleaseCustomRestoreTask(
193     RestoreTaskInfo &restoreTaskInfo)
194 {
195     photoCache_.clear();
196     CHECK_AND_PRINT_LOG(MediaFileUtils::DeleteDir(restoreTaskInfo.sourceDir), "delete dir failed.");
197     ReportCustomRestoreTask(restoreTaskInfo);
198     if (IsCancelTask(restoreTaskInfo)) {
199         CancelTaskFinish(restoreTaskInfo);
200     }
201 }
202 
ReportCustomRestoreTask(RestoreTaskInfo & restoreTaskInfo)203 void PhotoCustomRestoreOperation::ReportCustomRestoreTask(RestoreTaskInfo &restoreTaskInfo)
204 {
205     restoreTaskInfo.endTime = MediaFileUtils::UTCTimeSeconds();
206     CustomRestoreDfxDataPoint point;
207     point.customRestorePackageName = restoreTaskInfo.packageName;
208     point.albumLPath = restoreTaskInfo.albumLpath;
209     point.keyPath = restoreTaskInfo.keyPath;
210     point.totalNum = restoreTaskInfo.totalNum;
211     point.successNum = successNum_;
212     point.failedNum = failNum_;
213     point.sameNum = sameNum_;
214     if (IsCancelTask(restoreTaskInfo)) {
215         point.cancelNum = point.totalNum - point.successNum - point.sameNum - point.failedNum;
216     } else {
217         point.cancelNum = 0;
218         point.failedNum = point.totalNum - point.successNum - point.sameNum;
219     }
220     point.totalTime = static_cast<uint64_t>(restoreTaskInfo.endTime - restoreTaskInfo.beginTime);
221     MEDIA_INFO_LOG("report custom restore finished. cost:%{public}" PRId64, point.totalTime);
222     DfxReporter::ReportCustomRestoreFusion(point);
223 }
224 
HandleFirstRestoreFile(RestoreTaskInfo & restoreTaskInfo,vector<string> & files,int32_t index,int32_t & firstRestoreIndex)225 bool PhotoCustomRestoreOperation::HandleFirstRestoreFile(
226     RestoreTaskInfo &restoreTaskInfo, vector<string> &files, int32_t index, int32_t &firstRestoreIndex)
227 {
228     vector<string> subFiles(files.begin() + index, files.begin() + index + 1);
229     UniqueNumber uniqueNumber;
230     int32_t errCode = HandleCustomRestore(restoreTaskInfo, subFiles, true, uniqueNumber);
231     bool isFirstRestoreSuccess = errCode == E_OK;
232     int32_t lastIndex = static_cast<int32_t>(files.size() - 1);
233     if (!isFirstRestoreSuccess && index == lastIndex) {
234         MEDIA_ERR_LOG("first file restore failed. stop restore task.");
235         SendNotifyMessage(restoreTaskInfo, NOTIFY_FIRST, errCode, 1, uniqueNumber);
236     }
237     if (isFirstRestoreSuccess) {
238         MEDIA_ERR_LOG("first file restore success.");
239         firstRestoreIndex = index;
240         int notifyType = index == lastIndex ? NOTIFY_LAST : NOTIFY_FIRST;
241         SendNotifyMessage(restoreTaskInfo, notifyType, errCode, 1, uniqueNumber);
242     }
243     return isFirstRestoreSuccess;
244 }
245 
HandleBatchCustomRestore(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType,vector<string> subFiles)246 void PhotoCustomRestoreOperation::HandleBatchCustomRestore(
247     RestoreTaskInfo &restoreTaskInfo, int32_t notifyType, vector<string> subFiles)
248 {
249     if (IsCancelTask(restoreTaskInfo)) {
250         return;
251     }
252     int32_t fileNum = static_cast<int32_t>(subFiles.size());
253     UniqueNumber uniqueNumber;
254     int32_t errCode = HandleCustomRestore(restoreTaskInfo, subFiles, false, uniqueNumber);
255     SendNotifyMessage(restoreTaskInfo, notifyType, errCode, fileNum, uniqueNumber);
256 }
257 
InitRestoreTask(RestoreTaskInfo & restoreTaskInfo,int32_t fileNum)258 void PhotoCustomRestoreOperation::InitRestoreTask(RestoreTaskInfo &restoreTaskInfo, int32_t fileNum)
259 {
260     successNum_.store(0);
261     failNum_.store(0);
262     sameNum_.store(0);
263     photoCache_.clear();
264     restoreTaskInfo.uriType = RESTORE_URI_TYPE_PHOTO;
265     restoreTaskInfo.totalNum = fileNum;
266     restoreTaskInfo.beginTime = MediaFileUtils::UTCTimeSeconds();
267     std::thread applyEfficiencyQuotaThread([this, fileNum] { ApplyEfficiencyQuota(fileNum); });
268     applyEfficiencyQuotaThread.detach();
269     QueryAlbumId(restoreTaskInfo);
270     GetAlbumInfoBySubType(PhotoAlbumSubType::IMAGE, restoreTaskInfo.imageAlbumUri, restoreTaskInfo.imageAlbumId);
271     GetAlbumInfoBySubType(PhotoAlbumSubType::VIDEO, restoreTaskInfo.videoAlbumUri, restoreTaskInfo.videoAlbumId);
272 }
273 
NotifyAnalysisAlbum(const vector<string> & changedAlbumIds)274 static void NotifyAnalysisAlbum(const vector<string>& changedAlbumIds)
275 {
276     if (changedAlbumIds.size() <= 0) {
277         return;
278     }
279     auto watch = MediaLibraryNotify::GetInstance();
280     CHECK_AND_RETURN_LOG(watch != nullptr, "Can not get MediaLibraryNotify Instance");
281     for (const string& albumId : changedAlbumIds) {
282         watch->Notify(MediaFileUtils::GetUriByExtrConditions(
283             PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX, albumId), NotifyType::NOTIFY_UPDATE);
284     }
285 }
286 
UpdateAndNotifyShootingModeAlbumIfNeeded(const vector<FileInfo> & fileInfos)287 static void UpdateAndNotifyShootingModeAlbumIfNeeded(const vector<FileInfo>& fileInfos)
288 {
289     set<ShootingModeAlbumType> albumTypesSet;
290     for (const auto &fileInfo : fileInfos) {
291         vector<ShootingModeAlbumType> albumTypes = ShootingModeAlbum::GetShootingModeAlbumOfAsset(
292             fileInfo.subtype, fileInfo.mimeType, fileInfo.movingPhotoEffectMode,
293             fileInfo.frontCamera, fileInfo.shootingMode);
294         albumTypesSet.insert(albumTypes.begin(), albumTypes.end());
295     }
296 
297     vector<string> albumIdsToUpdate;
298     for (const auto& type : albumTypesSet) {
299         int32_t albumId;
300         if (MediaLibraryRdbUtils::QueryShootingModeAlbumIdByType(type, albumId)) {
301             albumIdsToUpdate.push_back(to_string(albumId));
302         }
303     }
304 
305     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
306     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "rdbstore is nullptr");
307 
308     if (albumIdsToUpdate.size() > 0) {
309         MediaLibraryRdbUtils::UpdateAnalysisAlbumInternal(rdbStore, albumIdsToUpdate);
310         NotifyAnalysisAlbum(albumIdsToUpdate);
311     }
312 }
313 
HandleCustomRestore(RestoreTaskInfo & restoreTaskInfo,vector<string> filePathVector,bool isFirst,UniqueNumber & uniqueNumber)314 int32_t PhotoCustomRestoreOperation::HandleCustomRestore(
315     RestoreTaskInfo &restoreTaskInfo, vector<string> filePathVector, bool isFirst,
316     UniqueNumber &uniqueNumber)
317 {
318     MEDIA_INFO_LOG("HandleCustomRestore begin. size: %{public}d, isFirst: %{public}d",
319         static_cast<int32_t>(filePathVector.size()), isFirst ? 1 : 0);
320     vector<FileInfo> restoreFiles = GetFileInfos(filePathVector, uniqueNumber);
321     int32_t errCode = UpdateUniqueNumber(uniqueNumber);
322     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "UpdateUniqueNumber failed. errCode: %{public}d", errCode);
323 
324     vector<FileInfo> destRestoreFiles = SetDestinationPath(restoreFiles, uniqueNumber);
325     if (destRestoreFiles.size() == 0) {
326         MEDIA_ERR_LOG("restore file number is zero.");
327         return E_ERR;
328     }
329     int32_t sameFileNum = 0;
330     vector<FileInfo> insertRestoreFiles = BatchInsert(restoreTaskInfo, destRestoreFiles, sameFileNum, isFirst);
331     int32_t successFileNum = RenameFiles(insertRestoreFiles);
332     AccurateRefresh::AssetAccurateRefresh assetRefresh(AccurateRefresh::CUSTOM_RESTORE_BUSSINESS_NAME);
333     errCode = BatchUpdateTimePending(insertRestoreFiles, assetRefresh);
334     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "BatchUpdateTimePending failed. errCode: %{public}d", errCode);
335     assetRefresh.RefreshAlbum();
336     assetRefresh.Notify();
337     UpdateAndNotifyShootingModeAlbumIfNeeded(insertRestoreFiles);
338     if (isFirst) {
339         CHECK_AND_RETURN_RET(successFileNum != 0, E_ERR);
340         CHECK_AND_RETURN_RET_LOG(UpdatePhotoAlbum(restoreTaskInfo, insertRestoreFiles[0]) == E_OK,
341             errCode, "UpdatePhotoAlbum failed.");
342     }
343     int32_t totalFileNum = static_cast<int32_t>(filePathVector.size());
344     successNum_.fetch_add(successFileNum);
345     failNum_.fetch_add(totalFileNum - successFileNum - sameFileNum);
346     MEDIA_DEBUG_LOG("HandleCustomRestore success.");
347     return E_OK;
348 }
349 
BatchUpdateTimePending(const vector<FileInfo> & restoreFiles,AccurateRefresh::AssetAccurateRefresh & assetRefresh)350 int32_t PhotoCustomRestoreOperation::BatchUpdateTimePending(const vector<FileInfo> &restoreFiles,
351     AccurateRefresh::AssetAccurateRefresh &assetRefresh)
352 {
353     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
354     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "BatchUpdateTimePending: get rdb store fail!");
355 
356     // 构建包含所有文件路径的参数列表
357     std::vector<std::string> filePahts;
358     for (const auto& file : restoreFiles) {
359         filePahts.push_back(file.filePath);
360     }
361 
362     NativeRdb::ValuesBucket values;
363     values.Put(MediaColumn::MEDIA_TIME_PENDING, 0);
364     NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PhotoColumn::PHOTOS_TABLE);
365     predicates.In(PhotoColumn::MEDIA_FILE_PATH, filePahts);
366     int32_t changeRows = -1;
367 
368     int32_t errCode = assetRefresh.Update(changeRows, values, predicates);
369     CHECK_AND_RETURN_RET_LOG((errCode == E_OK && changeRows > 0), E_HAS_DB_ERROR,
370         "BatchUpdateTimePending: update time_pending failed. errCode: %{public}d, updateRows: %{public}d", errCode,
371         changeRows);
372     return E_OK;
373 }
374 
UpdatePhotoAlbum(RestoreTaskInfo & restoreTaskInfo,FileInfo fileInfo)375 int32_t PhotoCustomRestoreOperation::UpdatePhotoAlbum(RestoreTaskInfo &restoreTaskInfo, FileInfo fileInfo)
376 {
377     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
378     CHECK_AND_RETURN_RET(rdbStore != nullptr, E_HAS_DB_ERROR);
379     const string querySql = "SELECT " + MediaColumn::MEDIA_ID + "," + PhotoColumn::PHOTO_OWNER_ALBUM_ID + " FROM " +
380                             PhotoColumn::PHOTOS_TABLE + " WHERE data ='" + fileInfo.filePath + "';";
381     auto resultSet = rdbStore->QuerySql(querySql);
382     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "execute select unique number failed.");
383 
384     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
385         MEDIA_ERR_LOG("execute GoToFirstRow err.");
386         resultSet->Close();
387         return E_HAS_DB_ERROR;
388     }
389     int32_t fileId = GetInt32Val(PhotoColumn::MEDIA_ID, resultSet);
390     int32_t albumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
391     resultSet->Close();
392     restoreTaskInfo.firstFileId = fileId;
393     string extrUri = MediaFileUtils::GetExtraUri(fileInfo.displayName, fileInfo.filePath);
394     restoreTaskInfo.firstFileUri = MediaFileUtils::GetUriByExtrConditions(
395         ML_FILE_URI_PREFIX + MediaFileUri::GetMediaTypeUri(fileInfo.mediaType, MEDIA_API_VERSION_V10) + "/",
396         to_string(fileId),
397         extrUri);
398     if (restoreTaskInfo.uriType == RESTORE_URI_TYPE_PHOTO) {
399         restoreTaskInfo.uri = restoreTaskInfo.firstFileUri;
400     } else {
401         restoreTaskInfo.uri = PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(albumId);
402     }
403     restoreTaskInfo.albumId = albumId;
404     return E_OK;
405 }
406 
SendPhotoAlbumNotify(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType,const UniqueNumber & uniqueNumber)407 void PhotoCustomRestoreOperation::SendPhotoAlbumNotify(RestoreTaskInfo &restoreTaskInfo, int32_t notifyType,
408     const UniqueNumber &uniqueNumber)
409 {
410     auto watch = MediaLibraryNotify::GetInstance();
411     CHECK_AND_RETURN_LOG(watch != nullptr, "Can not get MediaLibraryNotify Instance");
412     if (notifyType == NOTIFY_FIRST) {
413         watch->Notify(restoreTaskInfo.firstFileUri, NOTIFY_ADD);
414     } else {
415         watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NOTIFY_ADD);
416     }
417     std::string albumUri =
418         MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(restoreTaskInfo.albumId));
419     watch->Notify(albumUri, NotifyType::NOTIFY_UPDATE);
420     watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NotifyType::NOTIFY_ALBUM_ADD_ASSET, restoreTaskInfo.albumId);
421     if (uniqueNumber.imageTotalNumber > 0) {
422         watch->Notify(restoreTaskInfo.imageAlbumUri, NotifyType::NOTIFY_UPDATE);
423         watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NotifyType::NOTIFY_ALBUM_ADD_ASSET, restoreTaskInfo.imageAlbumId);
424     }
425     if (uniqueNumber.videoTotalNumber > 0) {
426         watch->Notify(restoreTaskInfo.videoAlbumUri, NotifyType::NOTIFY_UPDATE);
427         watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NotifyType::NOTIFY_ALBUM_ADD_ASSET, restoreTaskInfo.videoAlbumId);
428     }
429     MEDIA_DEBUG_LOG("PhotoAlbumNotify finished.");
430 }
431 
GenerateCustomRestoreNotify(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType)432 InnerRestoreResult PhotoCustomRestoreOperation::GenerateCustomRestoreNotify(
433     RestoreTaskInfo &restoreTaskInfo, int32_t notifyType)
434 {
435     InnerRestoreResult restoreResult;
436     restoreResult.errCode = 0;
437     restoreResult.stage = (notifyType == NOTIFY_LAST || notifyType == NOTIFY_CANCEL) ? "finished" : "onRestore";
438     restoreResult.uriType = restoreTaskInfo.uriType;
439     restoreResult.uri = restoreTaskInfo.uri;
440     restoreResult.totalNum = restoreTaskInfo.totalNum;
441     if (restoreTaskInfo.totalNum == 0) {
442         restoreResult.successNum = 0;
443         restoreResult.failedNum = 0;
444         restoreResult.sameNum = 0;
445         restoreResult.progress = 0;
446         return restoreResult;
447     }
448     restoreResult.successNum = successNum_;
449     restoreResult.sameNum = sameNum_;
450     if (notifyType == NOTIFY_LAST) {
451         restoreResult.failedNum = restoreTaskInfo.totalNum - restoreResult.successNum - restoreResult.sameNum;
452     } else {
453         restoreResult.failedNum = failNum_;
454     }
455     restoreResult.cancelNum = 0;
456     if (notifyType == NOTIFY_CANCEL) {
457         restoreResult.cancelNum =
458             restoreResult.totalNum - restoreResult.successNum - restoreResult.sameNum - restoreResult.failedNum;
459     }
460     restoreResult.progress = PROGRESS_MULTI_NUM *
461                              (restoreResult.successNum + restoreResult.failedNum + restoreResult.sameNum) /
462                              restoreTaskInfo.totalNum;
463     return restoreResult;
464 }
465 
SendNotifyMessage(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType,int32_t errCode,int32_t fileNum,const UniqueNumber & uniqueNumber)466 void PhotoCustomRestoreOperation::SendNotifyMessage(
467     RestoreTaskInfo &restoreTaskInfo, int32_t notifyType, int32_t errCode, int32_t fileNum,
468     const UniqueNumber &uniqueNumber)
469 {
470     // notify album
471     if (errCode == E_OK && successNum_ > 0) {
472         SendPhotoAlbumNotify(restoreTaskInfo, notifyType, uniqueNumber);
473     }
474     if (errCode != E_OK) {
475         failNum_.fetch_add(fileNum);
476     }
477     InnerRestoreResult restoreResult = GenerateCustomRestoreNotify(restoreTaskInfo, notifyType);
478     if (notifyType == NOTIFY_FIRST && errCode != E_OK) {
479         restoreResult.stage = "finished";
480         restoreResult.errCode = 1;
481         restoreResult.progress = 0;
482         restoreResult.uri = "";
483     }
484     MEDIA_DEBUG_LOG("CustomRestoreNotify stage:%{public}s errCode:%{public}d progress:%{public}d",
485         restoreResult.stage.c_str(), restoreResult.errCode, restoreResult.progress);
486     MEDIA_DEBUG_LOG(
487         "CustomRestoreNotify totalNum:%{public}d successNum:%{public}d failedNum:%{public}d sameNum:%{public}d",
488         restoreResult.totalNum, restoreResult.successNum, restoreResult.failedNum, restoreResult.sameNum);
489     CustomRestoreNotify customRestoreNotify;
490     customRestoreNotify.Notify(restoreTaskInfo.keyPath, restoreResult);
491 }
492 
SetDestinationPath(vector<FileInfo> & restoreFiles,UniqueNumber & uniqueNumber)493 vector<FileInfo> PhotoCustomRestoreOperation::SetDestinationPath(
494     vector<FileInfo> &restoreFiles, UniqueNumber &uniqueNumber)
495 {
496     vector<FileInfo> newRestoreFiles;
497     for (auto &fileInfo : restoreFiles) {
498         string mediaDirPath;
499         int32_t mediaType = fileInfo.mediaType;
500         GetAssetRootDir(mediaType, mediaDirPath);
501         CHECK_AND_CONTINUE_ERR_LOG(!mediaDirPath.empty(),
502             "get asset root dir failed. mediaType: %{public}d", mediaType);
503 
504         int32_t fileId = 0;
505         if (fileInfo.mediaType == MediaType::MEDIA_TYPE_IMAGE) {
506             fileId = uniqueNumber.imageCurrentNumber++;
507         } else if (fileInfo.mediaType == MediaType::MEDIA_TYPE_VIDEO) {
508             fileId = uniqueNumber.videoCurrentNumber++;
509         }
510         int32_t bucketNum = 0;
511         int32_t retCode = MediaFileUri::CreateAssetBucket(fileId, bucketNum);
512         CHECK_AND_CONTINUE_ERR_LOG(retCode == E_OK, "CreateAssetBucket failed. bucketNum: %{public}d", bucketNum);
513 
514         string realName;
515         retCode = MediaFileUtils::CreateAssetRealName(fileId, fileInfo.mediaType, fileInfo.extension, realName);
516         CHECK_AND_CONTINUE_ERR_LOG(retCode == E_OK, "CreateAssetRealName failed. retCode: %{public}d", retCode);
517 
518         string dirPath = ROOT_MEDIA_DIR + mediaDirPath + to_string(bucketNum);
519         if (!MediaFileUtils::IsFileExists(dirPath)) {
520             CHECK_AND_CONTINUE_ERR_LOG(MediaFileUtils::CreateDirectory(dirPath),
521                 "CreateDirectory failed. retCode: %{public}s", dirPath.c_str());
522         }
523         fileInfo.filePath = dirPath + "/" + realName;
524         fileInfo.fileId = fileId;
525         newRestoreFiles.push_back(fileInfo);
526     }
527     return newRestoreFiles;
528 }
529 
GetAssetRootDir(int32_t mediaType,string & rootDirPath)530 void PhotoCustomRestoreOperation::GetAssetRootDir(int32_t mediaType, string &rootDirPath)
531 {
532     map<int, string> rootDir = {
533         {MEDIA_TYPE_FILE, DOCUMENT_BUCKET + SLASH_CHAR},
534         {MEDIA_TYPE_VIDEO, PHOTO_BUCKET + SLASH_CHAR},
535         {MEDIA_TYPE_IMAGE, PHOTO_BUCKET + SLASH_CHAR},
536         {MEDIA_TYPE_AUDIO, AUDIO_BUCKET + SLASH_CHAR},
537     };
538     if (rootDir.count(mediaType) == 0) {
539         rootDirPath = rootDir[MEDIA_TYPE_FILE];
540     } else {
541         rootDirPath = rootDir[mediaType];
542     }
543 }
544 
BatchInsert(RestoreTaskInfo & restoreTaskInfo,vector<FileInfo> & restoreFiles,int32_t & sameFileNum,bool isFirst)545 vector<FileInfo> PhotoCustomRestoreOperation::BatchInsert(
546     RestoreTaskInfo &restoreTaskInfo, vector<FileInfo> &restoreFiles, int32_t &sameFileNum, bool isFirst)
547 {
548     vector<FileInfo> insertFiles;
549     vector<NativeRdb::ValuesBucket> values;
550     for (auto &fileInfo : restoreFiles) {
551         NativeRdb::ValuesBucket value = GetInsertValue(restoreTaskInfo, fileInfo);
552         if (!IsDuplication(restoreTaskInfo, fileInfo)) {
553             values.push_back(value);
554             insertFiles.push_back(fileInfo);
555         }
556     }
557     sameFileNum = static_cast<int32_t>(restoreFiles.size() - insertFiles.size());
558     sameNum_.fetch_add(sameFileNum);
559     MEDIA_INFO_LOG("BatchInsert values size: %{public}d, sameNum:%{public}d",
560         static_cast<int32_t>(values.size()), sameFileNum);
561     if (values.size() == 0) {
562         return insertFiles;
563     }
564     int64_t rowNum = 0;
565     int32_t errCode = E_ERR;
566     TransactionOperations trans{__func__};
567     std::function<int(void)> func = [&]() -> int {
568         errCode = trans.BatchInsert(rowNum, PhotoColumn::PHOTOS_TABLE, values);
569         CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsert failed, errCode: %{public}d,"
570             " rowNum: %{public}" PRId64, errCode, rowNum);
571         return errCode;
572     };
573     // If not the first batch of data, retry 10 times
574     errCode = trans.RetryTrans(func, !isFirst);
575     if (errCode != E_OK) {
576         insertFiles.clear();
577         MEDIA_ERR_LOG("RetryTrans: trans retry fail!, ret:%{public}d", errCode);
578         return insertFiles;
579     }
580     MEDIA_INFO_LOG("BatchInsert success rowNum: %{public}" PRId64, rowNum);
581     return insertFiles;
582 }
583 
QueryAlbumId(RestoreTaskInfo & restoreTaskInfo)584 void PhotoCustomRestoreOperation::QueryAlbumId(RestoreTaskInfo &restoreTaskInfo)
585 {
586     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
587     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "QueryAlbumId: get rdb store fail!");
588 
589     const string queryAlbumPathSql =
590         "SELECT lpath from album_plugin WHERE (bundle_name = ? OR album_name = ?) AND priority = '1';";
591     std::vector<NativeRdb::ValueObject> albumPathParams = {restoreTaskInfo.bundleName, restoreTaskInfo.packageName};
592     auto albumPathResult = rdbStore->QuerySql(queryAlbumPathSql, albumPathParams);
593     string lpath;
594     if (albumPathResult == nullptr) {
595         MEDIA_ERR_LOG("QueryAlbumId: query album_plugin failed!");
596     } else if (albumPathResult->GoToFirstRow() != NativeRdb::E_OK) {
597         MEDIA_WARN_LOG("QueryAlbumId: album_plugin have no record!");
598         albumPathResult->Close();
599     } else {
600         lpath = GetStringVal("lpath", albumPathResult);
601         albumPathResult->Close();
602     }
603     if (lpath.empty()) {
604         lpath = ALBUM_PATH_PREFIX + restoreTaskInfo.packageName;
605     }
606 
607     const string querySql = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " + PhotoAlbumColumns::TABLE + " WHERE " +
608                             PhotoAlbumColumns::ALBUM_LPATH + " = ? ;";
609     std::vector<NativeRdb::ValueObject> params = {lpath};
610     auto resultSet = rdbStore->QuerySql(querySql, params);
611     CHECK_AND_RETURN_LOG(resultSet != nullptr, "QueryAlbumId: query PhotoAlbum failed!");
612 
613     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
614         MEDIA_WARN_LOG("album is not exits, skip check duplication.");
615         restoreTaskInfo.isDeduplication = false;
616         resultSet->Close();
617         return;
618     }
619     int32_t albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
620     resultSet->Close();
621     if (albumId > 0) {
622         restoreTaskInfo.albumId = albumId;
623         MEDIA_ERR_LOG("QueryAlbumId albumId:%{public}d", albumId);
624         InitPhotoCache(restoreTaskInfo);
625     }
626 }
627 
GetAlbumInfoBySubType(int32_t subType,string & albumUri,int32_t & albumId)628 int32_t PhotoCustomRestoreOperation::GetAlbumInfoBySubType(int32_t subType, string &albumUri, int32_t &albumId)
629 {
630     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
631     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "GetAlbumInfoBySubType: get rdb store fail!");
632 
633     const string querySql = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " + PhotoAlbumColumns::TABLE + " WHERE " +
634         PhotoAlbumColumns::ALBUM_SUBTYPE + " = ? ;";
635     std::vector<NativeRdb::ValueObject> params = {subType};
636     auto resultSet = rdbStore->QuerySql(querySql, params);
637     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR,
638         "GetAlbumInfoBySubType: query PhotoAlbum failed! subType=%{public}d", subType);
639 
640     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
641         MEDIA_ERR_LOG("GetAlbumInfoBySubType first row empty.");
642         resultSet->Close();
643         return E_HAS_DB_ERROR;
644     }
645     albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
646     resultSet->Close();
647     albumUri = MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(albumId));
648     return E_OK;
649 }
650 
IsDuplication(RestoreTaskInfo & restoreTaskInfo,FileInfo & fileInfo)651 bool PhotoCustomRestoreOperation::IsDuplication(RestoreTaskInfo &restoreTaskInfo, FileInfo &fileInfo)
652 {
653     bool cond = (!restoreTaskInfo.isDeduplication || restoreTaskInfo.albumId == 0);
654     CHECK_AND_RETURN_RET(!cond, false);
655     int32_t mediaType = fileInfo.mediaType;
656     if (restoreTaskInfo.hasPhotoCache) {
657         string photoId = fileInfo.fileName + "_" + to_string(fileInfo.size) + "_" + to_string(mediaType) + "_" +
658                          to_string(fileInfo.orientation);
659         return photoCache_.count(photoId) > 0;
660     }
661 
662     const string querySql =
663         "SELECT COUNT(1) as count FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " + PhotoColumn::PHOTO_OWNER_ALBUM_ID +
664         "=" + to_string(restoreTaskInfo.albumId) + " AND " + MediaColumn::MEDIA_NAME + "='" + fileInfo.fileName +
665         "' AND " + MediaColumn::MEDIA_SIZE + "=" + to_string(fileInfo.size) + " AND " + MediaColumn::MEDIA_TYPE + "=" +
666         to_string(mediaType) + " AND " + PhotoColumn::PHOTO_ORIENTATION + "=" + to_string(fileInfo.orientation) + ";";
667     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
668     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, false, "IsDuplication: get rdb store fail!");
669 
670     auto resultSet = rdbStore->QuerySql(querySql);
671     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, false, "IsDuplication: query PhotoAlbum failed!");
672     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
673         MEDIA_ERR_LOG("IsDuplication first row empty.");
674         resultSet->Close();
675         return false;
676     }
677     int32_t count = GetInt32Val("count", resultSet);
678     resultSet->Close();
679     return count > 0;
680 }
681 
InitPhotoCache(RestoreTaskInfo & restoreTaskInfo)682 int32_t PhotoCustomRestoreOperation::InitPhotoCache(RestoreTaskInfo &restoreTaskInfo)
683 {
684     bool cond = (!restoreTaskInfo.isDeduplication || restoreTaskInfo.albumId == 0);
685     CHECK_AND_RETURN_RET(!cond, E_OK);
686     MEDIA_INFO_LOG("InitPhotoCache begin, albumId: %{public}d", restoreTaskInfo.albumId);
687     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
688     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "InitPhotoCache: get rdb store fail!");
689 
690     const string queryCountSql = "SELECT COUNT(1) as count FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " +
691                                  PhotoColumn::PHOTO_OWNER_ALBUM_ID + "=" + to_string(restoreTaskInfo.albumId) + ";";
692     auto resultSet = rdbStore->QuerySql(queryCountSql);
693     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "InitPhotoCache: get resultSet fail!");
694     if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
695         MEDIA_ERR_LOG("InitPhotoCache first row empty.");
696         resultSet->Close();
697         return E_HAS_DB_ERROR;
698     }
699 
700     int32_t count = GetInt32Val("count", resultSet);
701     resultSet->Close();
702     if (count > MAX_PHOTO_CACHE_NUM) {
703         MEDIA_WARN_LOG("album has more than %{public}d, skip create cache.", MAX_PHOTO_CACHE_NUM);
704         return E_OK;
705     }
706     const string queryCacheSql = "SELECT " + MediaColumn::MEDIA_NAME + "," + MediaColumn::MEDIA_SIZE + "," +
707                                  MediaColumn::MEDIA_TYPE + "," + PhotoColumn::PHOTO_ORIENTATION + " FROM " +
708                                  PhotoColumn::PHOTOS_TABLE + " WHERE " + PhotoColumn::PHOTO_OWNER_ALBUM_ID + "=" +
709                                  to_string(restoreTaskInfo.albumId) + ";";
710     auto resultCacheSet = rdbStore->QuerySql(queryCacheSql);
711     CHECK_AND_RETURN_RET(resultCacheSet != nullptr, E_HAS_DB_ERROR);
712 
713     while (resultCacheSet->GoToNextRow() == NativeRdb::E_OK) {
714         string displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultCacheSet);
715         int64_t mediaSize = GetInt64Val(MediaColumn::MEDIA_SIZE, resultCacheSet);
716         int32_t mediaType = GetInt32Val(MediaColumn::MEDIA_TYPE, resultCacheSet);
717         int32_t orientation = GetInt32Val(PhotoColumn::PHOTO_ORIENTATION, resultCacheSet);
718         photoCache_.insert(
719             displayName + "_" + to_string(mediaSize) + "_" + to_string(mediaType) + "_" + to_string(orientation));
720     }
721     resultCacheSet->Close();
722     restoreTaskInfo.hasPhotoCache = true;
723     MEDIA_INFO_LOG("InitPhotoCache success, num:%{public}d", static_cast<int32_t>(photoCache_.size()));
724     return E_OK;
725 }
726 
UpdateUniqueNumber(UniqueNumber & uniqueNumber)727 int32_t PhotoCustomRestoreOperation::UpdateUniqueNumber(UniqueNumber &uniqueNumber)
728 {
729     int32_t errCode = MediaLibraryAssetOperations::CreateAssetUniqueIds(
730         MediaType::MEDIA_TYPE_IMAGE, uniqueNumber.imageTotalNumber, uniqueNumber.imageCurrentNumber);
731     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "CreateAssetUniqueNumber IMAGE fail!, ret:%{public}d", errCode);
732 
733     MEDIA_DEBUG_LOG("imageTotalNumber: %{public}d imageCurrentNumber: %{public}d",
734         uniqueNumber.imageTotalNumber, uniqueNumber.imageCurrentNumber);
735     errCode = MediaLibraryAssetOperations::CreateAssetUniqueIds(
736         MediaType::MEDIA_TYPE_VIDEO, uniqueNumber.videoTotalNumber, uniqueNumber.videoCurrentNumber);
737     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "CreateAssetUniqueNumber VIDEO fail!, ret:%{public}d", errCode);
738     MEDIA_DEBUG_LOG("videoTotalNumber: %{public}d videoCurrentNumber: %{public}d",
739         uniqueNumber.videoTotalNumber, uniqueNumber.videoCurrentNumber);
740     return E_OK;
741 }
742 
FillFileInfo(FileInfo & fileInfo,const std::unique_ptr<Metadata> & data)743 static void FillFileInfo(FileInfo& fileInfo, const std::unique_ptr<Metadata>& data)
744 {
745     fileInfo.size = data->GetFileSize();
746     fileInfo.orientation = data->GetOrientation();
747     fileInfo.mimeType = data->GetFileMimeType();
748     fileInfo.shootingMode = data->GetShootingMode();
749     fileInfo.frontCamera = data->GetFrontCamera();
750     fileInfo.movingPhotoEffectMode = 0;
751 }
752 
GetInsertValue(RestoreTaskInfo & restoreTaskInfo,FileInfo & fileInfo)753 NativeRdb::ValuesBucket PhotoCustomRestoreOperation::GetInsertValue(
754     RestoreTaskInfo &restoreTaskInfo, FileInfo &fileInfo)
755 {
756     NativeRdb::ValuesBucket value;
757     value.PutString(MediaColumn::MEDIA_FILE_PATH, fileInfo.filePath);
758     value.PutString(MediaColumn::MEDIA_TITLE, fileInfo.title);
759     value.PutString(MediaColumn::MEDIA_NAME, fileInfo.displayName);
760     int32_t subType = fileInfo.isLivePhoto ? static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)
761                                            : static_cast<int32_t>(PhotoSubType::DEFAULT);
762     value.PutInt(PhotoColumn::PHOTO_SUBTYPE, subType);
763     fileInfo.subtype = subType;
764     value.PutString(MediaColumn::MEDIA_PACKAGE_NAME, restoreTaskInfo.packageName);
765     value.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, restoreTaskInfo.bundleName);
766     value.PutString(MediaColumn::MEDIA_OWNER_APPID, restoreTaskInfo.appId);
767     std::unique_ptr<Metadata> data = make_unique<Metadata>();
768     data->SetFilePath(fileInfo.originFilePath);
769     data->SetFileName(fileInfo.fileName);
770     data->SetFileMediaType(fileInfo.mediaType);
771     FillMetadata(data);
772     value.Put(MediaColumn::MEDIA_DATE_TAKEN, data->GetDateTaken());
773     value.Put(PhotoColumn::PHOTO_DETAIL_TIME, data->GetDetailTime());
774     value.Put(PhotoColumn::PHOTO_DATE_YEAR, data->GetDateYear());
775     value.Put(PhotoColumn::PHOTO_DATE_MONTH, data->GetDateMonth());
776     value.Put(PhotoColumn::PHOTO_DATE_DAY, data->GetDateDay());
777     value.PutLong(MediaColumn::MEDIA_DATE_ADDED, MediaFileUtils::UTCTimeMilliSeconds());
778     value.PutInt(PhotoColumn::PHOTO_ORIENTATION, data->GetOrientation());
779     value.PutInt(PhotoColumn::PHOTO_EXIF_ROTATE, data->GetExifRotate());
780     value.PutString(MediaColumn::MEDIA_FILE_PATH, data->GetFilePath());
781     value.PutString(MediaColumn::MEDIA_MIME_TYPE, data->GetFileMimeType());
782     value.PutString(PhotoColumn::PHOTO_MEDIA_SUFFIX, data->GetFileExtension());
783     value.PutInt(MediaColumn::MEDIA_TYPE, fileInfo.mediaType);
784     value.PutString(MediaColumn::MEDIA_TITLE, data->GetFileTitle());
785     value.PutLong(MediaColumn::MEDIA_SIZE, data->GetFileSize());
786     value.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, data->GetFileDateModified());
787     value.PutInt(MediaColumn::MEDIA_DURATION, data->GetFileDuration());
788     value.PutLong(MediaColumn::MEDIA_TIME_PENDING, -1);
789     value.PutInt(PhotoColumn::PHOTO_HEIGHT, data->GetFileHeight());
790     value.PutInt(PhotoColumn::PHOTO_WIDTH, data->GetFileWidth());
791     value.PutDouble(PhotoColumn::PHOTO_LONGITUDE, data->GetLongitude());
792     value.PutDouble(PhotoColumn::PHOTO_LATITUDE, data->GetLatitude());
793     value.PutString(PhotoColumn::PHOTO_ALL_EXIF, data->GetAllExif());
794     value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE, data->GetShootingMode());
795     value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE_TAG, data->GetShootingModeTag());
796     value.PutLong(PhotoColumn::PHOTO_LAST_VISIT_TIME, data->GetLastVisitTime());
797     value.PutString(PhotoColumn::PHOTO_FRONT_CAMERA, data->GetFrontCamera());
798     value.PutInt(PhotoColumn::PHOTO_DYNAMIC_RANGE_TYPE, data->GetDynamicRangeType());
799     value.PutString(PhotoColumn::PHOTO_USER_COMMENT, data->GetUserComment());
800     value.PutInt(PhotoColumn::PHOTO_QUALITY, 0);
801     FillFileInfo(fileInfo, data);
802     return value;
803 }
804 
GetFileInfos(vector<string> & filePathVector,UniqueNumber & uniqueNumber)805 vector<FileInfo> PhotoCustomRestoreOperation::GetFileInfos(vector<string> &filePathVector, UniqueNumber &uniqueNumber)
806 {
807     vector<FileInfo> restoreFiles;
808     for (auto &filePath : filePathVector) {
809         FileInfo fileInfo;
810         fileInfo.fileName = MediaFileUtils::GetFileName(filePath);
811         fileInfo.displayName = fileInfo.fileName;
812         fileInfo.originFilePath = filePath;
813         fileInfo.extension = ScannerUtils::GetFileExtension(fileInfo.fileName);
814         fileInfo.title = ScannerUtils::GetFileTitle(fileInfo.fileName);
815         fileInfo.mediaType = MediaFileUtils::GetMediaType(fileInfo.fileName);
816         fileInfo.isLivePhoto = MovingPhotoFileUtils::IsLivePhoto(filePath);
817         if (fileInfo.mediaType == MediaType::MEDIA_TYPE_FILE) {
818             fileInfo.mediaType = MediaFileUtils::GetMediaTypeNotSupported(fileInfo.fileName);
819             bool cond = (fileInfo.mediaType == MediaType::MEDIA_TYPE_IMAGE ||
820                 fileInfo.mediaType == MediaType::MEDIA_TYPE_VIDEO);
821             CHECK_AND_WARN_LOG(!cond, "media type not support, fileName is %{private}s", fileInfo.fileName.c_str());
822         }
823         if (fileInfo.mediaType == MediaType::MEDIA_TYPE_IMAGE) {
824             uniqueNumber.imageTotalNumber++;
825         } else if (fileInfo.mediaType == MediaType::MEDIA_TYPE_VIDEO) {
826             uniqueNumber.videoTotalNumber++;
827         } else {
828             MEDIA_ERR_LOG(
829                 "This media type[%{public}s] is not image or video, skip restore.", fileInfo.extension.c_str());
830             continue;
831         }
832         restoreFiles.push_back(fileInfo);
833     }
834     return restoreFiles;
835 }
836 
FillMetadata(std::unique_ptr<Metadata> & data)837 int32_t PhotoCustomRestoreOperation::FillMetadata(std::unique_ptr<Metadata> &data)
838 {
839     int32_t err = GetFileMetadata(data);
840     if (err != E_OK) {
841         MEDIA_ERR_LOG("failed to get file metadata");
842         return err;
843     }
844     if (data->GetFileMediaType() == MEDIA_TYPE_IMAGE) {
845         err = MetadataExtractor::ExtractImageMetadata(data);
846     } else {
847         err = MetadataExtractor::ExtractAVMetadata(data, Scene::AV_META_SCENE_CLONE);
848         MEDIA_INFO_LOG("Extract av metadata end");
849     }
850     CHECK_AND_RETURN_RET_LOG(err == E_OK, err, "failed to extension data");
851     return E_OK;
852 }
853 
GetFileMetadata(std::unique_ptr<Metadata> & data)854 int32_t PhotoCustomRestoreOperation::GetFileMetadata(std::unique_ptr<Metadata> &data)
855 {
856     struct stat statInfo {};
857     if (stat(data->GetFilePath().c_str(), &statInfo) != 0) {
858         MEDIA_ERR_LOG("stat syscall err %{public}d", errno);
859         return E_FAIL;
860     }
861     data->SetFileSize(statInfo.st_size);
862     auto dateModified = static_cast<int64_t>(MediaFileUtils::Timespec2Millisecond(statInfo.st_mtim));
863     if (dateModified == 0) {
864         dateModified = MediaFileUtils::UTCTimeMilliSeconds();
865         MEDIA_WARN_LOG("Invalid dateModified from st_mtim, use current time instead: %{public}lld",
866             static_cast<long long>(dateModified));
867     }
868     if (dateModified != 0 && data->GetFileDateModified() == 0) {
869         data->SetFileDateModified(dateModified);
870     }
871     string extension = ScannerUtils::GetFileExtension(data->GetFileName());
872     string mimeType = MimeTypeUtils::GetMimeTypeFromContent(data->GetFilePath());
873     data->SetFileExtension(extension);
874     data->SetFileMimeType(mimeType);
875     return E_OK;
876 }
877 
UpdateCoverPosition(const string & filePath,int64_t coverPosition)878 static void UpdateCoverPosition(const string &filePath, int64_t coverPosition)
879 {
880     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
881     CHECK_AND_RETURN_LOG(rdbStore != nullptr, "UpdateCoverPosition: get rdb store fail!");
882     string updateSql = "UPDATE " + PhotoColumn::PHOTOS_TABLE + " SET " + PhotoColumn::PHOTO_COVER_POSITION + " = ?, " +
883         PhotoColumn::PHOTO_IS_RECTIFICATION_COVER + " = 1 WHERE " + PhotoColumn::MEDIA_FILE_PATH + " = ?;";
884     std::vector<NativeRdb::ValueObject> params = {coverPosition, filePath};
885     int32_t errCode = rdbStore->ExecuteSql(updateSql, params);
886     CHECK_AND_PRINT_LOG(errCode >= 0, "UpdateCoverPosition: execute update cover_position failed,"
887         " ret = %{public}d", errCode);
888 }
889 
RenameFiles(const vector<FileInfo> & restoreFiles)890 int32_t PhotoCustomRestoreOperation::RenameFiles(const vector<FileInfo> &restoreFiles)
891 {
892     int32_t renameNum = 0;
893     for (const auto &fileInfo : restoreFiles) {
894         if (fileInfo.isLivePhoto) {
895             if (MoveLivePhoto(fileInfo.originFilePath, fileInfo.filePath) != E_OK) {
896                 MEDIA_ERR_LOG("MoveFile failed. srcFile:%{public}s, destFile:%{public}s",
897                     fileInfo.originFilePath.c_str(),
898                     fileInfo.filePath.c_str());
899                 DeleteDatabaseRecord(fileInfo.filePath);
900             } else {
901                 renameNum++;
902             }
903             continue;
904         }
905         if (!MediaFileUtils::MoveFile(fileInfo.originFilePath, fileInfo.filePath, true)) {
906             MEDIA_ERR_LOG("MoveFile failed. errno:%{public}d, srcFile:%{public}s, destFile:%{public}s", errno,
907                 fileInfo.originFilePath.c_str(),
908                 fileInfo.filePath.c_str());
909             DeleteDatabaseRecord(fileInfo.filePath);
910         } else {
911             renameNum++;
912         }
913     }
914     return renameNum;
915 }
916 
MoveLivePhoto(const string & originFilePath,const string & filePath)917 int32_t PhotoCustomRestoreOperation::MoveLivePhoto(const string &originFilePath, const string &filePath)
918 {
919     string videoPath = MovingPhotoFileUtils::GetMovingPhotoVideoPath(filePath);
920     string extraDataPath = MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(filePath);
921     string extraPathDir = MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(filePath);
922     if (!MediaFileUtils::IsFileExists(extraPathDir) && !MediaFileUtils::CreateDirectory(extraPathDir)) {
923         MEDIA_WARN_LOG("Failed to create local extra data dir");
924         return E_HAS_FS_ERROR;
925     }
926 
927     int32_t ret = MovingPhotoFileUtils::ConvertToMovingPhoto(originFilePath, filePath, videoPath, extraDataPath);
928     if (ret != E_OK) {
929         MEDIA_ERR_LOG("Failed to convert live photo, ret:%{public}d", ret);
930         (void)MediaFileUtils::DeleteFile(filePath);
931         (void)MediaFileUtils::DeleteFile(videoPath);
932         (void)MediaFileUtils::DeleteDir(extraPathDir);
933         return ret;
934     }
935     uint64_t coverPosition = 0;
936     uint32_t version = 0;
937     uint32_t frameIndex = 0;
938     bool hasCinemagraphInfo = false;
939     string absExtraDataPath;
940     if (!PathToRealPath(extraDataPath, absExtraDataPath)) {
941         MEDIA_WARN_LOG("file is not real path: %{private}s, errno: %{public}d", extraDataPath.c_str(), errno);
942         UpdateCoverPosition(filePath, static_cast<int64_t>(coverPosition));
943         return E_OK;
944     }
945     UniqueFd extraDataFd(open(absExtraDataPath.c_str(), O_RDONLY));
946     (void)MovingPhotoFileUtils::GetVersionAndFrameNum(extraDataFd.Get(), version, frameIndex, hasCinemagraphInfo);
947     (void)MovingPhotoFileUtils::GetCoverPosition(videoPath, frameIndex, coverPosition);
948     UpdateCoverPosition(filePath, static_cast<int64_t>(coverPosition));
949     return ret;
950 }
951 
DeleteDatabaseRecord(const string & filePath)952 void PhotoCustomRestoreOperation::DeleteDatabaseRecord(const string &filePath)
953 {
954     string deleteSql =
955         "DELETE FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " + PhotoColumn::MEDIA_FILE_PATH + " = ?;";
956     std::vector<NativeRdb::ValueObject> params = {filePath};
957     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
958     if (rdbStore == nullptr) {
959         return;
960     }
961 
962     int32_t ret = rdbStore->ExecuteSql(deleteSql, params);
963     CHECK_AND_RETURN_LOG(ret == NativeRdb::E_OK, "delete data from database failed, ret:%{public}d", ret);
964 }
965 
CleanTimeoutCustomRestoreTaskDir()966 void PhotoCustomRestoreOperation::CleanTimeoutCustomRestoreTaskDir()
967 {
968     MEDIA_INFO_LOG("CleanTimeoutCustomRestoreTaskDir");
969     auto timestampNow = std::chrono::duration_cast<std::chrono::milliseconds>(
970         std::chrono::system_clock::now().time_since_epoch()).count();
971     DIR* dir = opendir(CUSTOM_RESTORE_DIR.c_str());
972     if (dir == nullptr) {
973         MEDIA_ERR_LOG("failed open dir, errno: %{public}d.", errno);
974         return;
975     }
976     struct dirent *ptr = nullptr;
977     while ((ptr = readdir(dir)) != nullptr) {
978         if (ptr->d_type != DT_DIR || strcmp(".", ptr->d_name) == 0
979             || strcmp("..", ptr->d_name) == 0) {
980             continue;
981         }
982         std::string fileStr = CUSTOM_RESTORE_DIR + "/" + ptr->d_name;
983         struct stat statInfo {};
984         if (stat(fileStr.c_str(), &statInfo) != 0) {
985             MEDIA_ERR_LOG("stat syscall err");
986             continue;
987         }
988         auto dateCreated = static_cast<int64_t>(MediaFileUtils::Timespec2Millisecond(statInfo.st_ctim));
989         if ((timestampNow - dateCreated) < TIMEOUT_TASK_DIR_CLEAN_INTERVAL) {
990             MEDIA_ERR_LOG("no timeout file");
991             continue;
992         }
993         CHECK_AND_PRINT_LOG(MediaFileUtils::DeleteDir(fileStr), "clean timeout task dir failed");
994     }
995     closedir(dir);
996 }
997 
998 }  // namespace OHOS::Media
999