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