1 /*
2 * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define MLOG_TAG "MediaLibraryBaseRestore"
17
18 #include "base_restore.h"
19
20 #include <sstream>
21
22 #include "application_context.h"
23 #include "backup_database_utils.h"
24 #include "backup_dfx_utils.h"
25 #include "backup_file_utils.h"
26 #include "backup_log_utils.h"
27 #include "directory_ex.h"
28 #include "extension_context.h"
29 #include "media_column.h"
30 #include "media_log.h"
31 #include "media_file_utils.h"
32 #include "media_scanner_manager.h"
33 #include "medialibrary_asset_operations.h"
34 #include "medialibrary_data_manager.h"
35 #include "medialibrary_object_utils.h"
36 #include "medialibrary_rdb_utils.h"
37 #include "medialibrary_type_const.h"
38 #include "medialibrary_errno.h"
39 #include "metadata.h"
40 #include "moving_photo_file_utils.h"
41 #include "parameters.h"
42 #include "photo_album_column.h"
43 #include "result_set_utils.h"
44 #include "userfilemgr_uri.h"
45 #include "medialibrary_notify.h"
46 #include "upgrade_restore_task_report.h"
47 #include "medialibrary_rdb_transaction.h"
48 #include "database_report.h"
49
50 namespace OHOS {
51 namespace Media {
52 const std::string DATABASE_PATH = "/data/storage/el2/database/rdb/media_library.db";
53 const std::string SINGLE_DIR_NAME = "A";
54 const std::string CLONE_FLAG = "multimedia.medialibrary.cloneFlag";
55
StartRestore(const std::string & backupRetoreDir,const std::string & upgradePath)56 void BaseRestore::StartRestore(const std::string &backupRetoreDir, const std::string &upgradePath)
57 {
58 backupRestoreDir_ = backupRetoreDir;
59 int32_t errorCode = Init(backupRetoreDir, upgradePath, true);
60 if (errorCode == E_OK) {
61 RestorePhoto();
62 RestoreAudio();
63 MEDIA_INFO_LOG("migrate database number: %{public}lld, file number: %{public}lld (%{public}lld + "
64 "%{public}lld), duplicate number: %{public}lld + %{public}lld, audio database number:%{public}lld, "
65 "audio file number:%{public}lld, duplicate audio number: %{public}lld, map number: %{public}lld",
66 (long long)migrateDatabaseNumber_, (long long)migrateFileNumber_,
67 (long long)(migrateFileNumber_ - migrateVideoFileNumber_), (long long)migrateVideoFileNumber_,
68 (long long)migratePhotoDuplicateNumber_, (long long)migrateVideoDuplicateNumber_,
69 (long long)migrateAudioDatabaseNumber_, (long long)migrateAudioFileNumber_,
70 (long long)migrateAudioDuplicateNumber_, (long long) migrateDatabaseMapNumber_);
71 UpdateDatabase();
72 } else {
73 if (errorCode != EXTERNAL_DB_NOT_EXIST) {
74 SetErrorCode(RestoreError::INIT_FAILED);
75 }
76 ErrorInfo errorInfo(RestoreError::INIT_FAILED, 0, errorCode);
77 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
78 }
79 HandleRestData();
80 }
81
Init(void)82 int32_t BaseRestore::Init(void)
83 {
84 if (mediaLibraryRdb_ != nullptr) {
85 return E_OK;
86 }
87 auto context = AbilityRuntime::Context::GetApplicationContext();
88 if (context == nullptr) {
89 MEDIA_ERR_LOG("Failed to get context");
90 return E_FAIL;
91 }
92 int32_t err = BackupDatabaseUtils::InitDb(mediaLibraryRdb_, MEDIA_DATA_ABILITY_DB_NAME, DATABASE_PATH, BUNDLE_NAME,
93 true, context->GetArea());
94 if (err != E_OK) {
95 MEDIA_ERR_LOG("medialibrary rdb fail, err = %{public}d", err);
96 return E_FAIL;
97 }
98 int32_t sceneCode = 0;
99 int32_t errCode = MediaLibraryDataManager::GetInstance()->InitMediaLibraryMgr(context, nullptr, sceneCode);
100 if (errCode != E_OK) {
101 MEDIA_ERR_LOG("When restore, InitMediaLibraryMgr fail, errcode = %{public}d", errCode);
102 return errCode;
103 }
104 migrateDatabaseNumber_ = 0;
105 migrateFileNumber_ = 0;
106 migrateVideoFileNumber_ = 0;
107 migrateAudioDatabaseNumber_ = 0;
108 migrateAudioFileNumber_ = 0;
109 imageNumber_ = BackupDatabaseUtils::QueryUniqueNumber(mediaLibraryRdb_, IMAGE_ASSET_TYPE);
110 videoNumber_ = BackupDatabaseUtils::QueryUniqueNumber(mediaLibraryRdb_, VIDEO_ASSET_TYPE);
111 audioNumber_ = BackupDatabaseUtils::QueryUniqueNumber(mediaLibraryRdb_, AUDIO_ASSET_TYPE);
112 MEDIA_INFO_LOG("imageNumber: %{public}d", (int)imageNumber_);
113 MEDIA_INFO_LOG("videoNumber: %{public}d", (int)videoNumber_);
114 MEDIA_INFO_LOG("audioNumber: %{public}d", (int)audioNumber_);
115 return E_OK;
116 }
117
ConvertPathToRealPath(const std::string & srcPath,const std::string & prefix,std::string & newPath,std::string & relativePath)118 bool BaseRestore::ConvertPathToRealPath(const std::string &srcPath, const std::string &prefix,
119 std::string &newPath, std::string &relativePath)
120 {
121 size_t pos = 0;
122 int32_t count = 0;
123 constexpr int32_t prefixLevel = 4;
124 for (size_t i = 0; i < srcPath.length(); i++) {
125 if (srcPath[i] == '/') {
126 count++;
127 if (count == prefixLevel) {
128 pos = i;
129 break;
130 }
131 }
132 }
133 if (count < prefixLevel) {
134 return false;
135 }
136 relativePath = srcPath.substr(pos);
137 if (!dualDirName_.empty() && relativePath.find(dualDirName_) != string::npos) {
138 std::size_t posStart = relativePath.find_first_of("/");
139 std::size_t posEnd = relativePath.find_first_of("/", posStart + 1);
140 if (posEnd != string::npos) {
141 string temp = relativePath.substr(posStart + 1, posEnd - posStart -1);
142 if (temp == dualDirName_) {
143 relativePath.replace(relativePath.find(dualDirName_), dualDirName_.length(), SINGLE_DIR_NAME);
144 }
145 }
146 }
147 std::string extraPrefix = BackupFileUtils::GetExtraPrefixForRealPath(sceneCode_, srcPath);
148 newPath = prefix + extraPrefix + relativePath;
149 return true;
150 }
151
QuerySql(const string & sql,const vector<string> & selectionArgs) const152 shared_ptr<NativeRdb::ResultSet> BaseRestore::QuerySql(const string &sql, const vector<string> &selectionArgs) const
153 {
154 if (mediaLibraryRdb_ == nullptr) {
155 MEDIA_ERR_LOG("Pointer rdb_ is nullptr. Maybe it didn't init successfully.");
156 return nullptr;
157 }
158
159 return mediaLibraryRdb_->QuerySql(sql, selectionArgs);
160 }
161
MoveFile(const std::string & srcFile,const std::string & dstFile) const162 int32_t BaseRestore::MoveFile(const std::string &srcFile, const std::string &dstFile) const
163 {
164 int32_t errCode = BackupFileUtils::MoveFile(srcFile, dstFile, sceneCode_);
165 if (errCode == E_SUCCESS) {
166 return E_OK;
167 }
168 if (this->CopyFile(srcFile, dstFile) != E_OK) {
169 return E_FAIL;
170 }
171 (void)MediaFileUtils::DeleteFile(srcFile);
172 return E_OK;
173 }
174
CopyFile(const std::string & srcFile,const std::string & dstFile) const175 int32_t BaseRestore::CopyFile(const std::string &srcFile, const std::string &dstFile) const
176 {
177 if (!MediaFileUtils::CopyFileUtil(srcFile, dstFile)) {
178 MEDIA_ERR_LOG("CopyFile failed, src: %{public}s, dst: %{public}s, errMsg: %{public}s",
179 BackupFileUtils::GarbleFilePath(srcFile, sceneCode_).c_str(),
180 BackupFileUtils::GarbleFilePath(srcFile, DEFAULT_RESTORE_ID).c_str(), strerror(errno));
181 return E_FAIL;
182 }
183 return E_OK;
184 }
185
IsFileValid(FileInfo & fileInfo,const int32_t sceneCode)186 int32_t BaseRestore::IsFileValid(FileInfo &fileInfo, const int32_t sceneCode)
187 {
188 int32_t errCode = BackupFileUtils::IsFileValid(fileInfo.filePath, DUAL_FRAME_CLONE_RESTORE_ID,
189 fileInfo.relativePath, hasLowQualityImage_);
190 if (errCode != E_OK) {
191 MEDIA_ERR_LOG("File is not valid: %{public}s, errno=%{public}d.",
192 BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode).c_str(), errno);
193 return errCode;
194 }
195
196 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
197 if (!MediaFileUtils::IsFileValid(fileInfo.movingPhotoVideoPath)) {
198 MEDIA_ERR_LOG("Moving photo video is not valid: %{public}s, errno=%{public}d.",
199 BackupFileUtils::GarbleFilePath(fileInfo.movingPhotoVideoPath, sceneCode).c_str(), errno);
200 return E_FAIL;
201 }
202
203 if (!MediaFileUtils::IsFileValid(fileInfo.extraDataPath)) {
204 MEDIA_WARN_LOG("Media extra data is not valid: %{public}s, errno=%{public}d.",
205 BackupFileUtils::GarbleFilePath(fileInfo.extraDataPath, sceneCode).c_str(), errno);
206 return E_FAIL;
207 }
208 }
209 return E_OK;
210 }
211
RemoveDuplicateDualCloneFiles(const FileInfo & fileInfo)212 static void RemoveDuplicateDualCloneFiles(const FileInfo &fileInfo)
213 {
214 (void)MediaFileUtils::DeleteFile(fileInfo.filePath);
215 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
216 (void)MediaFileUtils::DeleteFile(fileInfo.movingPhotoVideoPath);
217 (void)MediaFileUtils::DeleteFile(fileInfo.extraDataPath);
218 }
219 }
220
GetInsertValues(const int32_t sceneCode,std::vector<FileInfo> & fileInfos,int32_t sourceType)221 vector<NativeRdb::ValuesBucket> BaseRestore::GetInsertValues(const int32_t sceneCode, std::vector<FileInfo> &fileInfos,
222 int32_t sourceType)
223 {
224 vector<NativeRdb::ValuesBucket> values;
225 for (size_t i = 0; i < fileInfos.size(); i++) {
226 int32_t errCode = IsFileValid(fileInfos[i], sceneCode);
227 if (errCode != E_OK) {
228 fileInfos[i].needMove = false;
229 std::string fileDbCheckInfo = CheckInvalidFile(fileInfos[i], errCode);
230 ErrorInfo errorInfo(RestoreError::FILE_INVALID, 1, std::to_string(errCode),
231 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i], { fileDbCheckInfo }));
232 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
233 continue;
234 }
235 std::string cloudPath;
236 int32_t uniqueId = GetUniqueId(fileInfos[i].fileType);
237 errCode = BackupFileUtils::CreateAssetPathById(uniqueId, fileInfos[i].fileType,
238 MediaFileUtils::GetExtensionFromPath(fileInfos[i].displayName), cloudPath);
239 if (errCode != E_OK) {
240 fileInfos[i].needMove = false;
241 ErrorInfo errorInfo(RestoreError::CREATE_PATH_FAILED, 1, std::to_string(errCode),
242 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i]));
243 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
244 continue;
245 }
246 fileInfos[i].cloudPath = cloudPath;
247 NativeRdb::ValuesBucket value = GetInsertValue(fileInfos[i], cloudPath, sourceType);
248 SetValueFromMetaData(fileInfos[i], value);
249 if ((sceneCode == DUAL_FRAME_CLONE_RESTORE_ID || sceneCode == OTHERS_PHONE_CLONE_RESTORE ||
250 sceneCode == I_PHONE_CLONE_RESTORE) && this->HasSameFileForDualClone(fileInfos[i])) {
251 fileInfos[i].needMove = false;
252 RemoveDuplicateDualCloneFiles(fileInfos[i]);
253 MEDIA_WARN_LOG("File %{public}s already exists.",
254 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str());
255 UpdateDuplicateNumber(fileInfos[i].fileType);
256 continue;
257 }
258 if (fileInfos[i].isNew) {
259 values.emplace_back(value);
260 }
261 }
262 return values;
263 }
264
InsertDateTaken(std::unique_ptr<Metadata> & metadata,FileInfo & fileInfo,NativeRdb::ValuesBucket & value)265 static void InsertDateTaken(std::unique_ptr<Metadata> &metadata, FileInfo &fileInfo, NativeRdb::ValuesBucket &value)
266 {
267 int64_t dateTaken = metadata->GetDateTaken();
268 if (dateTaken != 0) {
269 value.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
270 fileInfo.dateTaken = dateTaken;
271 return;
272 }
273
274 int64_t dateAdded = metadata->GetFileDateAdded();
275 if (dateAdded == 0) {
276 int64_t dateModified = metadata->GetFileDateModified();
277 if (dateModified == 0) {
278 dateTaken = MediaFileUtils::UTCTimeMilliSeconds();
279 } else {
280 dateTaken = dateModified;
281 }
282 } else {
283 dateTaken = dateAdded;
284 }
285 value.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
286 fileInfo.dateTaken = dateTaken;
287 }
288
InsertDateAdded(std::unique_ptr<Metadata> & metadata,NativeRdb::ValuesBucket & value)289 static void InsertDateAdded(std::unique_ptr<Metadata> &metadata, NativeRdb::ValuesBucket &value)
290 {
291 int64_t dateAdded = metadata->GetFileDateAdded();
292 if (dateAdded != 0) {
293 value.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
294 return;
295 }
296
297 int64_t dateTaken = metadata->GetDateTaken();
298 if (dateTaken == 0) {
299 int64_t dateModified = metadata->GetFileDateModified();
300 if (dateModified == 0) {
301 dateAdded = MediaFileUtils::UTCTimeMilliSeconds();
302 } else {
303 dateAdded = dateModified;
304 }
305 } else {
306 dateAdded = dateTaken;
307 }
308 value.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
309 }
310
InsertOrientation(std::unique_ptr<Metadata> & metadata,NativeRdb::ValuesBucket & value,FileInfo & fileInfo,int32_t sceneCode)311 static void InsertOrientation(std::unique_ptr<Metadata> &metadata, NativeRdb::ValuesBucket &value,
312 FileInfo &fileInfo, int32_t sceneCode)
313 {
314 bool hasOrientation = value.HasColumn(PhotoColumn::PHOTO_ORIENTATION);
315 if (hasOrientation && fileInfo.fileType != MEDIA_TYPE_VIDEO) {
316 return; // image use orientation in rdb
317 }
318 if (hasOrientation) {
319 value.Delete(PhotoColumn::PHOTO_ORIENTATION);
320 }
321 value.PutInt(PhotoColumn::PHOTO_ORIENTATION, metadata->GetOrientation()); // video use orientation in metadata
322 if (sceneCode == OTHERS_PHONE_CLONE_RESTORE || sceneCode == I_PHONE_CLONE_RESTORE) {
323 fileInfo.orientation = metadata->GetOrientation();
324 }
325 }
326
SetCoverPosition(const FileInfo & fileInfo,const unique_ptr<Metadata> & imageMetaData,NativeRdb::ValuesBucket & value)327 static void SetCoverPosition(const FileInfo &fileInfo,
328 const unique_ptr<Metadata> &imageMetaData, NativeRdb::ValuesBucket &value)
329 {
330 uint64_t coverPosition = 0;
331 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
332 uint32_t version = 0;
333 uint32_t frameIndex = 0;
334 bool hasCinemagraphInfo = false;
335 string absExtraDataPath;
336 if (!PathToRealPath(fileInfo.extraDataPath, absExtraDataPath)) {
337 MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d",
338 fileInfo.extraDataPath.c_str(), errno);
339 value.PutLong(PhotoColumn::PHOTO_COVER_POSITION, static_cast<int64_t>(coverPosition));
340 return;
341 }
342 UniqueFd extraDataFd(open(absExtraDataPath.c_str(), O_RDONLY));
343 (void)MovingPhotoFileUtils::GetVersionAndFrameNum(extraDataFd.Get(), version, frameIndex, hasCinemagraphInfo);
344 (void)MovingPhotoFileUtils::GetCoverPosition(fileInfo.movingPhotoVideoPath,
345 frameIndex, coverPosition, Scene::AV_META_SCENE_CLONE);
346 }
347 value.PutLong(PhotoColumn::PHOTO_COVER_POSITION, static_cast<int64_t>(coverPosition));
348 }
349
SetValueFromMetaData(FileInfo & fileInfo,NativeRdb::ValuesBucket & value)350 void BaseRestore::SetValueFromMetaData(FileInfo &fileInfo, NativeRdb::ValuesBucket &value)
351 {
352 std::unique_ptr<Metadata> data = make_unique<Metadata>();
353 data->SetFilePath(fileInfo.filePath);
354 data->SetFileMediaType(fileInfo.fileType);
355 data->SetFileDateModified(fileInfo.dateModified);
356 data->SetFileName(fileInfo.displayName);
357 BackupFileUtils::FillMetadata(data);
358 MediaType mediaType = data->GetFileMediaType();
359
360 value.PutString(MediaColumn::MEDIA_FILE_PATH, data->GetFilePath());
361 value.PutString(MediaColumn::MEDIA_MIME_TYPE, data->GetFileMimeType());
362 value.PutInt(MediaColumn::MEDIA_TYPE, mediaType);
363 value.PutString(MediaColumn::MEDIA_TITLE, data->GetFileTitle());
364 if (fileInfo.fileSize != 0) {
365 value.PutLong(MediaColumn::MEDIA_SIZE, fileInfo.fileSize);
366 } else {
367 MEDIA_WARN_LOG("DB file size is zero!");
368 value.PutLong(MediaColumn::MEDIA_SIZE, data->GetFileSize());
369 fileInfo.fileSize = data->GetFileSize();
370 }
371 value.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, data->GetFileDateModified());
372 value.PutInt(MediaColumn::MEDIA_DURATION, data->GetFileDuration());
373 InsertDateTaken(data, fileInfo, value);
374 value.PutLong(MediaColumn::MEDIA_TIME_PENDING, 0);
375 value.PutInt(PhotoColumn::PHOTO_HEIGHT, data->GetFileHeight());
376 value.PutInt(PhotoColumn::PHOTO_WIDTH, data->GetFileWidth());
377 value.PutDouble(PhotoColumn::PHOTO_LONGITUDE, data->GetLongitude());
378 value.PutDouble(PhotoColumn::PHOTO_LATITUDE, data->GetLatitude());
379 value.PutString(PhotoColumn::PHOTO_ALL_EXIF, data->GetAllExif());
380 value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE, data->GetShootingMode());
381 value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE_TAG, data->GetShootingModeTag());
382 value.PutLong(PhotoColumn::PHOTO_LAST_VISIT_TIME, data->GetLastVisitTime());
383 value.PutString(PhotoColumn::PHOTO_FRONT_CAMERA, data->GetFrontCamera());
384 value.PutInt(PhotoColumn::PHOTO_DYNAMIC_RANGE_TYPE, data->GetDynamicRangeType());
385 InsertDateAdded(data, value);
386 InsertOrientation(data, value, fileInfo, sceneCode_);
387 int64_t dateAdded = 0;
388 NativeRdb::ValueObject valueObject;
389 if (value.GetObject(MediaColumn::MEDIA_DATE_ADDED, valueObject)) {
390 valueObject.GetLong(dateAdded);
391 }
392 fileInfo.dateAdded = dateAdded;
393 value.PutString(PhotoColumn::PHOTO_DATE_YEAR,
394 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, fileInfo.dateTaken));
395 value.PutString(PhotoColumn::PHOTO_DATE_MONTH,
396 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, fileInfo.dateTaken));
397 value.PutString(PhotoColumn::PHOTO_DATE_DAY,
398 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, fileInfo.dateTaken));
399 SetCoverPosition(fileInfo, data, value);
400 }
401
CreateDir(std::string & dir)402 void BaseRestore::CreateDir(std::string &dir)
403 {
404 if (!MediaFileUtils::IsFileExists(dir)) {
405 MediaFileUtils::CreateDirectory(dir);
406 }
407 }
408
RecursiveCreateDir(std::string & relativePath,std::string & suffix)409 void BaseRestore::RecursiveCreateDir(std::string &relativePath, std::string &suffix)
410 {
411 CreateDir(relativePath);
412 size_t pos = suffix.find('/');
413 if (pos == std::string::npos) {
414 return;
415 }
416 std::string prefix = suffix.substr(0, pos + 1);
417 std::string suffixTmp = suffix.erase(0, prefix.length());
418 prefix = relativePath + prefix;
419 RecursiveCreateDir(prefix, suffixTmp);
420 }
421
InsertAudio(int32_t sceneCode,std::vector<FileInfo> & fileInfos)422 void BaseRestore::InsertAudio(int32_t sceneCode, std::vector<FileInfo> &fileInfos)
423 {
424 if (fileInfos.empty()) {
425 MEDIA_ERR_LOG("fileInfos are empty");
426 return;
427 }
428 int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
429 int32_t fileMoveCount = 0;
430 for (size_t i = 0; i < fileInfos.size(); i++) {
431 if (!MediaFileUtils::IsFileExists(fileInfos[i].filePath)) {
432 MEDIA_ERR_LOG("File is not exist: filePath: %{public}s, size: %{public}lld",
433 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str(),
434 (long long)fileInfos[i].fileSize);
435 continue;
436 }
437 string relativePath0 = RESTORE_MUSIC_LOCAL_DIR;
438 string relativePath1 = fileInfos[i].relativePath;
439 if (relativePath1[0] == '/') {
440 relativePath1.erase(0, 1);
441 }
442 string dstPath = RESTORE_MUSIC_LOCAL_DIR + relativePath1;
443 RecursiveCreateDir(relativePath0, relativePath1);
444 if (MediaFileUtils::IsFileExists(dstPath)) {
445 MEDIA_INFO_LOG("dstPath %{public}s already exists.",
446 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str());
447 UpdateDuplicateNumber(fileInfos[i].fileType);
448 continue;
449 }
450 int32_t moveErrCode = BackupFileUtils::MoveFile(fileInfos[i].filePath, dstPath, sceneCode);
451 if (moveErrCode != E_SUCCESS) {
452 MEDIA_ERR_LOG("MoveFile failed, filePath: %{public}s, errCode: %{public}d, errno: %{public}d",
453 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str(), moveErrCode, errno);
454 UpdateFailedFiles(fileInfos[i].fileType, fileInfos[i], RestoreError::MOVE_FAILED);
455 continue;
456 }
457 BackupFileUtils::ModifyFile(dstPath, fileInfos[i].dateModified / MSEC_TO_SEC);
458 fileMoveCount++;
459 }
460 migrateAudioFileNumber_ += fileMoveCount;
461 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
462 MEDIA_INFO_LOG("move %{public}ld file cost %{public}ld.", (long)fileMoveCount, (long)(end - startMove));
463 }
464
MoveExtraData(const FileInfo & fileInfo,int32_t sceneCode)465 static bool MoveExtraData(const FileInfo &fileInfo, int32_t sceneCode)
466 {
467 string localExtraDataDir = BackupFileUtils::GetReplacedPathByPrefixType(
468 PrefixType::CLOUD, PrefixType::LOCAL, MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(fileInfo.cloudPath));
469 if (localExtraDataDir.empty()) {
470 MEDIA_WARN_LOG("Failed to get local extra data dir");
471 return false;
472 }
473 if (!MediaFileUtils::IsFileExists(localExtraDataDir) && !MediaFileUtils::CreateDirectory(localExtraDataDir)) {
474 MEDIA_WARN_LOG("Failed to create local extra data dir, errno:%{public}d", errno);
475 return false;
476 }
477
478 string localExtraDataPath = BackupFileUtils::GetReplacedPathByPrefixType(
479 PrefixType::CLOUD, PrefixType::LOCAL, MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(fileInfo.cloudPath));
480 if (localExtraDataPath.empty()) {
481 MEDIA_WARN_LOG("Failed to get local extra data path");
482 return false;
483 }
484 int32_t errCode = BackupFileUtils::MoveFile(fileInfo.extraDataPath, localExtraDataPath, sceneCode);
485 if (errCode != E_OK) {
486 MEDIA_WARN_LOG("MoveFile failed, src:%{public}s, dest:%{public}s, err:%{public}d, errno:%{public}d",
487 BackupFileUtils::GarbleFilePath(fileInfo.extraDataPath, sceneCode).c_str(),
488 BackupFileUtils::GarbleFilePath(localExtraDataPath, sceneCode).c_str(), errCode, errno);
489 return false;
490 }
491 return true;
492 }
493
MoveAndModifyFile(const FileInfo & fileInfo,int32_t sceneCode)494 static bool MoveAndModifyFile(const FileInfo &fileInfo, int32_t sceneCode)
495 {
496 string tmpPath = fileInfo.cloudPath;
497 string localPath = tmpPath.replace(0, RESTORE_CLOUD_DIR.length(), RESTORE_LOCAL_DIR);
498 int32_t errCode = BackupFileUtils::MoveFile(fileInfo.filePath, localPath, sceneCode);
499 if (errCode != E_OK) {
500 MEDIA_ERR_LOG("MoveFile failed, src:%{public}s, dest:%{public}s, err:%{public}d, errno:%{public}d",
501 BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode).c_str(),
502 BackupFileUtils::GarbleFilePath(localPath, sceneCode).c_str(), errCode, errno);
503 return false;
504 }
505 BackupFileUtils::ModifyFile(localPath, fileInfo.dateModified / MSEC_TO_SEC);
506
507 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
508 string tmpVideoPath = MovingPhotoFileUtils::GetMovingPhotoVideoPath(fileInfo.cloudPath);
509 string localVideoPath = tmpVideoPath.replace(0, RESTORE_CLOUD_DIR.length(), RESTORE_LOCAL_DIR);
510 errCode = BackupFileUtils::MoveFile(fileInfo.movingPhotoVideoPath, localVideoPath, sceneCode);
511 if (errCode != E_OK) {
512 MEDIA_ERR_LOG(
513 "MoveFile failed for mov video, src:%{public}s, dest:%{public}s, err:%{public}d, errno:%{public}d",
514 BackupFileUtils::GarbleFilePath(fileInfo.movingPhotoVideoPath, sceneCode).c_str(),
515 BackupFileUtils::GarbleFilePath(localVideoPath, sceneCode).c_str(), errCode, errno);
516 (void)MediaFileUtils::DeleteFile(localPath);
517 return false;
518 }
519 BackupFileUtils::ModifyFile(localVideoPath, fileInfo.dateModified / MSEC_TO_SEC);
520 return MoveExtraData(fileInfo, sceneCode);
521 }
522 return true;
523 }
524
MoveMigrateFile(std::vector<FileInfo> & fileInfos,int32_t & fileMoveCount,int32_t & videoFileMoveCount,int32_t sceneCode)525 void BaseRestore::MoveMigrateFile(std::vector<FileInfo> &fileInfos, int32_t &fileMoveCount, int32_t &videoFileMoveCount,
526 int32_t sceneCode)
527 {
528 vector<std::string> moveFailedData;
529 for (size_t i = 0; i < fileInfos.size(); i++) {
530 if (!fileInfos[i].needMove) {
531 continue;
532 }
533 if (IsFileValid(fileInfos[i], sceneCode) != E_OK) {
534 continue;
535 }
536 if (!MoveAndModifyFile(fileInfos[i], sceneCode)) {
537 fileInfos[i].updateMap.clear();
538 UpdateFailedFiles(fileInfos[i].fileType, fileInfos[i], RestoreError::MOVE_FAILED);
539 ErrorInfo errorInfo(RestoreError::MOVE_FAILED, 1, strerror(errno),
540 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i]));
541 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
542 moveFailedData.push_back(fileInfos[i].cloudPath);
543 continue;
544 }
545 fileMoveCount++;
546 videoFileMoveCount += fileInfos[i].fileType == MediaType::MEDIA_TYPE_VIDEO;
547 }
548 DeleteMoveFailedData(moveFailedData);
549 migrateFileNumber_ += fileMoveCount;
550 migrateVideoFileNumber_ += videoFileMoveCount;
551 }
552
InsertPhoto(int32_t sceneCode,std::vector<FileInfo> & fileInfos,int32_t sourceType)553 int BaseRestore::InsertPhoto(int32_t sceneCode, std::vector<FileInfo> &fileInfos, int32_t sourceType)
554 {
555 MEDIA_INFO_LOG("Start insert %{public}zu photos", fileInfos.size());
556 if (mediaLibraryRdb_ == nullptr) {
557 MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
558 return E_OK;
559 }
560 if (fileInfos.empty()) {
561 MEDIA_ERR_LOG("fileInfos are empty");
562 return E_OK;
563 }
564 int64_t startGenerate = MediaFileUtils::UTCTimeMilliSeconds();
565 vector<NativeRdb::ValuesBucket> values = GetInsertValues(sceneCode, fileInfos, sourceType);
566 int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
567 int64_t rowNum = 0;
568 int32_t errCode = BatchInsertWithRetry(PhotoColumn::PHOTOS_TABLE, values, rowNum);
569 if (errCode != E_OK) {
570 if (needReportFailed_) {
571 UpdateFailedFiles(fileInfos, RestoreError::INSERT_FAILED);
572 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, static_cast<int32_t>(fileInfos.size()), errCode);
573 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
574 }
575 return errCode;
576 }
577
578 int64_t startInsertRelated = MediaFileUtils::UTCTimeMilliSeconds();
579 InsertPhotoRelated(fileInfos, sourceType);
580
581 int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
582 migrateDatabaseNumber_ += rowNum;
583 int32_t fileMoveCount = 0;
584 int32_t videoFileMoveCount = 0;
585 MoveMigrateFile(fileInfos, fileMoveCount, videoFileMoveCount, sceneCode);
586 this->tabOldPhotosRestore_.Restore(this->mediaLibraryRdb_, fileInfos);
587 int64_t startUpdate = MediaFileUtils::UTCTimeMilliSeconds();
588 UpdatePhotosByFileInfoMap(mediaLibraryRdb_, fileInfos);
589 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
590 MEDIA_INFO_LOG("generate values cost %{public}ld, insert %{public}ld assets cost %{public}ld, insert photo related"
591 " cost %{public}ld, and move %{public}ld files (%{public}ld + %{public}ld) cost %{public}ld. update cost"
592 " %{public}ld.",
593 (long)(startInsert - startGenerate), (long)rowNum, (long)(startInsertRelated - startInsert),
594 (long)(startMove - startInsertRelated), (long)fileMoveCount, (long)(fileMoveCount - videoFileMoveCount),
595 (long)videoFileMoveCount, (long)(startUpdate - startMove), long(end - startUpdate));
596 return E_OK;
597 }
598
DeleteMoveFailedData(std::vector<std::string> & moveFailedData)599 void BaseRestore::DeleteMoveFailedData(std::vector<std::string> &moveFailedData)
600 {
601 if (moveFailedData.empty()) {
602 MEDIA_INFO_LOG("No move failed");
603 return;
604 }
605 MEDIA_INFO_LOG("%{public}d file move failed", static_cast<int>(moveFailedData.size()));
606 NativeRdb::AbsRdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
607 predicates.In(MediaColumn::MEDIA_FILE_PATH, moveFailedData);
608 int32_t changedRows = 0;
609 int deleteRes = BackupDatabaseUtils::Delete(predicates, changedRows, mediaLibraryRdb_);
610 MEDIA_INFO_LOG("changeRows:%{public}d, deleteRes:%{public}d", changedRows, deleteRes);
611 }
612
BatchInsertWithRetry(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)613 int32_t BaseRestore::BatchInsertWithRetry(const std::string &tableName, std::vector<NativeRdb::ValuesBucket> &values,
614 int64_t &rowNum)
615 {
616 if (values.empty()) {
617 return 0;
618 }
619
620 int32_t errCode = E_ERR;
621 TransactionOperations trans{ __func__ };
622 trans.SetBackupRdbStore(mediaLibraryRdb_);
623 std::function<int(void)> func = [&]()->int {
624 errCode = trans.BatchInsert(rowNum, tableName, values);
625 if (errCode != E_OK) {
626 MEDIA_ERR_LOG("InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.", errCode, (long)rowNum);
627 }
628 return errCode;
629 };
630 errCode = trans.RetryTrans(func, true);
631 if (errCode != E_OK) {
632 MEDIA_ERR_LOG("BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
633 }
634 return errCode;
635 }
636
MoveDirectory(const std::string & srcDir,const std::string & dstDir,bool deleteOriginalFile) const637 int32_t BaseRestore::MoveDirectory(const std::string &srcDir, const std::string &dstDir, bool deleteOriginalFile) const
638 {
639 if (!MediaFileUtils::CreateDirectory(dstDir)) {
640 MEDIA_ERR_LOG("Create dstDir %{public}s failed",
641 BackupFileUtils::GarbleFilePath(dstDir, DEFAULT_RESTORE_ID).c_str());
642 return E_FAIL;
643 }
644 if (!MediaFileUtils::IsFileExists(srcDir)) {
645 MEDIA_WARN_LOG("%{public}s doesn't exist, skip.", srcDir.c_str());
646 return E_OK;
647 }
648 for (const auto &dirEntry : std::filesystem::directory_iterator{ srcDir }) {
649 std::string srcFilePath = dirEntry.path();
650 std::string tmpFilePath = srcFilePath;
651 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
652 int32_t opRet = E_FAIL;
653 if (deleteOriginalFile) {
654 opRet = this->MoveFile(srcFilePath, dstFilePath);
655 } else {
656 opRet = this->CopyFile(srcFilePath, dstFilePath);
657 }
658 if (opRet != E_OK) {
659 MEDIA_ERR_LOG("Move file from %{public}s to %{public}s failed, deleteOriginalFile=%{public}d",
660 BackupFileUtils::GarbleFilePath(srcFilePath, sceneCode_).c_str(),
661 BackupFileUtils::GarbleFilePath(dstFilePath, DEFAULT_RESTORE_ID).c_str(),
662 deleteOriginalFile);
663 return E_FAIL;
664 }
665 }
666 return E_OK;
667 }
668
IsSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName,FileInfo & fileInfo)669 bool BaseRestore::IsSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName,
670 FileInfo &fileInfo)
671 {
672 string srcPath = fileInfo.filePath;
673 string dstPath = BackupFileUtils::GetFullPathByPrefixType(PrefixType::LOCAL, fileInfo.relativePath);
674 struct stat srcStatInfo {};
675 struct stat dstStatInfo {};
676
677 if (access(dstPath.c_str(), F_OK)) {
678 return false;
679 }
680 if (stat(srcPath.c_str(), &srcStatInfo) != 0) {
681 MEDIA_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", srcPath.c_str(), errno);
682 return false;
683 }
684 if (stat(dstPath.c_str(), &dstStatInfo) != 0) {
685 MEDIA_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", dstPath.c_str(), errno);
686 return false;
687 }
688 if ((srcStatInfo.st_size != dstStatInfo.st_size || srcStatInfo.st_mtime != dstStatInfo.st_mtime) &&
689 !HasSameAudioFile(rdbStore, tableName, fileInfo)) { /* file size & last modify time */
690 MEDIA_INFO_LOG("Size (%{public}lld -> %{public}lld) or mtime (%{public}lld -> %{public}lld) differs",
691 (long long)srcStatInfo.st_size, (long long)dstStatInfo.st_size, (long long)srcStatInfo.st_mtime,
692 (long long)dstStatInfo.st_mtime);
693 return false;
694 }
695 fileInfo.isNew = false;
696 return true;
697 }
698
HasSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName,FileInfo & fileInfo)699 bool BaseRestore::HasSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName,
700 FileInfo &fileInfo)
701 {
702 string querySql = "SELECT " + MediaColumn::MEDIA_ID + ", " + MediaColumn::MEDIA_FILE_PATH + " FROM " +
703 tableName + " WHERE " + MediaColumn::MEDIA_NAME + " = '" + fileInfo.displayName + "' AND " +
704 MediaColumn::MEDIA_SIZE + " = " + to_string(fileInfo.fileSize) + " AND " +
705 MediaColumn::MEDIA_DATE_MODIFIED + " = " + to_string(fileInfo.dateModified);
706 querySql += " LIMIT 1";
707 auto resultSet = BackupDatabaseUtils::GetQueryResultSet(rdbStore, querySql);
708 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
709 return false;
710 }
711 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
712 string cloudPath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
713 if (fileId <= 0 || cloudPath.empty()) {
714 return false;
715 }
716 fileInfo.fileIdNew = fileId;
717 fileInfo.cloudPath = cloudPath;
718 return true;
719 }
720
InsertPhotoMap(std::vector<FileInfo> & fileInfos,int64_t & mapRowNum)721 void BaseRestore::InsertPhotoMap(std::vector<FileInfo> &fileInfos, int64_t &mapRowNum)
722 {
723 BatchInsertMap(fileInfos, mapRowNum);
724 migrateDatabaseMapNumber_ += mapRowNum;
725 }
726
BatchQueryPhoto(vector<FileInfo> & fileInfos,bool isFull,const NeedQueryMap & needQueryMap)727 void BaseRestore::BatchQueryPhoto(vector<FileInfo> &fileInfos, bool isFull, const NeedQueryMap &needQueryMap)
728 {
729 string querySql = "SELECT " + MediaColumn::MEDIA_ID + " , " + MediaColumn::MEDIA_FILE_PATH + " FROM " +
730 PhotoColumn::PHOTOS_TABLE + " WHERE ";
731 bool firstSql = false;
732 std::vector<std::string> cloudPathArgs;
733 for (auto &fileInfo : fileInfos) {
734 if (!isFull && !NeedQuery(fileInfo, needQueryMap)) {
735 continue;
736 }
737 if (firstSql) {
738 querySql += " OR ";
739 } else {
740 firstSql = true;
741 }
742 querySql += MediaColumn::MEDIA_FILE_PATH + " = ? ";
743 cloudPathArgs.push_back(fileInfo.cloudPath);
744 }
745 auto result = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql, cloudPathArgs);
746 if (result == nullptr) {
747 MEDIA_ERR_LOG("Query resultSql is null.");
748 return;
749 }
750 while (result->GoToNextRow() == NativeRdb::E_OK) {
751 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, result);
752 std::string path = GetStringVal(MediaColumn::MEDIA_FILE_PATH, result);
753 auto pathMatch = [path {path}](const auto &fileInfo) {
754 return fileInfo.cloudPath == path;
755 };
756 auto it = std::find_if(fileInfos.begin(), fileInfos.end(), pathMatch);
757 if (it != fileInfos.end() && fileId > 0) {
758 it->fileIdNew = fileId;
759 }
760 }
761 }
762
BatchInsertMap(const vector<FileInfo> & fileInfos,int64_t & totalRowNum)763 void BaseRestore::BatchInsertMap(const vector<FileInfo> &fileInfos, int64_t &totalRowNum)
764 {
765 vector<NativeRdb::ValuesBucket> values;
766 for (const auto &fileInfo : fileInfos) {
767 if (!fileInfo.packageName.empty()) {
768 // add for trigger insert_photo_insert_source_album
769 continue;
770 }
771 if (fileInfo.cloudPath.empty() || fileInfo.mediaAlbumId <= 0 || fileInfo.fileIdNew <= 0) {
772 MEDIA_ERR_LOG("AlbumMap error file name = %{public}s.", fileInfo.displayName.c_str());
773 continue;
774 }
775 NativeRdb::ValuesBucket value;
776 value.PutInt(PhotoMap::ASSET_ID, fileInfo.fileIdNew);
777 value.PutInt(PhotoMap::ALBUM_ID, fileInfo.mediaAlbumId);
778 values.emplace_back(value);
779 }
780 int64_t rowNum = 0;
781 int32_t errCode = BatchInsertWithRetry(PhotoMap::TABLE, values, rowNum);
782 if (errCode != E_OK) {
783 MEDIA_ERR_LOG("Batch insert map failed, errCode: %{public}d", errCode);
784 }
785 totalRowNum += rowNum;
786 }
787
StartRestoreEx(const std::string & backupRetoreDir,const std::string & upgradePath,std::string & restoreExInfo)788 void BaseRestore::StartRestoreEx(const std::string &backupRetoreDir, const std::string &upgradePath,
789 std::string &restoreExInfo)
790 {
791 UpgradeRestoreTaskReport()
792 .SetSceneCode(this->sceneCode_)
793 .SetTaskId(this->taskId_)
794 .ReportProgress("start", std::to_string(MediaFileUtils::UTCTimeSeconds()));
795 StartRestore(backupRetoreDir, upgradePath);
796 DatabaseReport()
797 .SetSceneCode(this->sceneCode_)
798 .SetTaskId(this->taskId_)
799 .ReportMedia(this->mediaLibraryRdb_, DatabaseReport::PERIOD_AFTER);
800 restoreExInfo = GetRestoreExInfo();
801 UpgradeRestoreTaskReport()
802 .SetSceneCode(this->sceneCode_)
803 .SetTaskId(this->taskId_)
804 .ReportTask(restoreExInfo)
805 .ReportTotal(std::to_string(errorCode_), GetRestoreTotalInfo())
806 .ReportTimeCost()
807 .ReportProgress("end", std::to_string(MediaFileUtils::UTCTimeSeconds()));
808 }
809
GetRestoreExInfo()810 std::string BaseRestore::GetRestoreExInfo()
811 {
812 nlohmann::json restoreExInfoJson;
813 restoreExInfoJson[STAT_KEY_RESULT_INFO] = { GetErrorInfoJson(), GetCountInfoJson(STAT_TYPES) };
814 return restoreExInfoJson.dump();
815 }
816
GetErrorInfoJson()817 nlohmann::json BaseRestore::GetErrorInfoJson()
818 {
819 int32_t errorCode = errorCode_ == RestoreError::SUCCESS ? STAT_DEFAULT_ERROR_CODE_SUCCESS :
820 STAT_DEFAULT_ERROR_CODE_FAILED;
821 nlohmann::json errorInfoJson = {
822 { STAT_KEY_TYPE, STAT_VALUE_ERROR_INFO },
823 { STAT_KEY_ERROR_CODE, std::to_string(errorCode) },
824 { STAT_KEY_ERROR_INFO, errorInfo_ }
825 };
826 return errorInfoJson;
827 }
828
GetCountInfoJson(const std::vector<std::string> & countInfoTypes)829 nlohmann::json BaseRestore::GetCountInfoJson(const std::vector<std::string> &countInfoTypes)
830 {
831 nlohmann::json countInfoJson;
832 countInfoJson[STAT_KEY_TYPE] = STAT_VALUE_COUNT_INFO;
833 size_t limit = MAX_FAILED_FILES_LIMIT;
834 for (const auto &type : countInfoTypes) {
835 SubCountInfo subCountInfo = GetSubCountInfo(type);
836 MEDIA_INFO_LOG("SubCountInfo %{public}s success: %{public}lld, duplicate: %{public}lld, failed: %{public}zu",
837 type.c_str(), (long long)subCountInfo.successCount, (long long)subCountInfo.duplicateCount,
838 subCountInfo.failedFiles.size());
839 countInfoJson[STAT_KEY_INFOS].push_back(GetSubCountInfoJson(type, subCountInfo, limit));
840 }
841 return countInfoJson;
842 }
843
GetSubCountInfo(const std::string & type)844 SubCountInfo BaseRestore::GetSubCountInfo(const std::string &type)
845 {
846 std::unordered_map<std::string, FailedFileInfo> failedFiles = GetFailedFiles(type);
847 if (type == STAT_TYPE_PHOTO) {
848 return SubCountInfo(migrateFileNumber_ - migrateVideoFileNumber_, migratePhotoDuplicateNumber_, failedFiles);
849 }
850 if (type == STAT_TYPE_VIDEO) {
851 return SubCountInfo(migrateVideoFileNumber_, migrateVideoDuplicateNumber_, failedFiles);
852 }
853 return SubCountInfo(migrateAudioFileNumber_, migrateAudioDuplicateNumber_, failedFiles);
854 }
855
GetFailedFiles(const std::string & type)856 std::unordered_map<std::string, FailedFileInfo> BaseRestore::GetFailedFiles(const std::string &type)
857 {
858 std::lock_guard<mutex> lock(failedFilesMutex_);
859 std::unordered_map<std::string, FailedFileInfo> failedFiles;
860 auto iter = failedFilesMap_.find(type);
861 if (iter != failedFilesMap_.end()) {
862 return iter->second;
863 }
864 return failedFiles;
865 }
866
GetSubCountInfoJson(const std::string & type,const SubCountInfo & subCountInfo,size_t & limit)867 nlohmann::json BaseRestore::GetSubCountInfoJson(const std::string &type, const SubCountInfo &subCountInfo,
868 size_t &limit)
869 {
870 nlohmann::json subCountInfoJson;
871 subCountInfoJson[STAT_KEY_BACKUP_INFO] = type;
872 subCountInfoJson[STAT_KEY_SUCCESS_COUNT] = subCountInfo.successCount;
873 subCountInfoJson[STAT_KEY_DUPLICATE_COUNT] = subCountInfo.duplicateCount;
874 subCountInfoJson[STAT_KEY_FAILED_COUNT] = subCountInfo.failedFiles.size();
875 // update currentLimit = min(limit, failedFiles.size())
876 size_t currentLimit = limit <= subCountInfo.failedFiles.size() ? limit : subCountInfo.failedFiles.size();
877 std::string detailsPath;
878 std::vector<std::string> failedFilesList;
879 if (sceneCode_ == UPGRADE_RESTORE_ID) {
880 detailsPath = BackupFileUtils::GetDetailsPath(DEFAULT_RESTORE_ID, type, subCountInfo.failedFiles, currentLimit);
881 subCountInfoJson[STAT_KEY_DETAILS] = detailsPath;
882 } else {
883 failedFilesList = BackupFileUtils::GetFailedFilesList(DEFAULT_RESTORE_ID, subCountInfo.failedFiles,
884 currentLimit);
885 subCountInfoJson[STAT_KEY_DETAILS] = failedFilesList;
886 }
887 MEDIA_INFO_LOG("Get %{public}s details size: %{public}zu", type.c_str(), currentLimit);
888 limit -= currentLimit; // update total limit
889 return subCountInfoJson;
890 }
891
GetBackupInfo()892 std::string BaseRestore::GetBackupInfo()
893 {
894 return "";
895 }
896
SetErrorCode(int32_t errorCode)897 void BaseRestore::SetErrorCode(int32_t errorCode)
898 {
899 errorCode_ = errorCode;
900 errorInfo_ = BackupLogUtils::RestoreErrorToString(errorCode);
901 }
902
UpdateFailedFileByFileType(int32_t fileType,const FileInfo & fileInfo,int32_t errorCode)903 void BaseRestore::UpdateFailedFileByFileType(int32_t fileType, const FileInfo &fileInfo, int32_t errorCode)
904 {
905 std::lock_guard<mutex> lock(failedFilesMutex_);
906 FailedFileInfo failedFileInfo(sceneCode_, fileInfo, errorCode);
907 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) {
908 failedFilesMap_[STAT_TYPE_PHOTO].emplace(fileInfo.oldPath, failedFileInfo);
909 return;
910 }
911 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO)) {
912 failedFilesMap_[STAT_TYPE_VIDEO].emplace(fileInfo.oldPath, failedFileInfo);
913 return;
914 }
915 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_AUDIO)) {
916 failedFilesMap_[STAT_TYPE_AUDIO].emplace(fileInfo.oldPath, failedFileInfo);
917 return;
918 }
919 MEDIA_ERR_LOG("Unsupported file type: %{public}d", fileType);
920 }
921
UpdateFailedFiles(int32_t fileType,const FileInfo & fileInfo,int32_t errorCode)922 void BaseRestore::UpdateFailedFiles(int32_t fileType, const FileInfo &fileInfo, int32_t errorCode)
923 {
924 SetErrorCode(errorCode);
925 UpdateFailedFileByFileType(fileType, fileInfo, errorCode);
926 }
927
UpdateFailedFiles(const std::vector<FileInfo> & fileInfos,int32_t errorCode)928 void BaseRestore::UpdateFailedFiles(const std::vector<FileInfo> &fileInfos, int32_t errorCode)
929 {
930 SetErrorCode(errorCode);
931 for (const auto &fileInfo : fileInfos) {
932 UpdateFailedFileByFileType(fileInfo.fileType, fileInfo, errorCode);
933 }
934 }
935
UpdateDuplicateNumber(int32_t fileType)936 void BaseRestore::UpdateDuplicateNumber(int32_t fileType)
937 {
938 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) {
939 migratePhotoDuplicateNumber_++;
940 return;
941 }
942 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO)) {
943 migrateVideoDuplicateNumber_++;
944 return;
945 }
946 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_AUDIO)) {
947 migrateAudioDuplicateNumber_++;
948 return;
949 }
950 MEDIA_ERR_LOG("Unsupported file type: %{public}d", fileType);
951 }
952
SetParameterForClone()953 void BaseRestore::SetParameterForClone()
954 {
955 auto currentTime = to_string(MediaFileUtils::UTCTimeSeconds());
956 MEDIA_INFO_LOG("SetParameterForClone currentTime:%{public}s", currentTime.c_str());
957 bool retFlag = system::SetParameter(CLONE_FLAG, currentTime);
958 if (!retFlag) {
959 MEDIA_ERR_LOG("Failed to set parameter cloneFlag, retFlag:%{public}d", retFlag);
960 }
961 }
962
StopParameterForClone(int32_t sceneCode)963 void BaseRestore::StopParameterForClone(int32_t sceneCode)
964 {
965 bool retFlag = system::SetParameter(CLONE_FLAG, "0");
966 if (!retFlag) {
967 MEDIA_ERR_LOG("Failed to set parameter cloneFlag, retFlag:%{public}d", retFlag);
968 }
969 }
970
InsertPhotoRelated(std::vector<FileInfo> & fileInfos,int32_t sourceType)971 void BaseRestore::InsertPhotoRelated(std::vector<FileInfo> &fileInfos, int32_t sourceType)
972 {
973 if (sourceType != SourceType::GALLERY) {
974 return;
975 }
976 NeedQueryMap needQueryMap;
977 if (!NeedBatchQueryPhoto(fileInfos, needQueryMap)) {
978 MEDIA_INFO_LOG("There is no need to batch query photo");
979 return;
980 }
981 int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
982 BatchQueryPhoto(fileInfos, false, needQueryMap);
983 int64_t startInsertMap = MediaFileUtils::UTCTimeMilliSeconds();
984 int64_t mapRowNum = 0;
985 InsertPhotoMap(fileInfos, mapRowNum);
986 int64_t startInsertPortrait = MediaFileUtils::UTCTimeMilliSeconds();
987 int64_t faceRowNum = 0;
988 int64_t portraitMapRowNum = 0;
989 int64_t portraitPhotoNum = 0;
990 InsertFaceAnalysisData(fileInfos, needQueryMap, faceRowNum, portraitMapRowNum, portraitPhotoNum);
991 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
992 MEDIA_INFO_LOG("query cost %{public}ld, insert %{public}ld maps cost %{public}ld, insert face analysis data of "
993 "%{public}ld photos (%{public}ld faces + %{public}ld maps) cost %{public}ld",
994 (long)(startInsertMap - startQuery), (long)mapRowNum, (long)(startInsertPortrait - startInsertMap),
995 (long)portraitPhotoNum, (long)faceRowNum, (long)portraitMapRowNum, (long)(end - startInsertPortrait));
996 }
997
NeedBatchQueryPhoto(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)998 bool BaseRestore::NeedBatchQueryPhoto(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
999 {
1000 return NeedBatchQueryPhotoForPhotoMap(fileInfos, needQueryMap) ||
1001 NeedBatchQueryPhotoForPortrait(fileInfos, needQueryMap);
1002 }
1003
NeedBatchQueryPhotoForPhotoMap(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)1004 bool BaseRestore::NeedBatchQueryPhotoForPhotoMap(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
1005 {
1006 std::unordered_set<std::string> needQuerySet;
1007 for (const auto &fileInfo : fileInfos) {
1008 if (!fileInfo.packageName.empty()) {
1009 continue;
1010 }
1011 if (fileInfo.cloudPath.empty() || fileInfo.mediaAlbumId <= 0) {
1012 MEDIA_ERR_LOG("Album error file name = %{public}s.", fileInfo.displayName.c_str());
1013 continue;
1014 }
1015 needQuerySet.insert(fileInfo.cloudPath);
1016 }
1017 if (needQuerySet.empty()) {
1018 return false;
1019 }
1020 needQueryMap[PhotoRelatedType::PHOTO_MAP] = needQuerySet;
1021 return true;
1022 }
1023
NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)1024 bool BaseRestore::NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
1025 {
1026 return false;
1027 }
1028
NeedQuery(const FileInfo & fileInfo,const NeedQueryMap & needQueryMap)1029 bool BaseRestore::NeedQuery(const FileInfo &fileInfo, const NeedQueryMap &needQueryMap)
1030 {
1031 for (auto iter = needQueryMap.begin(); iter != needQueryMap.end(); ++iter) {
1032 if (NeedQueryByPhotoRelatedType(fileInfo, iter->first, iter->second)) {
1033 return true;
1034 }
1035 }
1036 return false;
1037 }
1038
NeedQueryByPhotoRelatedType(const FileInfo & fileInfo,PhotoRelatedType photoRelatedType,const std::unordered_set<std::string> & needQuerySet)1039 bool BaseRestore::NeedQueryByPhotoRelatedType(const FileInfo &fileInfo, PhotoRelatedType photoRelatedType,
1040 const std::unordered_set<std::string> &needQuerySet)
1041 {
1042 std::string searchPath;
1043 switch (photoRelatedType) {
1044 case PhotoRelatedType::PHOTO_MAP: {
1045 searchPath = fileInfo.cloudPath;
1046 break;
1047 }
1048 case PhotoRelatedType::PORTRAIT: {
1049 searchPath = fileInfo.hashCode;
1050 break;
1051 }
1052 default:
1053 MEDIA_ERR_LOG("Unsupported photo related type: %{public}d", static_cast<int32_t>(photoRelatedType));
1054 }
1055 return !searchPath.empty() && needQuerySet.count(searchPath) > 0;
1056 }
1057
InsertFaceAnalysisData(const std::vector<FileInfo> & fileInfos,const NeedQueryMap & needQueryMap,int64_t & faceRowNum,int64_t & mapRowNum,int64_t & photoNum)1058 void BaseRestore::InsertFaceAnalysisData(const std::vector<FileInfo> &fileInfos, const NeedQueryMap &needQueryMap,
1059 int64_t &faceRowNum, int64_t &mapRowNum, int64_t &photoNum)
1060 {
1061 return;
1062 }
1063
ReportPortraitStat(int32_t sceneCode)1064 void BaseRestore::ReportPortraitStat(int32_t sceneCode)
1065 {
1066 MEDIA_INFO_LOG("PortraitStat: album %{public}zu, photo %{public}lld, face %{public}lld, cost %{public}lld",
1067 portraitAlbumIdMap_.size(), (long long)migratePortraitPhotoNumber_, (long long)migratePortraitFaceNumber_,
1068 (long long)migratePortraitTotalTimeCost_);
1069 BackupDfxUtils::PostPortraitStat(static_cast<uint32_t>(portraitAlbumIdMap_.size()), migratePortraitPhotoNumber_,
1070 migratePortraitFaceNumber_, migratePortraitTotalTimeCost_);
1071 }
1072
GetUniqueId(int32_t fileType)1073 int32_t BaseRestore::GetUniqueId(int32_t fileType)
1074 {
1075 int32_t uniqueId = -1;
1076 switch (fileType) {
1077 case MediaType::MEDIA_TYPE_IMAGE: {
1078 lock_guard<mutex> lock(imageMutex_);
1079 uniqueId = static_cast<int32_t>(imageNumber_);
1080 imageNumber_++;
1081 break;
1082 }
1083 case MediaType::MEDIA_TYPE_VIDEO: {
1084 lock_guard<mutex> lock(videoMutex_);
1085 uniqueId = static_cast<int32_t>(videoNumber_);
1086 videoNumber_++;
1087 break;
1088 }
1089 case MediaType::MEDIA_TYPE_AUDIO: {
1090 lock_guard<mutex> lock(audioMutex_);
1091 uniqueId = static_cast<int32_t>(audioNumber_);
1092 audioNumber_++;
1093 break;
1094 }
1095 default:
1096 MEDIA_ERR_LOG("Unsupported file type: %{public}d", fileType);
1097 }
1098 return uniqueId;
1099 }
1100
GetProgressInfo()1101 std::string BaseRestore::GetProgressInfo()
1102 {
1103 nlohmann::json progressInfoJson;
1104 for (const auto &type : STAT_PROGRESS_TYPES) {
1105 SubProcessInfo subProcessInfo = GetSubProcessInfo(type);
1106 progressInfoJson[STAT_KEY_PROGRESS_INFO].push_back(GetSubProcessInfoJson(type, subProcessInfo));
1107 }
1108 std::string progressInfo = progressInfoJson.dump();
1109 UpgradeRestoreTaskReport()
1110 .SetSceneCode(this->sceneCode_)
1111 .SetTaskId(this->taskId_)
1112 .ReportProgress("onProcess", progressInfo, ongoingTotalNumber_.load())
1113 .ReportTimeout(ongoingTotalNumber_.load());
1114 return progressInfo;
1115 }
1116
GetSubProcessInfo(const std::string & type)1117 SubProcessInfo BaseRestore::GetSubProcessInfo(const std::string &type)
1118 {
1119 uint64_t success = 0;
1120 uint64_t duplicate = 0;
1121 uint64_t failed = 0;
1122 uint64_t total = 0;
1123 if (type == STAT_TYPE_PHOTO_VIDEO) {
1124 success = migrateFileNumber_;
1125 duplicate = migratePhotoDuplicateNumber_ + migrateVideoDuplicateNumber_;
1126 failed = static_cast<uint64_t>(GetFailedFiles(STAT_TYPE_PHOTO).size() + GetFailedFiles(STAT_TYPE_VIDEO).size());
1127 total = totalNumber_;
1128 } else if (type == STAT_TYPE_AUDIO) {
1129 success = migrateAudioFileNumber_;
1130 duplicate = migrateAudioDuplicateNumber_;
1131 failed = static_cast<uint64_t>(GetFailedFiles(type).size());
1132 total = audioTotalNumber_;
1133 } else if (type == STAT_TYPE_UPDATE) {
1134 UpdateProcessedNumber(updateProcessStatus_, updateProcessedNumber_, updateTotalNumber_);
1135 success = updateProcessedNumber_;
1136 total = updateTotalNumber_;
1137 } else if (type == STAT_TYPE_OTHER) {
1138 UpdateProcessedNumber(otherProcessStatus_, otherProcessedNumber_, otherTotalNumber_);
1139 success = otherProcessedNumber_;
1140 total = otherTotalNumber_;
1141 } else {
1142 ongoingTotalNumber_++;
1143 success = ongoingTotalNumber_;
1144 total = ongoingTotalNumber_; // make sure progressInfo changes as process goes on
1145 }
1146 uint64_t processed = success + duplicate + failed;
1147 return SubProcessInfo(processed, total);
1148 }
1149
UpdateProcessedNumber(const std::atomic<int32_t> & processStatus,std::atomic<uint64_t> & processedNumber,const std::atomic<uint64_t> & totalNumber)1150 void BaseRestore::UpdateProcessedNumber(const std::atomic<int32_t> &processStatus,
1151 std::atomic<uint64_t> &processedNumber, const std::atomic<uint64_t> &totalNumber)
1152 {
1153 if (processStatus == ProcessStatus::STOP) {
1154 processedNumber = totalNumber.load();
1155 return;
1156 }
1157 processedNumber += processedNumber < totalNumber ? 1 : 0;
1158 }
1159
GetSubProcessInfoJson(const std::string & type,const SubProcessInfo & subProcessInfo)1160 nlohmann::json BaseRestore::GetSubProcessInfoJson(const std::string &type, const SubProcessInfo &subProcessInfo)
1161 {
1162 nlohmann::json subProcessInfoJson;
1163 subProcessInfoJson[STAT_KEY_NAME] = type;
1164 subProcessInfoJson[STAT_KEY_PROCESSED] = subProcessInfo.processed;
1165 subProcessInfoJson[STAT_KEY_TOTAL] = subProcessInfo.total;
1166 subProcessInfoJson[STAT_KEY_IS_PERCENTAGE] = false;
1167 return subProcessInfoJson;
1168 }
1169
UpdateDatabase()1170 void BaseRestore::UpdateDatabase()
1171 {
1172 updateProcessStatus_ = ProcessStatus::START;
1173 GetUpdateTotalCount();
1174 MEDIA_INFO_LOG("Start update all albums");
1175 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1176 MediaLibraryRdbUtils::UpdateAllAlbums(rdbStore);
1177 MEDIA_INFO_LOG("Start update unique number");
1178 BackupDatabaseUtils::UpdateUniqueNumber(mediaLibraryRdb_, imageNumber_, IMAGE_ASSET_TYPE);
1179 BackupDatabaseUtils::UpdateUniqueNumber(mediaLibraryRdb_, videoNumber_, VIDEO_ASSET_TYPE);
1180 BackupDatabaseUtils::UpdateUniqueNumber(mediaLibraryRdb_, audioNumber_, AUDIO_ASSET_TYPE);
1181 MEDIA_INFO_LOG("Start notify");
1182 NotifyAlbum();
1183 updateProcessStatus_ = ProcessStatus::STOP;
1184 }
1185
NotifyAlbum()1186 void BaseRestore::NotifyAlbum()
1187 {
1188 auto watch = MediaLibraryNotify::GetInstance();
1189 if (watch == nullptr) {
1190 MEDIA_ERR_LOG("Can not get MediaLibraryNotify Instance");
1191 return;
1192 }
1193 watch->Notify(PhotoColumn::DEFAULT_PHOTO_URI, NotifyType::NOTIFY_ADD);
1194 }
1195
GetUpdateTotalCount()1196 void BaseRestore::GetUpdateTotalCount()
1197 {
1198 GetUpdateAllAlbumsCount();
1199 GetUpdateUniqueNumberCount();
1200 }
1201
GetUpdateAllAlbumsCount()1202 void BaseRestore::GetUpdateAllAlbumsCount()
1203 {
1204 const std::vector<std::string> ALBUM_TABLE_LIST = { "PhotoAlbum", "AnalysisAlbum" };
1205 int32_t albumTotalCount = 0;
1206 for (const auto &tableName : ALBUM_TABLE_LIST) {
1207 std::string querySql = "SELECT count(1) as count FROM " + tableName;
1208 albumTotalCount += BackupDatabaseUtils::QueryInt(mediaLibraryRdb_, querySql, CUSTOM_COUNT);
1209 }
1210 updateTotalNumber_ += static_cast<uint64_t>(albumTotalCount);
1211 MEDIA_INFO_LOG("onProcess Update updateTotalNumber_: %{public}lld", (long long)updateTotalNumber_);
1212 }
1213
GetUpdateUniqueNumberCount()1214 void BaseRestore::GetUpdateUniqueNumberCount()
1215 {
1216 updateTotalNumber_ += UNIQUE_NUMBER_NUM;
1217 MEDIA_INFO_LOG("onProcess Update updateTotalNumber_: %{public}lld", (long long)updateTotalNumber_);
1218 }
1219
RestoreThumbnail()1220 void BaseRestore::RestoreThumbnail()
1221 {
1222 // restore thumbnail for date fronted 500 photos
1223 MEDIA_INFO_LOG("Start RestoreThumbnail");
1224 otherProcessStatus_ = ProcessStatus::START;
1225 otherTotalNumber_ += THUMBNAIL_NUM;
1226 MEDIA_INFO_LOG("onProcess Update otherTotalNumber_: %{public}lld", (long long)otherTotalNumber_);
1227 BackupFileUtils::GenerateThumbnailsAfterRestore();
1228 otherProcessStatus_ = ProcessStatus::STOP;
1229 }
1230
StartBackup()1231 void BaseRestore::StartBackup()
1232 {}
1233
CheckInvalidFile(const FileInfo & fileInfo,int32_t errCode)1234 std::string BaseRestore::CheckInvalidFile(const FileInfo &fileInfo, int32_t errCode)
1235 {
1236 return "";
1237 }
1238
GetRestoreTotalInfo()1239 std::string BaseRestore::GetRestoreTotalInfo()
1240 {
1241 std::stringstream restoreTotalInfo;
1242 uint64_t success = migrateFileNumber_;
1243 uint64_t duplicate = migratePhotoDuplicateNumber_ + migrateVideoDuplicateNumber_;
1244 uint64_t failed = static_cast<uint64_t>(GetFailedFiles(STAT_TYPE_PHOTO).size() +
1245 GetFailedFiles(STAT_TYPE_VIDEO).size());
1246 uint64_t error = totalNumber_ - success - duplicate - failed;
1247 restoreTotalInfo << failed;
1248 restoreTotalInfo << ";" << error;
1249 restoreTotalInfo << ";" << GetNoNeedMigrateCount();
1250 return restoreTotalInfo.str();
1251 }
1252
GetNoNeedMigrateCount()1253 int32_t BaseRestore::GetNoNeedMigrateCount()
1254 {
1255 return 0;
1256 }
1257
UpdatePhotosByFileInfoMap(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<FileInfo> & fileInfos)1258 void BaseRestore::UpdatePhotosByFileInfoMap(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
1259 const std::vector<FileInfo>& fileInfos)
1260 {
1261 for (const FileInfo &fileInfo : fileInfos) {
1262 auto &updateMap = fileInfo.updateMap;
1263 if (fileInfo.fileIdNew <= 0 || fileInfo.isNew || updateMap.empty()) {
1264 continue;
1265 }
1266 int32_t changeRows = 0;
1267 std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
1268 make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
1269 predicates->SetWhereClause("file_id=?");
1270 predicates->SetWhereArgs({ to_string(fileInfo.fileIdNew) });
1271 NativeRdb::ValuesBucket updatePostBucket;
1272 for (auto it = updateMap.begin(); it != updateMap.end(); it++) {
1273 updatePostBucket.Put(it->first, it->second);
1274 }
1275 BackupDatabaseUtils::Update(mediaLibraryRdb, changeRows, updatePostBucket, predicates);
1276 if (changeRows <= 0) {
1277 MEDIA_ERR_LOG("update failed, fileId: %{public}d", fileInfo.fileIdNew);
1278 ErrorInfo errorInfo(RestoreError::UPDATE_PHOTOS_FAILED, 1, "",
1279 BackupLogUtils::FileInfoToString(this->sceneCode_, fileInfo));
1280 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
1281 }
1282 }
1283 }
1284 } // namespace Media
1285 } // namespace OHOS
1286