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 "userfile_manager_types.h"
47
48 using namespace std;
49 namespace OHOS::Media {
50 std::shared_ptr<PhotoCustomRestoreOperation> PhotoCustomRestoreOperation::instance_ = nullptr;
51 std::mutex PhotoCustomRestoreOperation::objMutex_;
52
GetInstance()53 PhotoCustomRestoreOperation &PhotoCustomRestoreOperation::GetInstance()
54 {
55 std::lock_guard<std::mutex> lock(PhotoCustomRestoreOperation::objMutex_);
56 if (PhotoCustomRestoreOperation::instance_ == nullptr) {
57 PhotoCustomRestoreOperation::instance_ = std::make_shared<PhotoCustomRestoreOperation>();
58 }
59 return *PhotoCustomRestoreOperation::instance_;
60 }
61
Start()62 PhotoCustomRestoreOperation &PhotoCustomRestoreOperation::Start()
63 {
64 if (this->isRunning_.exchange(true)) {
65 MEDIA_WARN_LOG("custom restore operation is running. skip start");
66 return *this;
67 }
68 CleanTimeoutCustomRestoreTaskDir();
69 while (!this->taskQueue_.empty()) {
70 RestoreTaskInfo restoreTaskInfo = this->taskQueue_.front();
71 if (IsCancelTask(restoreTaskInfo)) {
72 CancelTaskFinish(restoreTaskInfo);
73 this->taskQueue_.pop();
74 continue;
75 }
76 DoCustomRestore(restoreTaskInfo);
77 this->taskQueue_.pop();
78 }
79 {
80 std::unique_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
81 cancelKeySet_.clear();
82 }
83 this->isRunning_.store(false);
84 return *this;
85 }
86
CancelTask(RestoreTaskInfo restoreTaskInfo)87 void PhotoCustomRestoreOperation::CancelTask(RestoreTaskInfo restoreTaskInfo)
88 {
89 MEDIA_INFO_LOG("cancel custom restore task. keyPath: %{public}s", restoreTaskInfo.keyPath.c_str());
90 std::unique_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
91 cancelKeySet_.insert(restoreTaskInfo.keyPath);
92 }
93
IsCancelTask(RestoreTaskInfo & restoreTaskInfo)94 bool PhotoCustomRestoreOperation::IsCancelTask(RestoreTaskInfo &restoreTaskInfo)
95 {
96 std::shared_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
97 return cancelKeySet_.count(restoreTaskInfo.keyPath) > 0;
98 }
99
CancelTaskFinish(RestoreTaskInfo & restoreTaskInfo)100 void PhotoCustomRestoreOperation::CancelTaskFinish(RestoreTaskInfo &restoreTaskInfo)
101 {
102 UniqueNumber uniqueNumber;
103 SendNotifyMessage(restoreTaskInfo, NOTIFY_CANCEL, E_OK, 0, uniqueNumber);
104 std::unique_lock<std::shared_mutex> lockGuard(cancelOprationLock_);
105 cancelKeySet_.erase(restoreTaskInfo.keyPath);
106 }
107
ApplyEfficiencyQuota(int32_t fileNum)108 void PhotoCustomRestoreOperation::ApplyEfficiencyQuota(int32_t fileNum)
109 {
110 #ifdef EFFICIENCY_MANAGER_ENABLE
111 int64_t quota = fileNum * BASE_EFFICIENCY_QUOTA / BASE_FILE_NUM;
112 if (quota == 0) {
113 MEDIA_WARN_LOG("quota is zero, skip apply efficiency quota.");
114 return;
115 }
116 string module = BUNDLE_NAME;
117 string reason = "Custom Restore";
118 MEDIA_DEBUG_LOG("ApplyEfficiencyQuota. quota: %{public}" PRId64, quota);
119 void *resourceQuotaMgrHandle = dlopen(ABNORMAL_MANAGER_LIB.c_str(), RTLD_NOW);
120 CHECK_AND_RETURN_LOG(resourceQuotaMgrHandle, "Not find resource_quota_manager lib.");
121
122 using HandleQuotaFunc = bool (*)(const std::string &, uint32_t, int64_t, const std::string &);
123 auto handleQuotaFunc =
124 reinterpret_cast<HandleQuotaFunc>(dlsym(resourceQuotaMgrHandle, "ApplyAbnormalControlQuota"));
125 if (!handleQuotaFunc) {
126 MEDIA_ERR_LOG("Not find ApplyAbnormalControlQuota func.");
127 dlclose(resourceQuotaMgrHandle);
128 return;
129 }
130 CHECK_AND_PRINT_LOG(handleQuotaFunc(module, MODULE_POWER_OVERUSED, quota, reason), "Do handleQuotaFunc failed.");
131 dlclose(resourceQuotaMgrHandle);
132 #endif
133 }
134
AddTask(RestoreTaskInfo restoreTaskInfo)135 PhotoCustomRestoreOperation &PhotoCustomRestoreOperation::AddTask(RestoreTaskInfo restoreTaskInfo)
136 {
137 MEDIA_INFO_LOG("add custom restore task. keyPath: %{public}s", restoreTaskInfo.keyPath.c_str());
138 this->taskQueue_.push(restoreTaskInfo);
139 return *this;
140 }
141
DoCustomRestore(RestoreTaskInfo & restoreTaskInfo)142 void PhotoCustomRestoreOperation::DoCustomRestore(RestoreTaskInfo &restoreTaskInfo)
143 {
144 ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_RESTORE_THREAD_NUM);
145 vector<string> files;
146 GetDirFiles(restoreTaskInfo.sourceDir, files);
147 InitRestoreTask(restoreTaskInfo, files.size());
148 bool isFirstRestoreSuccess = false;
149 int32_t firstRestoreIndex = 0;
150 int32_t total = static_cast<int32_t>(files.size());
151 int32_t lastIndex = total - 1;
152 for (int32_t index = 0; index < total; index++) {
153 if (IsCancelTask(restoreTaskInfo)) {
154 break;
155 }
156 if (index == 0 || !isFirstRestoreSuccess) {
157 isFirstRestoreSuccess = HandleFirstRestoreFile(restoreTaskInfo, files, index, firstRestoreIndex);
158 if (!isFirstRestoreSuccess && index == lastIndex) {
159 break;
160 }
161 continue;
162 }
163 // Remainder and multiple of MAX_RESTORE_FILE_NUM
164 int32_t remainder = (index + 1) % MAX_RESTORE_FILE_NUM;
165 int32_t multiples = (index + 1) / MAX_RESTORE_FILE_NUM;
166 if (remainder == 0 || index == lastIndex) {
167 int32_t fileNum = remainder == 0 && multiples > 0 ? MAX_RESTORE_FILE_NUM : remainder;
168 int32_t beginOffset = index - fileNum + 1;
169 if (beginOffset <= firstRestoreIndex) {
170 // not contain first restore file
171 beginOffset = firstRestoreIndex + 1;
172 fileNum = index - beginOffset + 1;
173 }
174 int32_t notifyType = index == lastIndex ? NOTIFY_LAST : NOTIFY_PROGRESS;
175 vector<string> subFiles(files.begin() + beginOffset, files.begin() + index + 1);
176 ffrt::submit(
177 [this, &restoreTaskInfo, notifyType, subFiles]() {
178 HandleBatchCustomRestore(restoreTaskInfo, notifyType, subFiles);
179 },
180 {},
181 {},
182 ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
183 }
184 }
185 ffrt::wait();
186 ReleaseCustomRestoreTask(restoreTaskInfo);
187 }
188
ReleaseCustomRestoreTask(RestoreTaskInfo & restoreTaskInfo)189 void PhotoCustomRestoreOperation::PhotoCustomRestoreOperation::ReleaseCustomRestoreTask(
190 RestoreTaskInfo &restoreTaskInfo)
191 {
192 photoCache_.clear();
193 CHECK_AND_PRINT_LOG(MediaFileUtils::DeleteDir(restoreTaskInfo.sourceDir), "delete dir failed.");
194 ReportCustomRestoreTask(restoreTaskInfo);
195 if (IsCancelTask(restoreTaskInfo)) {
196 CancelTaskFinish(restoreTaskInfo);
197 }
198 }
199
ReportCustomRestoreTask(RestoreTaskInfo & restoreTaskInfo)200 void PhotoCustomRestoreOperation::ReportCustomRestoreTask(RestoreTaskInfo &restoreTaskInfo)
201 {
202 restoreTaskInfo.endTime = MediaFileUtils::UTCTimeSeconds();
203 CustomRestoreDfxDataPoint point;
204 point.customRestorePackageName = restoreTaskInfo.packageName;
205 point.albumLPath = restoreTaskInfo.albumLpath;
206 point.keyPath = restoreTaskInfo.keyPath;
207 point.totalNum = restoreTaskInfo.totalNum;
208 point.successNum = successNum_;
209 point.failedNum = failNum_;
210 point.sameNum = sameNum_;
211 if (IsCancelTask(restoreTaskInfo)) {
212 point.cancelNum = point.totalNum - point.successNum - point.sameNum - point.failedNum;
213 } else {
214 point.cancelNum = 0;
215 point.failedNum = point.totalNum - point.successNum - point.sameNum;
216 }
217 point.totalTime = static_cast<uint64_t>(restoreTaskInfo.endTime - restoreTaskInfo.beginTime);
218 MEDIA_INFO_LOG("report custom restore finished. cost:%{public}" PRId64, point.totalTime);
219 DfxReporter::ReportCustomRestoreFusion(point);
220 }
221
HandleFirstRestoreFile(RestoreTaskInfo & restoreTaskInfo,vector<string> & files,int32_t index,int32_t & firstRestoreIndex)222 bool PhotoCustomRestoreOperation::HandleFirstRestoreFile(
223 RestoreTaskInfo &restoreTaskInfo, vector<string> &files, int32_t index, int32_t &firstRestoreIndex)
224 {
225 vector<string> subFiles(files.begin() + index, files.begin() + index + 1);
226 UniqueNumber uniqueNumber;
227 int32_t errCode = HandleCustomRestore(restoreTaskInfo, subFiles, true, uniqueNumber);
228 bool isFirstRestoreSuccess = errCode == E_OK;
229 int32_t lastIndex = static_cast<int32_t>(files.size() - 1);
230 if (!isFirstRestoreSuccess && index == lastIndex) {
231 MEDIA_ERR_LOG("first file restore failed. stop restore task.");
232 SendNotifyMessage(restoreTaskInfo, NOTIFY_FIRST, errCode, 1, uniqueNumber);
233 }
234 if (isFirstRestoreSuccess) {
235 MEDIA_ERR_LOG("first file restore success.");
236 firstRestoreIndex = index;
237 int notifyType = index == lastIndex ? NOTIFY_LAST : NOTIFY_FIRST;
238 SendNotifyMessage(restoreTaskInfo, notifyType, errCode, 1, uniqueNumber);
239 }
240 return isFirstRestoreSuccess;
241 }
242
HandleBatchCustomRestore(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType,vector<string> subFiles)243 void PhotoCustomRestoreOperation::HandleBatchCustomRestore(
244 RestoreTaskInfo &restoreTaskInfo, int32_t notifyType, vector<string> subFiles)
245 {
246 if (IsCancelTask(restoreTaskInfo)) {
247 return;
248 }
249 int32_t fileNum = static_cast<int32_t>(subFiles.size());
250 UniqueNumber uniqueNumber;
251 int32_t errCode = HandleCustomRestore(restoreTaskInfo, subFiles, false, uniqueNumber);
252 SendNotifyMessage(restoreTaskInfo, notifyType, errCode, fileNum, uniqueNumber);
253 }
254
InitRestoreTask(RestoreTaskInfo & restoreTaskInfo,int32_t fileNum)255 void PhotoCustomRestoreOperation::InitRestoreTask(RestoreTaskInfo &restoreTaskInfo, int32_t fileNum)
256 {
257 successNum_.store(0);
258 failNum_.store(0);
259 sameNum_.store(0);
260 photoCache_.clear();
261 restoreTaskInfo.uriType = RESTORE_URI_TYPE_PHOTO;
262 restoreTaskInfo.totalNum = fileNum;
263 restoreTaskInfo.beginTime = MediaFileUtils::UTCTimeSeconds();
264 std::thread applyEfficiencyQuotaThread([this, fileNum] { ApplyEfficiencyQuota(fileNum); });
265 applyEfficiencyQuotaThread.detach();
266 QueryAlbumId(restoreTaskInfo);
267 GetAlbumInfoBySubType(PhotoAlbumSubType::IMAGE, restoreTaskInfo.imageAlbumUri, restoreTaskInfo.imageAlbumId);
268 GetAlbumInfoBySubType(PhotoAlbumSubType::VIDEO, restoreTaskInfo.videoAlbumUri, restoreTaskInfo.videoAlbumId);
269 }
270
HandleCustomRestore(RestoreTaskInfo & restoreTaskInfo,vector<string> filePathVector,bool isFirst,UniqueNumber & uniqueNumber)271 int32_t PhotoCustomRestoreOperation::HandleCustomRestore(
272 RestoreTaskInfo &restoreTaskInfo, vector<string> filePathVector, bool isFirst,
273 UniqueNumber &uniqueNumber)
274 {
275 MEDIA_DEBUG_LOG("HandleCustomRestore begin. size: %{public}d, isFirst: %{public}d",
276 static_cast<int32_t>(filePathVector.size()), isFirst ? 1 : 0);
277 vector<FileInfo> restoreFiles = GetFileInfos(filePathVector, uniqueNumber);
278 MEDIA_DEBUG_LOG("GetFileInfos finished");
279 int32_t errCode = UpdateUniqueNumber(uniqueNumber);
280 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "UpdateUniqueNumber failed. errCode: %{public}d", errCode);
281
282 MEDIA_DEBUG_LOG("UpdateUniqueNumber success.");
283 vector<FileInfo> destRestoreFiles = SetDestinationPath(restoreFiles, uniqueNumber);
284 if (destRestoreFiles.size() == 0) {
285 MEDIA_ERR_LOG("restore file number is zero.");
286 return E_ERR;
287 }
288 MEDIA_DEBUG_LOG("SetDestinationPath finished");
289 int32_t sameFileNum = 0;
290 vector<FileInfo> insertRestoreFiles = BatchInsert(restoreTaskInfo, destRestoreFiles, sameFileNum);
291 MEDIA_DEBUG_LOG("BatchInsert success.");
292 int32_t successFileNum = RenameFiles(insertRestoreFiles);
293 MEDIA_DEBUG_LOG("RenameFiles finished.");
294 errCode = BatchUpdateTimePending(insertRestoreFiles);
295 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "BatchUpdateTimePending failed. errCode: %{public}d", errCode);
296 MEDIA_DEBUG_LOG("BatchUpdateTimePending success.");
297 if (isFirst) {
298 if (successFileNum == 0) {
299 return E_ERR;
300 }
301 if (UpdatePhotoAlbum(restoreTaskInfo, insertRestoreFiles[0]) != E_OK) {
302 MEDIA_ERR_LOG("UpdatePhotoAlbum failed.");
303 return errCode;
304 }
305 }
306 int32_t totalFileNum = static_cast<int32_t>(filePathVector.size());
307 successNum_.fetch_add(successFileNum);
308 failNum_.fetch_add(totalFileNum - successFileNum - sameFileNum);
309 MEDIA_DEBUG_LOG("HandleCustomRestore success.");
310 return E_OK;
311 }
312
BatchUpdateTimePending(vector<FileInfo> & restoreFiles)313 int32_t PhotoCustomRestoreOperation::BatchUpdateTimePending(vector<FileInfo> &restoreFiles)
314 {
315 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
316 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "BatchUpdateTimePending: get rdb store fail!");
317
318 // 构建包含所有文件路径的参数列表
319 std::vector<std::string> filePahts;
320 for (const auto& file : restoreFiles) {
321 filePahts.push_back(file.filePath);
322 }
323
324 NativeRdb::ValuesBucket values;
325 values.Put(MediaColumn::MEDIA_TIME_PENDING, 0);
326 NativeRdb::AbsRdbPredicates predicates = NativeRdb::AbsRdbPredicates(PhotoColumn::PHOTOS_TABLE);
327 predicates.In(PhotoColumn::MEDIA_FILE_PATH, filePahts);
328 int32_t changeRows = -1;
329
330 int32_t errCode = rdbStore->Update(changeRows, values, predicates);
331 CHECK_AND_RETURN_RET_LOG((errCode == E_OK && changeRows > 0), E_HAS_DB_ERROR,
332 "BatchUpdateTimePending: update time_pending failed. errCode: %{public}d, updateRows: %{public}d", errCode,
333 changeRows);
334 return E_OK;
335 }
336
UpdatePhotoAlbum(RestoreTaskInfo & restoreTaskInfo,FileInfo fileInfo)337 int32_t PhotoCustomRestoreOperation::UpdatePhotoAlbum(RestoreTaskInfo &restoreTaskInfo, FileInfo fileInfo)
338 {
339 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
340 CHECK_AND_RETURN_RET(rdbStore != nullptr, E_HAS_DB_ERROR);
341 const string querySql = "SELECT " + MediaColumn::MEDIA_ID + "," + PhotoColumn::PHOTO_OWNER_ALBUM_ID + " FROM " +
342 PhotoColumn::PHOTOS_TABLE + " WHERE data ='" + fileInfo.filePath + "';";
343 auto resultSet = rdbStore->QuerySql(querySql);
344 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "execute select unique number failed.");
345
346 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
347 MEDIA_ERR_LOG("execute GoToFirstRow err.");
348 resultSet->Close();
349 return E_HAS_DB_ERROR;
350 }
351 int32_t fileId = GetInt32Val(PhotoColumn::MEDIA_ID, resultSet);
352 int32_t albumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
353 resultSet->Close();
354 restoreTaskInfo.firstFileId = fileId;
355 string extrUri = MediaFileUtils::GetExtraUri(fileInfo.displayName, fileInfo.filePath);
356 restoreTaskInfo.firstFileUri = MediaFileUtils::GetUriByExtrConditions(
357 ML_FILE_URI_PREFIX + MediaFileUri::GetMediaTypeUri(fileInfo.mediaType, MEDIA_API_VERSION_V10) + "/",
358 to_string(fileId),
359 extrUri);
360 if (restoreTaskInfo.uriType == RESTORE_URI_TYPE_PHOTO) {
361 restoreTaskInfo.uri = restoreTaskInfo.firstFileUri;
362 } else {
363 restoreTaskInfo.uri = PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(albumId);
364 }
365 restoreTaskInfo.albumId = albumId;
366 return E_OK;
367 }
368
SendPhotoAlbumNotify(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType,const UniqueNumber & uniqueNumber)369 void PhotoCustomRestoreOperation::SendPhotoAlbumNotify(RestoreTaskInfo &restoreTaskInfo, int32_t notifyType,
370 const UniqueNumber &uniqueNumber)
371 {
372 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
373 if (uniqueNumber.imageTotalNumber > 0) {
374 MediaLibraryRdbUtils::UpdateSystemAlbumInternal(rdbStore, {to_string(PhotoAlbumSubType::IMAGE)});
375 }
376 if (uniqueNumber.videoTotalNumber > 0) {
377 MediaLibraryRdbUtils::UpdateSystemAlbumInternal(rdbStore, {to_string(PhotoAlbumSubType::VIDEO)});
378 }
379 std::string uri = PhotoColumn::PHOTO_URI_PREFIX + to_string(restoreTaskInfo.firstFileId);
380 MediaLibraryRdbUtils::UpdateSourceAlbumByUri(rdbStore, {uri});
381 MEDIA_DEBUG_LOG("UpdateSourceAlbumByUri finished.");
382 auto watch = MediaLibraryNotify::GetInstance();
383 CHECK_AND_RETURN_LOG(watch != nullptr, "Can not get MediaLibraryNotify Instance");
384 if (notifyType == NOTIFY_FIRST) {
385 watch->Notify(restoreTaskInfo.firstFileUri, NOTIFY_ADD);
386 } else {
387 watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NOTIFY_ADD);
388 }
389 std::string albumUri =
390 MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(restoreTaskInfo.albumId));
391 watch->Notify(albumUri, NotifyType::NOTIFY_UPDATE);
392 watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NotifyType::NOTIFY_ALBUM_ADD_ASSET, restoreTaskInfo.albumId);
393 if (uniqueNumber.imageTotalNumber > 0) {
394 watch->Notify(restoreTaskInfo.imageAlbumUri, NotifyType::NOTIFY_UPDATE);
395 watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NotifyType::NOTIFY_ALBUM_ADD_ASSET, restoreTaskInfo.imageAlbumId);
396 }
397 if (uniqueNumber.videoTotalNumber > 0) {
398 watch->Notify(restoreTaskInfo.videoAlbumUri, NotifyType::NOTIFY_UPDATE);
399 watch->Notify(PhotoColumn::PHOTO_URI_PREFIX, NotifyType::NOTIFY_ALBUM_ADD_ASSET, restoreTaskInfo.videoAlbumId);
400 }
401 MEDIA_DEBUG_LOG("PhotoAlbumNotify finished.");
402 }
403
GenerateCustomRestoreNotify(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType)404 InnerRestoreResult PhotoCustomRestoreOperation::GenerateCustomRestoreNotify(
405 RestoreTaskInfo &restoreTaskInfo, int32_t notifyType)
406 {
407 InnerRestoreResult restoreResult;
408 restoreResult.errCode = 0;
409 restoreResult.stage = (notifyType == NOTIFY_LAST || notifyType == NOTIFY_CANCEL) ? "finished" : "onRestore";
410 restoreResult.uriType = restoreTaskInfo.uriType;
411 restoreResult.uri = restoreTaskInfo.uri;
412 restoreResult.totalNum = restoreTaskInfo.totalNum;
413 if (restoreTaskInfo.totalNum == 0) {
414 restoreResult.successNum = 0;
415 restoreResult.failedNum = 0;
416 restoreResult.sameNum = 0;
417 restoreResult.progress = 0;
418 return restoreResult;
419 }
420 restoreResult.successNum = successNum_;
421 restoreResult.sameNum = sameNum_;
422 if (notifyType == NOTIFY_LAST) {
423 restoreResult.failedNum = restoreTaskInfo.totalNum - restoreResult.successNum - restoreResult.sameNum;
424 } else {
425 restoreResult.failedNum = failNum_;
426 }
427 restoreResult.cancelNum = 0;
428 if (notifyType == NOTIFY_CANCEL) {
429 restoreResult.cancelNum =
430 restoreResult.totalNum - restoreResult.successNum - restoreResult.sameNum - restoreResult.failedNum;
431 }
432 restoreResult.progress = PROGRESS_MULTI_NUM *
433 (restoreResult.successNum + restoreResult.failedNum + restoreResult.sameNum) /
434 restoreTaskInfo.totalNum;
435 return restoreResult;
436 }
437
SendNotifyMessage(RestoreTaskInfo & restoreTaskInfo,int32_t notifyType,int32_t errCode,int32_t fileNum,const UniqueNumber & uniqueNumber)438 void PhotoCustomRestoreOperation::SendNotifyMessage(
439 RestoreTaskInfo &restoreTaskInfo, int32_t notifyType, int32_t errCode, int32_t fileNum,
440 const UniqueNumber &uniqueNumber)
441 {
442 // notify album
443 if (errCode == E_OK && successNum_ > 0) {
444 SendPhotoAlbumNotify(restoreTaskInfo, notifyType, uniqueNumber);
445 }
446 if (errCode != E_OK) {
447 failNum_.fetch_add(fileNum);
448 }
449 InnerRestoreResult restoreResult = GenerateCustomRestoreNotify(restoreTaskInfo, notifyType);
450 if (notifyType == NOTIFY_FIRST && errCode != E_OK) {
451 restoreResult.stage = "finished";
452 restoreResult.errCode = 1;
453 restoreResult.progress = 0;
454 restoreResult.uri = "";
455 }
456 MEDIA_DEBUG_LOG("CustomRestoreNotify stage:%{public}s errCode:%{public}d progress:%{public}d",
457 restoreResult.stage.c_str(), restoreResult.errCode, restoreResult.progress);
458 MEDIA_DEBUG_LOG(
459 "CustomRestoreNotify totalNum:%{public}d successNum:%{public}d failedNum:%{public}d sameNum:%{public}d",
460 restoreResult.totalNum, restoreResult.successNum, restoreResult.failedNum, restoreResult.sameNum);
461 CustomRestoreNotify customRestoreNotify;
462 customRestoreNotify.Notify(restoreTaskInfo.keyPath, restoreResult);
463 }
464
SetDestinationPath(vector<FileInfo> & restoreFiles,UniqueNumber & uniqueNumber)465 vector<FileInfo> PhotoCustomRestoreOperation::SetDestinationPath(
466 vector<FileInfo> &restoreFiles, UniqueNumber &uniqueNumber)
467 {
468 vector<FileInfo> newRestoreFiles;
469 for (auto &fileInfo : restoreFiles) {
470 string mediaDirPath;
471 int32_t mediaType = fileInfo.mediaType;
472 GetAssetRootDir(mediaType, mediaDirPath);
473 if (mediaDirPath.empty()) {
474 MEDIA_ERR_LOG("get asset root dir failed. mediaType: %{public}d", mediaType);
475 continue;
476 }
477 int32_t fileId = 0;
478 if (fileInfo.mediaType == MediaType::MEDIA_TYPE_IMAGE) {
479 fileId = uniqueNumber.imageCurrentNumber++;
480 } else if (fileInfo.mediaType == MediaType::MEDIA_TYPE_VIDEO) {
481 fileId = uniqueNumber.videoCurrentNumber++;
482 }
483
484 int32_t bucketNum = 0;
485 int32_t retCode = MediaFileUri::CreateAssetBucket(fileId, bucketNum);
486 if (retCode != E_OK) {
487 MEDIA_ERR_LOG("CreateAssetBucket failed. bucketNum: %{public}d", bucketNum);
488 continue;
489 }
490
491 string realName;
492 retCode = MediaFileUtils::CreateAssetRealName(fileId, fileInfo.mediaType, fileInfo.extension, realName);
493 if (retCode != E_OK) {
494 MEDIA_ERR_LOG("CreateAssetRealName failed. retCode: %{public}d", retCode);
495 continue;
496 }
497 string dirPath = ROOT_MEDIA_DIR + mediaDirPath + to_string(bucketNum);
498 if (!MediaFileUtils::IsFileExists(dirPath)) {
499 if (!MediaFileUtils::CreateDirectory(dirPath)) {
500 MEDIA_ERR_LOG("CreateDirectory failed. retCode: %{public}s", dirPath.c_str());
501 continue;
502 }
503 }
504 fileInfo.filePath = dirPath + "/" + realName;
505 fileInfo.fileId = fileId;
506 newRestoreFiles.push_back(fileInfo);
507 }
508 return newRestoreFiles;
509 }
510
GetAssetRootDir(int32_t mediaType,string & rootDirPath)511 void PhotoCustomRestoreOperation::GetAssetRootDir(int32_t mediaType, string &rootDirPath)
512 {
513 map<int, string> rootDir = {
514 {MEDIA_TYPE_FILE, DOCUMENT_BUCKET + SLASH_CHAR},
515 {MEDIA_TYPE_VIDEO, PHOTO_BUCKET + SLASH_CHAR},
516 {MEDIA_TYPE_IMAGE, PHOTO_BUCKET + SLASH_CHAR},
517 {MEDIA_TYPE_AUDIO, AUDIO_BUCKET + SLASH_CHAR},
518 };
519 if (rootDir.count(mediaType) == 0) {
520 rootDirPath = rootDir[MEDIA_TYPE_FILE];
521 } else {
522 rootDirPath = rootDir[mediaType];
523 }
524 }
525
BatchInsert(RestoreTaskInfo & restoreTaskInfo,vector<FileInfo> & restoreFiles,int32_t & sameFileNum)526 vector<FileInfo> PhotoCustomRestoreOperation::BatchInsert(
527 RestoreTaskInfo &restoreTaskInfo, vector<FileInfo> &restoreFiles, int32_t &sameFileNum)
528 {
529 vector<FileInfo> insertFiles;
530 vector<NativeRdb::ValuesBucket> values;
531 for (auto &fileInfo : restoreFiles) {
532 NativeRdb::ValuesBucket value = GetInsertValue(restoreTaskInfo, fileInfo);
533 if (!IsDuplication(restoreTaskInfo, fileInfo)) {
534 values.push_back(value);
535 insertFiles.push_back(fileInfo);
536 }
537 }
538 sameFileNum = static_cast<int32_t>(restoreFiles.size() - insertFiles.size());
539 sameNum_.fetch_add(sameFileNum);
540 MEDIA_DEBUG_LOG("BatchInsert values size: %{public}d, sameNum:%{public}d",
541 static_cast<int32_t>(values.size()), sameFileNum);
542 if (values.size() == 0) {
543 return insertFiles;
544 }
545 int64_t rowNum = 0;
546 int32_t errCode = E_ERR;
547 TransactionOperations trans{__func__};
548 std::function<int(void)> func = [&]() -> int {
549 errCode = trans.BatchInsert(rowNum, PhotoColumn::PHOTOS_TABLE, values);
550 CHECK_AND_PRINT_LOG(errCode == E_OK, "BatchInsert failed, errCode: %{public}d,"
551 " rowNum: %{public}" PRId64, errCode, rowNum);
552 return errCode;
553 };
554 errCode = trans.RetryTrans(func, false);
555 if (errCode != E_OK) {
556 insertFiles.clear();
557 MEDIA_ERR_LOG("RetryTrans: trans retry fail!, ret:%{public}d", errCode);
558 return insertFiles;
559 }
560 MEDIA_DEBUG_LOG("BatchInsert success rowNum: %{public}" PRId64, rowNum);
561 return insertFiles;
562 }
563
QueryAlbumId(RestoreTaskInfo & restoreTaskInfo)564 void PhotoCustomRestoreOperation::QueryAlbumId(RestoreTaskInfo &restoreTaskInfo)
565 {
566 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
567 CHECK_AND_RETURN_LOG(rdbStore != nullptr, "QueryAlbumId: get rdb store fail!");
568
569 const string queryAlbumPathSql =
570 "SELECT lpath from album_plugin WHERE (bundle_name = ? OR album_name = ?) AND priority = '1';";
571 std::vector<NativeRdb::ValueObject> albumPathParams = {restoreTaskInfo.bundleName, restoreTaskInfo.packageName};
572 auto albumPathResult = rdbStore->QuerySql(queryAlbumPathSql, albumPathParams);
573 string lpath;
574 if (albumPathResult == nullptr) {
575 MEDIA_ERR_LOG("QueryAlbumId: query album_plugin failed!");
576 } else if (albumPathResult->GoToFirstRow() != NativeRdb::E_OK) {
577 MEDIA_WARN_LOG("QueryAlbumId: album_plugin have no record!");
578 albumPathResult->Close();
579 } else {
580 lpath = GetStringVal("lpath", albumPathResult);
581 albumPathResult->Close();
582 }
583 if (lpath.empty()) {
584 lpath = ALBUM_PATH_PREFIX + restoreTaskInfo.packageName;
585 }
586
587 const string querySql = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " + PhotoAlbumColumns::TABLE + " WHERE " +
588 PhotoAlbumColumns::ALBUM_LPATH + " = ? ;";
589 std::vector<NativeRdb::ValueObject> params = {lpath};
590 auto resultSet = rdbStore->QuerySql(querySql, params);
591 CHECK_AND_RETURN_LOG(resultSet != nullptr, "QueryAlbumId: query PhotoAlbum failed!");
592
593 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
594 MEDIA_WARN_LOG("album is not exits, skip check duplication.");
595 restoreTaskInfo.isDeduplication = false;
596 resultSet->Close();
597 return;
598 }
599 int32_t albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
600 resultSet->Close();
601 if (albumId > 0) {
602 restoreTaskInfo.albumId = albumId;
603 MEDIA_ERR_LOG("QueryAlbumId albumId:%{public}d", albumId);
604 InitPhotoCache(restoreTaskInfo);
605 }
606 }
607
GetAlbumInfoBySubType(int32_t subType,string & albumUri,int32_t & albumId)608 int32_t PhotoCustomRestoreOperation::GetAlbumInfoBySubType(int32_t subType, string &albumUri, int32_t &albumId)
609 {
610 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
611 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "GetAlbumInfoBySubType: get rdb store fail!");
612
613 const string querySql = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " + PhotoAlbumColumns::TABLE + " WHERE " +
614 PhotoAlbumColumns::ALBUM_SUBTYPE + " = ? ;";
615 std::vector<NativeRdb::ValueObject> params = {subType};
616 auto resultSet = rdbStore->QuerySql(querySql, params);
617 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR,
618 "GetAlbumInfoBySubType: query PhotoAlbum failed! subType=%{public}d", subType);
619
620 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
621 MEDIA_ERR_LOG("GetAlbumInfoBySubType first row empty.");
622 resultSet->Close();
623 return E_HAS_DB_ERROR;
624 }
625 albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
626 resultSet->Close();
627 albumUri = MediaFileUtils::GetUriByExtrConditions(PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(albumId));
628 return E_OK;
629 }
630
IsDuplication(RestoreTaskInfo & restoreTaskInfo,FileInfo & fileInfo)631 bool PhotoCustomRestoreOperation::IsDuplication(RestoreTaskInfo &restoreTaskInfo, FileInfo &fileInfo)
632 {
633 bool cond = (!restoreTaskInfo.isDeduplication || restoreTaskInfo.albumId == 0);
634 CHECK_AND_RETURN_RET(!cond, false);
635 int32_t mediaType = fileInfo.mediaType;
636 if (restoreTaskInfo.hasPhotoCache) {
637 string photoId = fileInfo.fileName + "_" + to_string(fileInfo.size) + "_" + to_string(mediaType) + "_" +
638 to_string(fileInfo.orientation);
639 return photoCache_.count(photoId) > 0;
640 }
641
642 const string querySql =
643 "SELECT COUNT(1) as count FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " + PhotoColumn::PHOTO_OWNER_ALBUM_ID +
644 "=" + to_string(restoreTaskInfo.albumId) + " AND " + MediaColumn::MEDIA_NAME + "='" + fileInfo.fileName +
645 "' AND " + MediaColumn::MEDIA_SIZE + "=" + to_string(fileInfo.size) + " AND " + MediaColumn::MEDIA_TYPE + "=" +
646 to_string(mediaType) + " AND " + PhotoColumn::PHOTO_ORIENTATION + "=" + to_string(fileInfo.orientation) + ";";
647 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
648 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, false, "IsDuplication: get rdb store fail!");
649
650 auto resultSet = rdbStore->QuerySql(querySql);
651 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, false, "IsDuplication: query PhotoAlbum failed!");
652 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
653 MEDIA_ERR_LOG("IsDuplication first row empty.");
654 resultSet->Close();
655 return false;
656 }
657 int32_t count = GetInt32Val("count", resultSet);
658 resultSet->Close();
659 return count > 0;
660 }
661
InitPhotoCache(RestoreTaskInfo & restoreTaskInfo)662 int32_t PhotoCustomRestoreOperation::InitPhotoCache(RestoreTaskInfo &restoreTaskInfo)
663 {
664 bool cond = (!restoreTaskInfo.isDeduplication || restoreTaskInfo.albumId == 0);
665 CHECK_AND_RETURN_RET(!cond, E_OK);
666 MEDIA_INFO_LOG("InitPhotoCache begin, albumId: %{public}d", restoreTaskInfo.albumId);
667 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
668 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "InitPhotoCache: get rdb store fail!");
669
670 const string queryCountSql = "SELECT COUNT(1) as count FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " +
671 PhotoColumn::PHOTO_OWNER_ALBUM_ID + "=" + to_string(restoreTaskInfo.albumId) + ";";
672 auto resultSet = rdbStore->QuerySql(queryCountSql);
673 CHECK_AND_RETURN_RET_LOG(resultSet != nullptr, E_HAS_DB_ERROR, "InitPhotoCache: get resultSet fail!");
674 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
675 MEDIA_ERR_LOG("InitPhotoCache first row empty.");
676 resultSet->Close();
677 return E_HAS_DB_ERROR;
678 }
679
680 int32_t count = GetInt32Val("count", resultSet);
681 resultSet->Close();
682 if (count > MAX_PHOTO_CACHE_NUM) {
683 MEDIA_WARN_LOG("album has more than %{public}d, skip create cache.", MAX_PHOTO_CACHE_NUM);
684 return E_OK;
685 }
686 const string queryCacheSql = "SELECT " + MediaColumn::MEDIA_NAME + "," + MediaColumn::MEDIA_SIZE + "," +
687 MediaColumn::MEDIA_TYPE + "," + PhotoColumn::PHOTO_ORIENTATION + " FROM " +
688 PhotoColumn::PHOTOS_TABLE + " WHERE " + PhotoColumn::PHOTO_OWNER_ALBUM_ID + "=" +
689 to_string(restoreTaskInfo.albumId) + ";";
690 auto resultCacheSet = rdbStore->QuerySql(queryCacheSql);
691 CHECK_AND_RETURN_RET(resultCacheSet != nullptr, E_HAS_DB_ERROR);
692
693 while (resultCacheSet->GoToNextRow() == NativeRdb::E_OK) {
694 string displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultCacheSet);
695 int64_t mediaSize = GetInt64Val(MediaColumn::MEDIA_SIZE, resultCacheSet);
696 int32_t mediaType = GetInt32Val(MediaColumn::MEDIA_TYPE, resultCacheSet);
697 int32_t orientation = GetInt32Val(PhotoColumn::PHOTO_ORIENTATION, resultCacheSet);
698 photoCache_.insert(
699 displayName + "_" + to_string(mediaSize) + "_" + to_string(mediaType) + "_" + to_string(orientation));
700 }
701 resultCacheSet->Close();
702 restoreTaskInfo.hasPhotoCache = true;
703 MEDIA_INFO_LOG("InitPhotoCache success, num:%{public}d", static_cast<int32_t>(photoCache_.size()));
704 return E_OK;
705 }
706
UpdateUniqueNumber(UniqueNumber & uniqueNumber)707 int32_t PhotoCustomRestoreOperation::UpdateUniqueNumber(UniqueNumber &uniqueNumber)
708 {
709 int32_t errCode = MediaLibraryAssetOperations::CreateAssetUniqueIds(
710 MediaType::MEDIA_TYPE_IMAGE, uniqueNumber.imageTotalNumber, uniqueNumber.imageCurrentNumber);
711 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "CreateAssetUniqueNumber IMAGE fail!, ret:%{public}d", errCode);
712
713 MEDIA_DEBUG_LOG("imageTotalNumber: %{public}d imageCurrentNumber: %{public}d",
714 uniqueNumber.imageTotalNumber, uniqueNumber.imageCurrentNumber);
715 errCode = MediaLibraryAssetOperations::CreateAssetUniqueIds(
716 MediaType::MEDIA_TYPE_VIDEO, uniqueNumber.videoTotalNumber, uniqueNumber.videoCurrentNumber);
717 CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "CreateAssetUniqueNumber VIDEO fail!, ret:%{public}d", errCode);
718 MEDIA_DEBUG_LOG("videoTotalNumber: %{public}d videoCurrentNumber: %{public}d",
719 uniqueNumber.videoTotalNumber, uniqueNumber.videoCurrentNumber);
720 return E_OK;
721 }
722
InsertDateTaken(std::unique_ptr<Metadata> & metadata,NativeRdb::ValuesBucket & value)723 static void InsertDateTaken(std::unique_ptr<Metadata> &metadata, NativeRdb::ValuesBucket &value)
724 {
725 int64_t dateTaken = metadata->GetDateTaken();
726 if (dateTaken != 0) {
727 value.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
728 value.PutString(PhotoColumn::PHOTO_DATE_YEAR,
729 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, dateTaken));
730 value.PutString(PhotoColumn::PHOTO_DATE_MONTH,
731 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, dateTaken));
732 value.PutString(PhotoColumn::PHOTO_DATE_DAY,
733 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, dateTaken));
734 return;
735 }
736 int64_t dateAdded = metadata->GetFileDateAdded();
737 if (dateAdded == 0) {
738 int64_t dateModified = metadata->GetFileDateModified();
739 if (dateModified == 0) {
740 dateTaken = MediaFileUtils::UTCTimeMilliSeconds();
741 } else {
742 dateTaken = dateModified;
743 }
744 } else {
745 dateTaken = dateAdded;
746 }
747 value.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
748 value.PutString(PhotoColumn::PHOTO_DATE_YEAR,
749 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, dateTaken));
750 value.PutString(PhotoColumn::PHOTO_DATE_MONTH,
751 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, dateTaken));
752 value.PutString(PhotoColumn::PHOTO_DATE_DAY,
753 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, dateTaken));
754 }
755
GetInsertValue(RestoreTaskInfo & restoreTaskInfo,FileInfo & fileInfo)756 NativeRdb::ValuesBucket PhotoCustomRestoreOperation::GetInsertValue(
757 RestoreTaskInfo &restoreTaskInfo, FileInfo &fileInfo)
758 {
759 NativeRdb::ValuesBucket value;
760 value.PutString(MediaColumn::MEDIA_FILE_PATH, fileInfo.filePath);
761 value.PutString(MediaColumn::MEDIA_TITLE, fileInfo.title);
762 value.PutString(MediaColumn::MEDIA_NAME, fileInfo.displayName);
763 int32_t subType = fileInfo.isLivePhoto ? static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)
764 : static_cast<int32_t>(PhotoSubType::DEFAULT);
765 value.PutInt(PhotoColumn::PHOTO_SUBTYPE, subType);
766 value.PutString(MediaColumn::MEDIA_PACKAGE_NAME, restoreTaskInfo.packageName);
767 value.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, restoreTaskInfo.bundleName);
768 value.PutString(MediaColumn::MEDIA_OWNER_APPID, restoreTaskInfo.appId);
769 std::unique_ptr<Metadata> data = make_unique<Metadata>();
770 data->SetFilePath(fileInfo.originFilePath);
771 data->SetFileName(fileInfo.fileName);
772 data->SetFileMediaType(fileInfo.mediaType);
773 FillMetadata(data);
774 fileInfo.size = data->GetFileSize();
775 fileInfo.orientation = data->GetOrientation();
776 InsertDateTaken(data, value);
777 value.PutLong(MediaColumn::MEDIA_DATE_ADDED, MediaFileUtils::UTCTimeMilliSeconds());
778 value.PutInt(PhotoColumn::PHOTO_ORIENTATION, data->GetOrientation());
779 value.PutString(MediaColumn::MEDIA_FILE_PATH, data->GetFilePath());
780 value.PutString(MediaColumn::MEDIA_MIME_TYPE, data->GetFileMimeType());
781 value.PutString(PhotoColumn::PHOTO_MEDIA_SUFFIX, data->GetFileExtension());
782 value.PutInt(MediaColumn::MEDIA_TYPE, fileInfo.mediaType);
783 value.PutString(MediaColumn::MEDIA_TITLE, data->GetFileTitle());
784 value.PutLong(MediaColumn::MEDIA_SIZE, data->GetFileSize());
785 value.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, data->GetFileDateModified());
786 value.PutInt(MediaColumn::MEDIA_DURATION, data->GetFileDuration());
787 value.PutLong(MediaColumn::MEDIA_TIME_PENDING, 0);
788 value.PutInt(PhotoColumn::PHOTO_HEIGHT, data->GetFileHeight());
789 value.PutInt(PhotoColumn::PHOTO_WIDTH, data->GetFileWidth());
790 value.PutDouble(PhotoColumn::PHOTO_LONGITUDE, data->GetLongitude());
791 value.PutDouble(PhotoColumn::PHOTO_LATITUDE, data->GetLatitude());
792 value.PutString(PhotoColumn::PHOTO_ALL_EXIF, data->GetAllExif());
793 value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE, data->GetShootingMode());
794 value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE_TAG, data->GetShootingModeTag());
795 value.PutLong(PhotoColumn::PHOTO_LAST_VISIT_TIME, data->GetLastVisitTime());
796 value.PutString(PhotoColumn::PHOTO_FRONT_CAMERA, data->GetFrontCamera());
797 value.PutInt(PhotoColumn::PHOTO_DYNAMIC_RANGE_TYPE, data->GetDynamicRangeType());
798 value.PutString(PhotoColumn::PHOTO_USER_COMMENT, data->GetUserComment());
799 value.PutInt(PhotoColumn::PHOTO_QUALITY, 0);
800 value.PutString(PhotoColumn::PHOTO_DETAIL_TIME, data->GetDetailTime());
801 return value;
802 }
803
GetFileInfos(vector<string> & filePathVector,UniqueNumber & uniqueNumber)804 vector<FileInfo> PhotoCustomRestoreOperation::GetFileInfos(vector<string> &filePathVector, UniqueNumber &uniqueNumber)
805 {
806 vector<FileInfo> restoreFiles;
807 for (auto &filePath : filePathVector) {
808 FileInfo fileInfo;
809 fileInfo.fileName = MediaFileUtils::GetFileName(filePath);
810 fileInfo.displayName = fileInfo.fileName;
811 fileInfo.originFilePath = filePath;
812 fileInfo.extension = ScannerUtils::GetFileExtension(fileInfo.fileName);
813 fileInfo.title = ScannerUtils::GetFileTitle(fileInfo.fileName);
814 fileInfo.mediaType = MediaFileUtils::GetMediaType(fileInfo.fileName);
815 fileInfo.isLivePhoto = MovingPhotoFileUtils::IsLivePhoto(filePath);
816 if (fileInfo.mediaType == MediaType::MEDIA_TYPE_FILE) {
817 fileInfo.mediaType = MediaFileUtils::GetMediaTypeNotSupported(fileInfo.fileName);
818 if (fileInfo.mediaType == MediaType::MEDIA_TYPE_IMAGE ||
819 fileInfo.mediaType == MediaType::MEDIA_TYPE_VIDEO) {
820 MEDIA_WARN_LOG("media type not support, fileName is %{private}s", fileInfo.fileName.c_str());
821 }
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::GetMimeTypeFromExtension(extension);
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 " = ? 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(vector<FileInfo> & restoreFiles)890 int32_t PhotoCustomRestoreOperation::RenameFiles(vector<FileInfo> &restoreFiles)
891 {
892 int32_t renameNum = 0;
893 for (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