1 /*
2  * Copyright (C) 2023 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 "MediaLibraryCloneRestore"
17 
18 #include "clone_restore.h"
19 #include "backup_const_column.h"
20 
21 #include "application_context.h"
22 #include "backup_dfx_utils.h"
23 #include "backup_file_utils.h"
24 #include "backup_log_utils.h"
25 #include "database_report.h"
26 #include "ffrt.h"
27 #include "ffrt_inner.h"
28 #include "media_column.h"
29 #include "media_file_utils.h"
30 #include "media_library_db_upgrade.h"
31 #include "media_log.h"
32 #include "medialibrary_data_manager.h"
33 #include "medialibrary_errno.h"
34 #include "medialibrary_notify.h"
35 #include "medialibrary_photo_operations.h"
36 #include "medialibrary_type_const.h"
37 #include "photos_dao.h"
38 #include "rdb_store.h"
39 #include "result_set_utils.h"
40 #include "upgrade_restore_task_report.h"
41 #include "userfile_manager_types.h"
42 
43 #ifdef CLOUD_SYNC_MANAGER
44 #include "cloud_sync_manager.h"
45 #endif
46 
47 using namespace std;
48 namespace OHOS {
49 namespace Media {
50 const int32_t CLONE_QUERY_COUNT = 200;
51 const int32_t SYSTEM_ALBUM_ID_START = 1;
52 const int32_t SYSTEM_ALBUM_ID_END = 7;
53 const string MEDIA_DB_PATH = "/data/storage/el2/database/rdb/media_library.db";
54 constexpr int64_t SECONDS_LEVEL_LIMIT = 1e10;
55 const unordered_map<string, unordered_set<string>> NEEDED_COLUMNS_MAP = {
56     { PhotoColumn::PHOTOS_TABLE,
57         {
58             MediaColumn::MEDIA_ID,
59             MediaColumn::MEDIA_FILE_PATH,
60             MediaColumn::MEDIA_SIZE,
61             MediaColumn::MEDIA_TYPE,
62             MediaColumn::MEDIA_NAME,
63             MediaColumn::MEDIA_DATE_ADDED,
64             MediaColumn::MEDIA_DATE_MODIFIED,
65             PhotoColumn::PHOTO_ORIENTATION,
66             PhotoColumn::PHOTO_SUBTYPE,
67             MediaColumn::MEDIA_DATE_TRASHED,
68             MediaColumn::MEDIA_HIDDEN,
69         }},
70     { PhotoAlbumColumns::TABLE,
71         {
72             PhotoAlbumColumns::ALBUM_ID,
73             PhotoAlbumColumns::ALBUM_TYPE,
74             PhotoAlbumColumns::ALBUM_SUBTYPE,
75             PhotoAlbumColumns::ALBUM_NAME,
76             PhotoAlbumColumns::ALBUM_BUNDLE_NAME,
77         }},
78     { PhotoMap::TABLE,
79         {
80             PhotoMap::ALBUM_ID,
81             PhotoMap::ASSET_ID,
82         }},
83     { ANALYSIS_ALBUM_TABLE,
84         {
85             PhotoAlbumColumns::ALBUM_ID,
86             PhotoAlbumColumns::ALBUM_TYPE,
87             PhotoAlbumColumns::ALBUM_SUBTYPE,
88             PhotoAlbumColumns::ALBUM_NAME,
89         }},
90     { ANALYSIS_PHOTO_MAP_TABLE,
91         {
92             PhotoMap::ALBUM_ID,
93             PhotoMap::ASSET_ID,
94         }},
95     { AudioColumn::AUDIOS_TABLE,
96         {
97             MediaColumn::MEDIA_ID,
98             MediaColumn::MEDIA_FILE_PATH,
99             MediaColumn::MEDIA_SIZE,
100             MediaColumn::MEDIA_TYPE,
101             MediaColumn::MEDIA_NAME,
102             MediaColumn::MEDIA_DATE_ADDED,
103             MediaColumn::MEDIA_DATE_MODIFIED,
104         }},
105 };
106 const unordered_map<string, unordered_set<string>> NEEDED_COLUMNS_EXCEPTION_MAP = {
107     { PhotoAlbumColumns::TABLE,
108         {
109             PhotoAlbumColumns::ALBUM_BUNDLE_NAME,
110         }},
111 };
112 const unordered_map<string, unordered_set<string>> EXCLUDED_COLUMNS_MAP = {
113     { PhotoColumn::PHOTOS_TABLE,
114         {
115             PhotoColumn::PHOTO_CLOUD_ID, PhotoColumn::PHOTO_DIRTY, PhotoColumn::PHOTO_META_DATE_MODIFIED,
116             PhotoColumn::PHOTO_SYNC_STATUS, PhotoColumn::PHOTO_CLOUD_VERSION, PhotoColumn::PHOTO_POSITION,
117             PhotoColumn::PHOTO_THUMB_STATUS, PhotoColumn::PHOTO_CLEAN_FLAG, // cloud related
118             PhotoColumn::PHOTO_THUMBNAIL_READY, PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, // thumbnail related
119             PhotoColumn::PHOTO_LCD_VISIT_TIME, // lcd related
120             PhotoColumn::PHOTO_CE_AVAILABLE, PhotoColumn::PHOTO_CE_STATUS_CODE, // cloud enhancement
121             PhotoColumn::PHOTO_THUMBNAIL_VISIBLE
122         }},
123     { PhotoAlbumColumns::TABLE,
124         {
125             PhotoAlbumColumns::ALBUM_COVER_URI, PhotoAlbumColumns::ALBUM_COUNT, PhotoAlbumColumns::CONTAINS_HIDDEN,
126             PhotoAlbumColumns::HIDDEN_COUNT, PhotoAlbumColumns::HIDDEN_COVER, PhotoAlbumColumns::ALBUM_IMAGE_COUNT,
127             PhotoAlbumColumns::ALBUM_VIDEO_COUNT, // updated by album udpate
128             PhotoAlbumColumns::ALBUM_DIRTY, PhotoAlbumColumns::ALBUM_CLOUD_ID, // cloud related
129             PhotoAlbumColumns::ALBUM_ORDER, // created by trigger
130         }},
131     { ANALYSIS_ALBUM_TABLE,
132         {
133             PhotoAlbumColumns::ALBUM_COVER_URI,
134             PhotoAlbumColumns::ALBUM_COUNT,
135         }},
136 };
137 const unordered_map<string, unordered_map<string, string>> TABLE_QUERY_WHERE_CLAUSE_MAP = {
138     { PhotoColumn::PHOTOS_TABLE,
139         {
140             { PhotoColumn::PHOTO_POSITION, PhotoColumn::PHOTO_POSITION + " IN (1, 3)" },
141             { PhotoColumn::PHOTO_SYNC_STATUS, PhotoColumn::PHOTO_SYNC_STATUS + " = " +
142                 to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)) },
143             { PhotoColumn::PHOTO_CLEAN_FLAG, PhotoColumn::PHOTO_CLEAN_FLAG + " = " +
144                 to_string(static_cast<int32_t>(CleanType::TYPE_NOT_CLEAN)) },
145             { MediaColumn::MEDIA_TIME_PENDING, MediaColumn::MEDIA_TIME_PENDING + " = 0" },
146             { PhotoColumn::PHOTO_IS_TEMP, PhotoColumn::PHOTO_IS_TEMP + " = 0" },
147         }},
148     { PhotoAlbumColumns::TABLE,
149         {
150             { PhotoAlbumColumns::ALBUM_NAME, PhotoAlbumColumns::ALBUM_NAME + " IS NOT NULL" },
151             { PhotoAlbumColumns::ALBUM_TYPE, PhotoAlbumColumns::ALBUM_TYPE + " != " +
152                 to_string(PhotoAlbumType::SYSTEM)},
153         }},
154     { ANALYSIS_ALBUM_TABLE,
155         {
156             { PhotoAlbumColumns::ALBUM_NAME, PhotoAlbumColumns::ALBUM_NAME + " IS NOT NULL" },
157             { PhotoAlbumColumns::ALBUM_SUBTYPE, PhotoAlbumColumns::ALBUM_SUBTYPE + " IN (" +
158                 to_string(PhotoAlbumSubType::SHOOTING_MODE) + ")" },
159         }},
160 };
161 const vector<string> CLONE_ALBUMS = { PhotoAlbumColumns::TABLE, ANALYSIS_ALBUM_TABLE };
162 const unordered_map<string, string> CLONE_ALBUM_MAP = {
163     { PhotoAlbumColumns::TABLE, PhotoMap::TABLE },
164     { ANALYSIS_ALBUM_TABLE, ANALYSIS_PHOTO_MAP_TABLE },
165 };
166 const unordered_map<string, ResultSetDataType> COLUMN_TYPE_MAP = {
167     { "INT", ResultSetDataType::TYPE_INT32 },
168     { "INTEGER", ResultSetDataType::TYPE_INT32 },
169     { "BIGINT", ResultSetDataType::TYPE_INT64 },
170     { "DOUBLE", ResultSetDataType::TYPE_DOUBLE },
171     { "TEXT", ResultSetDataType::TYPE_STRING },
172 };
173 const unordered_map<string, string> ALBUM_URI_PREFIX_MAP = {
174     { PhotoAlbumColumns::TABLE, PhotoAlbumColumns::ALBUM_URI_PREFIX },
175     { ANALYSIS_ALBUM_TABLE, PhotoAlbumColumns::ANALYSIS_ALBUM_URI_PREFIX },
176 };
177 
178 template<typename Key, typename Value>
GetValueFromMap(const unordered_map<Key,Value> & map,const Key & key,const Value & defaultValue=Value ())179 Value GetValueFromMap(const unordered_map<Key, Value> &map, const Key &key, const Value &defaultValue = Value())
180 {
181     auto it = map.find(key);
182     if (it == map.end()) {
183         return defaultValue;
184     }
185     return it->second;
186 }
187 
CloneRestore()188 CloneRestore::CloneRestore()
189 {
190     sceneCode_ = CLONE_RESTORE_ID;
191     MEDIA_INFO_LOG("Use ffrt without escape");
192 }
193 
StartRestore(const string & backupRestoreDir,const string & upgradePath)194 void CloneRestore::StartRestore(const string &backupRestoreDir, const string &upgradePath)
195 {
196     MEDIA_INFO_LOG("Start clone restore");
197     SetParameterForClone();
198 #ifdef CLOUD_SYNC_MANAGER
199     FileManagement::CloudSync::CloudSyncManager::GetInstance().StopSync("com.ohos.medialibrary.medialibrarydata");
200 #endif
201     backupRestoreDir_ = backupRestoreDir;
202     garbagePath_ = backupRestoreDir_ + "/storage/media/local/files";
203     int32_t errorCode = Init(backupRestoreDir, upgradePath, true);
204     if (errorCode == E_OK) {
205         RestoreGallery();
206         RestoreMusic();
207         UpdateDatabase();
208         (void)NativeRdb::RdbHelper::DeleteRdbStore(dbPath_);
209     } else {
210         SetErrorCode(RestoreError::INIT_FAILED);
211         ErrorInfo errorInfo(RestoreError::INIT_FAILED, 0, errorCode);
212         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
213     }
214     HandleRestData();
215     StopParameterForClone(CLONE_RESTORE_ID);
216     CloseAllKvStore();
217     MEDIA_INFO_LOG("End clone restore");
218 }
219 
InitThumbnailStatus()220 void CloneRestore::InitThumbnailStatus()
221 {
222     std::string cloneThumbnailDir = backupRestoreDir_ + RESTORE_FILES_LOCAL_DIR + ".thumbs";
223     if (!MediaFileUtils::IsFileExists(cloneThumbnailDir)) {
224         MEDIA_WARN_LOG("Uncloned thumbnail dir, no need to clone thumbnail");
225         return;
226     }
227     hasCloneThumbnailDir_ = true;
228     isInitKvstoreSuccess_ = InitAllKvStore();
229 }
230 
Init(const string & backupRestoreDir,const string & upgradePath,bool isUpgrade)231 int32_t CloneRestore::Init(const string &backupRestoreDir, const string &upgradePath, bool isUpgrade)
232 {
233     dbPath_ = backupRestoreDir_ + MEDIA_DB_PATH;
234     filePath_ = backupRestoreDir_ + "/storage/media/local/files";
235     if (!MediaFileUtils::IsFileExists(dbPath_)) {
236         MEDIA_ERR_LOG("Media db is not exist.");
237         return E_FAIL;
238     }
239     if (isUpgrade && BaseRestore::Init() != E_OK) {
240         return E_FAIL;
241     }
242     auto context = AbilityRuntime::Context::GetApplicationContext();
243     if (context == nullptr) {
244         MEDIA_ERR_LOG("Failed to get context");
245         return E_FAIL;
246     }
247     int32_t err = BackupDatabaseUtils::InitDb(mediaRdb_, MEDIA_DATA_ABILITY_DB_NAME, dbPath_, BUNDLE_NAME, true,
248         context->GetArea());
249     if (mediaRdb_ == nullptr) {
250         MEDIA_ERR_LOG("Init remote medialibrary rdb fail, err = %{public}d", err);
251         return E_FAIL;
252     }
253     BackupDatabaseUtils::CheckDbIntegrity(mediaRdb_, sceneCode_, "OLD_MEDIA_LIBRARY");
254     InitThumbnailStatus();
255     this->photoAlbumClone_.OnStart(this->mediaRdb_, this->mediaLibraryRdb_);
256     this->photosClone_.OnStart(this->mediaLibraryRdb_, this->mediaRdb_);
257     MEDIA_INFO_LOG("Init db succ.");
258     return E_OK;
259 }
260 
RestorePhoto()261 void CloneRestore::RestorePhoto()
262 {
263     MEDIA_INFO_LOG("Start clone restore: photos");
264     if (!IsReadyForRestore(PhotoColumn::PHOTOS_TABLE)) {
265         MEDIA_ERR_LOG("Column status is not ready for restore photo, quit");
266         return;
267     }
268     unordered_map<string, string> srcColumnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(mediaRdb_,
269         PhotoColumn::PHOTOS_TABLE);
270     unordered_map<string, string> dstColumnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(mediaLibraryRdb_,
271         PhotoColumn::PHOTOS_TABLE);
272     if (!PrepareCommonColumnInfoMap(PhotoColumn::PHOTOS_TABLE, srcColumnInfoMap, dstColumnInfoMap)) {
273         MEDIA_ERR_LOG("Prepare common column info failed");
274         return;
275     }
276     // The begining of the restore process
277     // Start clone restore
278     this->photosClone_.LoadPhotoAlbums();
279     // Scenario 1, clone photos from PhotoAlbum, PhotoMap and Photos.
280     int totalNumberInPhotoMap = this->photosClone_.GetPhotosRowCountInPhotoMap();
281     MEDIA_INFO_LOG("GetPhotosRowCountInPhotoMap, totalNumber = %{public}d", totalNumberInPhotoMap);
282     totalNumber_ += static_cast<uint64_t>(totalNumberInPhotoMap);
283     MEDIA_INFO_LOG("onProcess Update totalNumber_: %{public}lld", (long long)totalNumber_);
284     ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_THREAD_NUM);
285     for (int32_t offset = 0; offset < totalNumberInPhotoMap; offset += CLONE_QUERY_COUNT) {
286         ffrt::submit([this, offset]() { RestorePhotoBatch(offset, 1); }, {&offset}, {},
287             ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
288     }
289     ffrt::wait();
290     size_t vectorLen = photosFailedOffsets.size();
291     needReportFailed_ = true;
292     for (size_t offset = 0; offset < vectorLen; offset++) {
293         RestorePhotoBatch(offset, 1);
294     }
295     photosFailedOffsets.clear();
296     needReportFailed_ = false;
297     // Scenario 2, clone photos from Photos only.
298     int32_t totalNumber = this->photosClone_.GetPhotosRowCountNotInPhotoMap();
299     MEDIA_INFO_LOG("QueryTotalNumberNot, totalNumber = %{public}d", totalNumber);
300     totalNumber_ += static_cast<uint64_t>(totalNumber);
301     MEDIA_INFO_LOG("onProcess Update totalNumber_: %{public}lld", (long long)totalNumber_);
302     for (int32_t offset = 0; offset < totalNumber; offset += CLONE_QUERY_COUNT) {
303         ffrt::submit([this, offset]() { RestorePhotoBatch(offset); }, { &offset }, {},
304             ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
305     }
306     ffrt::wait();
307     vectorLen = photosFailedOffsets.size();
308     needReportFailed_ = true;
309     for (size_t offset = 0; offset < vectorLen; offset++) {
310         RestorePhotoBatch(offset);
311     }
312     this->photosClone_.OnStop(otherTotalNumber_, otherProcessStatus_);
313 
314     BackupDatabaseUtils::UpdateFaceAnalysisTblStatus(mediaLibraryRdb_);
315     BackupDatabaseUtils::UpdateAnalysisPhotoMapStatus(mediaLibraryRdb_);
316     ReportPortraitCloneStat(sceneCode_);
317 }
318 
RestoreAlbum()319 void CloneRestore::RestoreAlbum()
320 {
321     MEDIA_INFO_LOG("Start clone restore: albums");
322     for (const auto &tableName : CLONE_ALBUMS) {
323         if (!IsReadyForRestore(tableName)) {
324             MEDIA_ERR_LOG("Column status of %{public}s is not ready for restore album, quit",
325                 BackupDatabaseUtils::GarbleInfoName(tableName).c_str());
326             continue;
327         }
328         unordered_map<string, string> srcColumnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(mediaRdb_, tableName);
329         unordered_map<string, string> dstColumnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(mediaLibraryRdb_,
330             tableName);
331         if (!PrepareCommonColumnInfoMap(tableName, srcColumnInfoMap, dstColumnInfoMap)) {
332             MEDIA_ERR_LOG("Prepare common column info failed");
333             continue;
334         }
335         GetAlbumExtraQueryWhereClause(tableName);
336         int32_t totalNumber = QueryTotalNumber(tableName);
337         MEDIA_INFO_LOG(
338             "QueryAlbumTotalNumber, tableName=%{public}s, totalNumber=%{public}d", tableName.c_str(), totalNumber);
339         for (int32_t offset = 0; offset < totalNumber; offset += CLONE_QUERY_COUNT) {
340             vector<AlbumInfo> albumInfos = QueryAlbumInfos(tableName, offset);
341             this->photoAlbumClone_.TRACE_LOG(tableName, albumInfos);
342             InsertAlbum(albumInfos, tableName);
343         }
344     }
345 
346     RestoreFromGalleryPortraitAlbum();
347     RestorePortraitClusteringInfo();
348 }
349 
MoveMigrateFile(std::vector<FileInfo> & fileInfos,int64_t & fileMoveCount,int64_t & videoFileMoveCount)350 void CloneRestore::MoveMigrateFile(std::vector<FileInfo> &fileInfos, int64_t &fileMoveCount,
351     int64_t &videoFileMoveCount)
352 {
353     vector<std::string> moveFailedData;
354     for (size_t i = 0; i < fileInfos.size(); i++) {
355         if (!MediaFileUtils::IsFileExists(fileInfos[i].filePath) || fileInfos[i].cloudPath.empty() ||
356             !fileInfos[i].needMove) {
357             continue;
358         }
359         int32_t errCode = MoveAsset(fileInfos[i]);
360         if (errCode != E_OK) {
361             fileInfos[i].updateMap.clear();
362             MEDIA_ERR_LOG("MoveFile failed, filePath = %{public}s, error:%{public}s",
363                 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, CLONE_RESTORE_ID, garbagePath_).c_str(),
364                 strerror(errno));
365             UpdateFailedFiles(fileInfos[i].fileType, fileInfos[i], RestoreError::MOVE_FAILED);
366             ErrorInfo errorInfo(RestoreError::MOVE_FAILED, 1, strerror(errno),
367                 BackupLogUtils::FileInfoToString(sceneCode_, fileInfos[i]));
368             UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
369             moveFailedData.push_back(fileInfos[i].cloudPath);
370             continue;
371         }
372         fileMoveCount++;
373         videoFileMoveCount += fileInfos[i].fileType == MediaType::MEDIA_TYPE_VIDEO;
374     }
375     DeleteMoveFailedData(moveFailedData);
376     migrateFileNumber_ += fileMoveCount;
377     migrateVideoFileNumber_ += videoFileMoveCount;
378 }
379 
InsertPhoto(vector<FileInfo> & fileInfos)380 int CloneRestore::InsertPhoto(vector<FileInfo> &fileInfos)
381 {
382     if (mediaLibraryRdb_ == nullptr) {
383         MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
384         return E_OK;
385     }
386     if (fileInfos.empty()) {
387         MEDIA_ERR_LOG("fileInfos are empty");
388         return E_OK;
389     }
390     int64_t startGenerate = MediaFileUtils::UTCTimeMilliSeconds();
391     vector<NativeRdb::ValuesBucket> values = GetInsertValues(CLONE_RESTORE_ID, fileInfos, SourceType::PHOTOS);
392     int64_t startInsertPhoto = MediaFileUtils::UTCTimeMilliSeconds();
393     int64_t photoRowNum = 0;
394     int32_t errCode = BatchInsertWithRetry(PhotoColumn::PHOTOS_TABLE, values, photoRowNum);
395     if (errCode != E_OK) {
396         if (needReportFailed_) {
397             UpdateFailedFiles(fileInfos, RestoreError::INSERT_FAILED);
398             ErrorInfo errorInfo(RestoreError::INSERT_FAILED, static_cast<int32_t>(fileInfos.size()), errCode);
399             UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
400         }
401         return errCode;
402     }
403     migrateDatabaseNumber_ += photoRowNum;
404 
405     int64_t startInsertRelated = MediaFileUtils::UTCTimeMilliSeconds();
406     InsertPhotoRelated(fileInfos);
407 
408     int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
409     int64_t fileMoveCount = 0;
410     int64_t videoFileMoveCount = 0;
411     MoveMigrateFile(fileInfos, fileMoveCount, videoFileMoveCount);
412     int64_t startUpdate = MediaFileUtils::UTCTimeMilliSeconds();
413     UpdatePhotosByFileInfoMap(mediaLibraryRdb_, fileInfos);
414     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
415     MEDIA_INFO_LOG("generate cost %{public}ld, insert %{public}ld assets cost %{public}ld, insert photo related cost "
416         "%{public}ld, and move %{public}ld files (%{public}ld + %{public}ld) cost %{public}ld. update cost %{public}ld",
417         (long)(startInsertPhoto - startGenerate), (long)photoRowNum, (long)(startInsertRelated - startInsertPhoto),
418         (long)(startMove - startInsertRelated), (long)fileMoveCount, (long)(fileMoveCount - videoFileMoveCount),
419         (long)videoFileMoveCount, (long)(startUpdate - startMove), (long)(end - startUpdate));
420     return E_OK;
421 }
422 
GetInsertValues(int32_t sceneCode,vector<FileInfo> & fileInfos,int32_t sourceType)423 vector<NativeRdb::ValuesBucket> CloneRestore::GetInsertValues(int32_t sceneCode, vector<FileInfo> &fileInfos,
424     int32_t sourceType)
425 {
426     vector<NativeRdb::ValuesBucket> values;
427     for (size_t i = 0; i < fileInfos.size(); i++) {
428         int32_t errCode = BackupFileUtils::IsFileValid(fileInfos[i].filePath, CLONE_RESTORE_ID);
429         if (errCode != E_OK) {
430             ErrorInfo errorInfo(RestoreError::FILE_INVALID, 1, std::to_string(errCode),
431                 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i]));
432             UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
433             continue;
434         }
435         if (!PrepareCloudPath(PhotoColumn::PHOTOS_TABLE, fileInfos[i])) {
436             continue;
437         }
438         if (fileInfos[i].isNew) {
439             NativeRdb::ValuesBucket value = GetInsertValue(fileInfos[i], fileInfos[i].cloudPath, sourceType);
440             values.emplace_back(value);
441         }
442     }
443     return values;
444 }
445 
HandleRestData(void)446 void CloneRestore::HandleRestData(void)
447 {
448     MEDIA_INFO_LOG("Start to handle rest data in native.");
449 }
450 
QueryFileInfos(int32_t offset,int32_t isRelatedToPhotoMap)451 vector<FileInfo> CloneRestore::QueryFileInfos(int32_t offset, int32_t isRelatedToPhotoMap)
452 {
453     vector<FileInfo> result;
454     result.reserve(CLONE_QUERY_COUNT);
455     std::shared_ptr<NativeRdb::ResultSet> resultSet;
456     if (isRelatedToPhotoMap == 1) {
457         resultSet = this->photosClone_.GetPhotosInPhotoMap(offset, CLONE_QUERY_COUNT);
458     } else {
459         resultSet = this->photosClone_.GetPhotosNotInPhotoMap(offset, CLONE_QUERY_COUNT);
460     }
461     if (resultSet == nullptr) {
462         MEDIA_ERR_LOG("Query resultSql is null.");
463         return result;
464     }
465     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
466         FileInfo fileInfo;
467         fileInfo.isRelatedToPhotoMap = isRelatedToPhotoMap;
468         if (ParseResultSet(resultSet, fileInfo)) {
469             result.emplace_back(fileInfo);
470         }
471     }
472     return result;
473 }
474 
ParseResultSet(const shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & fileInfo,string dbName)475 bool CloneRestore::ParseResultSet(const shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &fileInfo,
476     string dbName)
477 {
478     return ParseResultSet(PhotoColumn::PHOTOS_TABLE, resultSet, fileInfo);
479 }
480 
QueryTotalNumber(const string & tableName)481 int32_t CloneRestore::QueryTotalNumber(const string &tableName)
482 {
483     if (tableName == PhotoAlbumColumns::TABLE) {
484         return this->photoAlbumClone_.GetPhotoAlbumCountInOriginalDb();
485     }
486     if (tableName == PhotoColumn::PHOTOS_TABLE) {
487         return this->photosClone_.GetPhotosRowCountNotInPhotoMap();
488     }
489     string querySql = "SELECT " + MEDIA_COLUMN_COUNT_1 + " FROM " + tableName;
490     string whereClause = GetQueryWhereClauseByTable(tableName);
491     querySql += whereClause.empty() ? "" : " WHERE " + whereClause;
492     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
493     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
494         return 0;
495     }
496     int32_t result = GetInt32Val(MEDIA_COLUMN_COUNT_1, resultSet);
497     return result;
498 }
499 
QueryAlbumInfos(const string & tableName,int32_t offset)500 vector<AlbumInfo> CloneRestore::QueryAlbumInfos(const string &tableName, int32_t offset)
501 {
502     vector<AlbumInfo> result;
503     result.reserve(CLONE_QUERY_COUNT);
504     std::shared_ptr<NativeRdb::ResultSet> resultSet = nullptr;
505     if (tableName == PhotoAlbumColumns::TABLE) {
506         resultSet = this->photoAlbumClone_.GetPhotoAlbumInOriginalDb(offset, CLONE_QUERY_COUNT);
507     } else {
508         string querySql = "SELECT * FROM " + tableName;
509         string whereClause = GetQueryWhereClauseByTable(tableName);
510         querySql += whereClause.empty() ? "" : " WHERE " + whereClause;
511         querySql += " LIMIT " + to_string(offset) + ", " + to_string(CLONE_QUERY_COUNT);
512         resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
513     }
514     if (resultSet == nullptr) {
515         MEDIA_ERR_LOG("Query resultSql is null.");
516         return result;
517     }
518     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
519         AlbumInfo albumInfo;
520         if (ParseAlbumResultSet(tableName, resultSet, albumInfo)) {
521             result.emplace_back(albumInfo);
522         }
523     }
524     return result;
525 }
526 
ParseAlbumResultSet(const string & tableName,const shared_ptr<NativeRdb::ResultSet> & resultSet,AlbumInfo & albumInfo)527 bool CloneRestore::ParseAlbumResultSet(const string &tableName, const shared_ptr<NativeRdb::ResultSet> &resultSet,
528     AlbumInfo &albumInfo)
529 {
530     albumInfo.albumIdOld = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
531     albumInfo.albumName = GetStringVal(PhotoAlbumColumns::ALBUM_NAME, resultSet);
532     albumInfo.albumType = static_cast<PhotoAlbumType>(GetInt32Val(PhotoAlbumColumns::ALBUM_TYPE, resultSet));
533     albumInfo.albumSubType = static_cast<PhotoAlbumSubType>(GetInt32Val(PhotoAlbumColumns::ALBUM_SUBTYPE, resultSet));
534     albumInfo.lPath = GetStringVal(PhotoAlbumColumns::ALBUM_LPATH, resultSet);
535     albumInfo.albumBundleName = GetStringVal(PhotoAlbumColumns::ALBUM_BUNDLE_NAME, resultSet);
536     albumInfo.dateModified = GetInt64Val(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, resultSet);
537 
538     auto commonColumnInfoMap = GetValueFromMap(tableCommonColumnInfoMap_, tableName);
539     for (auto it = commonColumnInfoMap.begin(); it != commonColumnInfoMap.end(); ++it) {
540         string columnName = it->first;
541         string columnType = it->second;
542         GetValFromResultSet(resultSet, albumInfo.valMap, columnName, columnType);
543     }
544     return true;
545 }
546 
AnalyzeSource()547 void CloneRestore::AnalyzeSource()
548 {
549     MEDIA_INFO_LOG("analyze source later");
550 }
551 
MovePicture(FileInfo & fileInfo)552 int32_t CloneRestore::MovePicture(FileInfo &fileInfo)
553 {
554     bool deleteOriginalFile = fileInfo.isRelatedToPhotoMap == 1 ? false : true;
555     string localPath = BackupFileUtils::GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL,
556         fileInfo.cloudPath);
557     int32_t opRet = E_FAIL;
558     if (deleteOriginalFile) {
559         opRet = this->MoveFile(fileInfo.filePath, localPath);
560     } else {
561         opRet = this->CopyFile(fileInfo.filePath, localPath);
562     }
563     if (opRet != E_OK) {
564         MEDIA_ERR_LOG("Move photo file failed, filePath = %{public}s, deleteOriginalFile = %{public}d",
565             BackupFileUtils::GarbleFilePath(fileInfo.filePath, CLONE_RESTORE_ID, garbagePath_).c_str(),
566             deleteOriginalFile);
567         return E_FAIL;
568     }
569     return E_OK;
570 }
571 
MoveMovingPhotoVideo(FileInfo & fileInfo)572 int32_t CloneRestore::MoveMovingPhotoVideo(FileInfo &fileInfo)
573 {
574     if (fileInfo.subtype != static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
575         return E_OK;
576     }
577     bool deleteOriginalFile = fileInfo.isRelatedToPhotoMap == 1 ? false : true;
578     std::string localPath = BackupFileUtils::GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL,
579         fileInfo.cloudPath);
580     std::string srcLocalVideoPath = MediaFileUtils::GetMovingPhotoVideoPath(fileInfo.filePath);
581     if (!MediaFileUtils::IsFileExists(srcLocalVideoPath)) {
582         MEDIA_WARN_LOG("video of moving photo does not exist: %{private}s", srcLocalVideoPath.c_str());
583         return E_OK;
584     }
585     std::string localVideoPath = MediaFileUtils::GetMovingPhotoVideoPath(localPath);
586     int32_t opVideoRet = E_FAIL;
587     if (deleteOriginalFile) {
588         opVideoRet = this->MoveFile(srcLocalVideoPath, localVideoPath);
589     } else {
590         opVideoRet = this->CopyFile(srcLocalVideoPath, localVideoPath);
591     }
592     if (opVideoRet != E_OK) {
593         MEDIA_ERR_LOG("Move video of moving photo failed");
594         return E_FAIL;
595     }
596     BackupFileUtils::ModifyFile(localVideoPath, fileInfo.dateModified / MSEC_TO_SEC);
597     return E_OK;
598 }
599 
MoveEditedData(FileInfo & fileInfo)600 int32_t CloneRestore::MoveEditedData(FileInfo &fileInfo)
601 {
602     bool deleteOriginalFile = fileInfo.isRelatedToPhotoMap == 1 ? false : true;
603     string localPath =
604         BackupFileUtils::GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL, fileInfo.cloudPath);
605     string srcEditDataPath = this->backupRestoreDir_ + BackupFileUtils::GetFullPathByPrefixType(
606         PrefixType::LOCAL_EDIT_DATA, fileInfo.relativePath);
607     string dstEditDataPath = BackupFileUtils::GetReplacedPathByPrefixType(
608         PrefixType::CLOUD, PrefixType::LOCAL_EDIT_DATA, fileInfo.cloudPath);
609     if (this->IsFilePathExist(srcEditDataPath) &&
610         this->MoveDirectory(srcEditDataPath, dstEditDataPath, deleteOriginalFile) != E_OK) {
611         MEDIA_ERR_LOG("Move editData file failed");
612         return E_FAIL;
613     }
614     return E_OK;
615 }
616 
UpdateThumbnailStatusToFailed(std::shared_ptr<NativeRdb::RdbStore> & rdbStore,std::string id,bool isThumbnailStatusNeedUpdate,bool isLcdStatusNeedUpdate)617 static void UpdateThumbnailStatusToFailed(std::shared_ptr<NativeRdb::RdbStore> &rdbStore, std::string id,
618     bool isThumbnailStatusNeedUpdate, bool isLcdStatusNeedUpdate)
619 {
620     if (rdbStore == nullptr || id.empty()) {
621         return;
622     }
623 
624     NativeRdb::ValuesBucket values;
625     int changedRows;
626     if (isThumbnailStatusNeedUpdate) {
627         values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, RESTORE_THUMBNAIL_READY_NO_THUMBNAIL);
628         values.PutInt(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, RESTORE_THUMBNAIL_VISIBLE_FALSE);
629     }
630     if (isLcdStatusNeedUpdate) {
631         values.PutInt(PhotoColumn::PHOTO_LCD_VISIT_TIME, RESTORE_LCD_VISIT_TIME_NO_LCD);
632     }
633     int32_t err = rdbStore->Update(changedRows, PhotoColumn::PHOTOS_TABLE,
634         values, MEDIA_DATA_DB_ID + " = ?", vector<string> { id });
635     if (err != NativeRdb::E_OK) {
636         MEDIA_ERR_LOG("RdbStore Update failed! %{public}d", err);
637     }
638 }
639 
GetThumbnailLocalPath(const string path)640 static std::string GetThumbnailLocalPath(const string path)
641 {
642     size_t cloudDirLength = RESTORE_FILES_CLOUD_DIR.length();
643     if (path.length() <= cloudDirLength || path.substr(0, cloudDirLength).compare(RESTORE_FILES_CLOUD_DIR) != 0) {
644         return "";
645     }
646 
647     std::string suffixStr = path.substr(cloudDirLength);
648     return RESTORE_FILES_LOCAL_DIR + ".thumbs/" + suffixStr;
649 }
650 
MoveAstc(FileInfo & fileInfo)651 int32_t CloneRestore::MoveAstc(FileInfo &fileInfo)
652 {
653     if (oldMonthKvStorePtr_ == nullptr || oldYearKvStorePtr_ == nullptr ||
654         newMonthKvStorePtr_ == nullptr || newYearKvStorePtr_ == nullptr) {
655         MEDIA_ERR_LOG("Kvstore is nullptr");
656         return E_FAIL;
657     }
658     if (fileInfo.fileIdOld <= 0 || fileInfo.fileIdNew <= 0) {
659         MEDIA_ERR_LOG("Old fileId:%{public}d or new fileId:%{public}d is invalid",
660             fileInfo.fileIdOld, fileInfo.fileIdNew);
661         return E_FAIL;
662     }
663     string oldKey;
664     string newKey;
665     if (!MediaFileUtils::GenerateKvStoreKey(to_string(fileInfo.fileIdOld), fileInfo.oldAstcDateKey, oldKey) ||
666         !MediaFileUtils::GenerateKvStoreKey(to_string(fileInfo.fileIdNew), fileInfo.newAstcDateKey, newKey)) {
667         return E_FAIL;
668     }
669 
670     std::vector<uint8_t> monthValue;
671     std::vector<uint8_t> yearValue;
672     if (oldMonthKvStorePtr_->Query(oldKey, monthValue) != E_OK ||
673         newMonthKvStorePtr_->Insert(newKey, monthValue) != E_OK) {
674         MEDIA_ERR_LOG("MonthValue move failed, fileID %{public}s", newKey.c_str());
675         return E_FAIL;
676     }
677     if (oldYearKvStorePtr_->Query(oldKey, yearValue) != E_OK ||
678         newYearKvStorePtr_->Insert(newKey, yearValue) != E_OK) {
679         MEDIA_ERR_LOG("YearValue move failed, fileID %{public}s", newKey.c_str());
680         return E_FAIL;
681     }
682     if (fileInfo.isRelatedToPhotoMap != 1) {
683         oldMonthKvStorePtr_->Delete(oldKey);
684         oldYearKvStorePtr_->Delete(oldKey);
685     }
686     return E_OK;
687 }
688 
MoveThumbnailDir(FileInfo & fileInfo)689 int32_t CloneRestore::MoveThumbnailDir(FileInfo &fileInfo)
690 {
691     string thumbnailOldDir = backupRestoreDir_ + RESTORE_FILES_LOCAL_DIR + ".thumbs" + fileInfo.relativePath;
692     string thumbnailNewDir = GetThumbnailLocalPath(fileInfo.cloudPath);
693     if (fileInfo.relativePath.empty() || thumbnailNewDir.empty()) {
694         MEDIA_ERR_LOG("Old path:%{public}s or new path:%{public}s is invalid",
695             fileInfo.relativePath.c_str(), MediaFileUtils::DesensitizePath(fileInfo.cloudPath).c_str());
696         return E_FAIL;
697     }
698     if (!MediaFileUtils::IsDirectory(thumbnailOldDir)) {
699         MEDIA_ERR_LOG("Old dir is not a direcrory or does not exist, errno:%{public}d, dir:%{public}s",
700             errno, MediaFileUtils::DesensitizePath(thumbnailOldDir).c_str());
701         return E_FAIL;
702     }
703     if (BackupFileUtils::PreparePath(thumbnailNewDir) != E_OK) {
704         MEDIA_ERR_LOG("Prepare thumbnail dir path failed");
705         return E_FAIL;
706     }
707     if (MediaFileUtils::IsFileExists(thumbnailNewDir) && !MediaFileUtils::DeleteDir(thumbnailNewDir)) {
708         MEDIA_ERR_LOG("Delete thumbnail new dir failed, errno:%{public}d", errno);
709         return E_FAIL;
710     }
711 
712     int32_t opRet = E_FAIL;
713     if (fileInfo.isRelatedToPhotoMap != 1) {
714         opRet = MediaFileUtils::ModifyAsset(thumbnailOldDir, thumbnailNewDir);
715     } else {
716         opRet = MediaFileUtils::CopyDirectory(thumbnailOldDir, thumbnailNewDir);
717     }
718     if (opRet != E_OK) {
719         if (!MediaFileUtils::IsFileExists(thumbnailNewDir)) {
720             return opRet;
721         }
722         MEDIA_WARN_LOG("MoveThumbnailDir failed but thumbnailNewDir exists");
723         if (!MediaFileUtils::DeleteDir(thumbnailNewDir)) {
724             MEDIA_ERR_LOG("Delete existential thumbnailNewDir failed, errno:%{public}d", errno);
725         }
726         return opRet;
727     }
728     return E_OK;
729 }
730 
731 /**
732  * The processing logic of the MoveThumbnail function must match the logic of the GetThumbnailInsertValue function.
733  * If the status indicates that the thumbnail does not exist, the thumbnail does not need to be cloned and
734  * the status of the thumbnail needs to be set to the initial status in the GetThumbnailInsertValue function.
735  * If the status indicates that the thumbnail exists but the thumbnail fails to be transferred,
736  * the thumbnail status needs to be set to the initial status.
737 */
MoveThumbnail(FileInfo & fileInfo)738 int32_t CloneRestore::MoveThumbnail(FileInfo &fileInfo)
739 {
740     if (!hasCloneThumbnailDir_) {
741         return E_NO_SUCH_FILE;
742     }
743     if (fileInfo.thumbnailReady < RESTORE_THUMBNAIL_READY_SUCCESS &&
744         fileInfo.lcdVisitTime < RESTORE_LCD_VISIT_TIME_SUCCESS) {
745         MEDIA_INFO_LOG("Thumbnail dose not exist, id:%{public}d, path:%{public}s",
746             fileInfo.fileIdNew, MediaFileUtils::DesensitizePath(fileInfo.cloudPath).c_str());
747         return E_NO_SUCH_FILE;
748     }
749     if (MoveThumbnailDir(fileInfo) != E_OK) {
750         UpdateThumbnailStatusToFailed(mediaLibraryRdb_, to_string(fileInfo.fileIdNew), true, true);
751         MEDIA_ERR_LOG("Move thumbnail failed, id:%{public}d, path:%{public}s",
752             fileInfo.fileIdNew, MediaFileUtils::DesensitizePath(fileInfo.cloudPath).c_str());
753         return E_FAIL;
754     }
755 
756     if (!isInitKvstoreSuccess_) {
757         return E_NO_SUCH_FILE;
758     }
759     if (fileInfo.thumbnailReady < RESTORE_THUMBNAIL_READY_SUCCESS) {
760         MEDIA_ERR_LOG("Astc does not exist, id:%{public}d, path:%{public}s",
761             fileInfo.fileIdNew, MediaFileUtils::DesensitizePath(fileInfo.cloudPath).c_str());
762         return E_NO_SUCH_FILE;
763     }
764     if (MoveAstc(fileInfo) != E_OK) {
765         UpdateThumbnailStatusToFailed(mediaLibraryRdb_, to_string(fileInfo.fileIdNew), true, false);
766         MEDIA_ERR_LOG("Move astc failed, id:%{public}d, path:%{public}s",
767             fileInfo.fileIdNew, MediaFileUtils::DesensitizePath(fileInfo.cloudPath).c_str());
768         return E_FAIL;
769     }
770 
771     MediaLibraryPhotoOperations::StoreThumbnailSize(to_string(fileInfo.fileIdNew), fileInfo.cloudPath);
772     return E_OK;
773 }
774 
MoveAsset(FileInfo & fileInfo)775 int32_t CloneRestore::MoveAsset(FileInfo &fileInfo)
776 {
777     // Picture files.
778     int32_t optRet = this->MovePicture(fileInfo);
779     if (optRet != E_OK) {
780         return E_FAIL;
781     }
782     // Video files of moving photo.
783     optRet = this->MoveMovingPhotoVideo(fileInfo);
784     if (optRet != E_OK) {
785         return E_FAIL;
786     }
787     // Edit Data.
788     optRet = this->MoveEditedData(fileInfo);
789     if (optRet != E_OK) {
790         return E_FAIL;
791     }
792     // Thumbnail of photos.
793     this->MoveThumbnail(fileInfo);
794     return E_OK;
795 }
796 
IsFilePathExist(const string & filePath) const797 bool CloneRestore::IsFilePathExist(const string &filePath) const
798 {
799     if (!MediaFileUtils::IsFileExists(filePath)) {
800         MEDIA_DEBUG_LOG("%{private}s doesn't exist", filePath.c_str());
801         return false;
802     }
803     if (MediaFileUtils::IsDirectory(filePath) && MediaFileUtils::IsDirEmpty(filePath)) {
804         MEDIA_DEBUG_LOG("%{private}s is an empty directory", filePath.c_str());
805         return false;
806     }
807     return true;
808 }
809 
GetThumbnailInsertValue(const FileInfo & fileInfo,NativeRdb::ValuesBucket & values)810 void CloneRestore::GetThumbnailInsertValue(const FileInfo &fileInfo, NativeRdb::ValuesBucket &values)
811 {
812     if (!hasCloneThumbnailDir_) {
813         // If there is no thumbnail directory, all statuses of thumbnail are set to the initial status.
814         values.PutInt(PhotoColumn::PHOTO_LCD_VISIT_TIME, RESTORE_LCD_VISIT_TIME_NO_LCD);
815         values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, RESTORE_THUMBNAIL_READY_NO_THUMBNAIL);
816         values.PutInt(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, RESTORE_THUMBNAIL_VISIBLE_FALSE);
817         return;
818     }
819 
820     // The LCD status is same as the origin status.
821     values.PutInt(PhotoColumn::PHOTO_LCD_VISIT_TIME, fileInfo.lcdVisitTime);
822     if (!isInitKvstoreSuccess_ || fileInfo.thumbnailReady < RESTORE_THUMBNAIL_READY_SUCCESS) {
823         // The kvdb does not exist or the THM status indicates that there is no THM.
824         // Therefore, the THM status needs to be set to the initial status.
825         values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, RESTORE_THUMBNAIL_READY_NO_THUMBNAIL);
826         values.PutInt(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, RESTORE_THUMBNAIL_VISIBLE_FALSE);
827         return;
828     }
829     values.PutLong(PhotoColumn::PHOTO_THUMBNAIL_READY, fileInfo.thumbnailReady);
830     values.PutInt(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE, RESTORE_THUMBNAIL_VISIBLE_TRUE);
831 }
832 
GetInsertValue(const FileInfo & fileInfo,const string & newPath,int32_t sourceType)833 NativeRdb::ValuesBucket CloneRestore::GetInsertValue(const FileInfo &fileInfo, const string &newPath,
834     int32_t sourceType)
835 {
836     NativeRdb::ValuesBucket values;
837     values.PutString(MediaColumn::MEDIA_FILE_PATH, newPath);
838     values.PutLong(MediaColumn::MEDIA_SIZE, fileInfo.fileSize);
839     values.PutInt(MediaColumn::MEDIA_TYPE, fileInfo.fileType);
840     values.PutString(MediaColumn::MEDIA_NAME, fileInfo.displayName);
841     values.PutLong(MediaColumn::MEDIA_DATE_ADDED, fileInfo.dateAdded);
842     values.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, fileInfo.dateModified);
843     values.PutInt(PhotoColumn::PHOTO_ORIENTATION, fileInfo.orientation); // photos need orientation
844     values.PutInt(PhotoColumn::PHOTO_SUBTYPE, fileInfo.subtype);
845     // use owner_album_id to mark the album id which the photo is in.
846     values.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, fileInfo.ownerAlbumId);
847     // Only SOURCE album has package_name and owner_package.
848     values.PutString(MediaColumn::MEDIA_PACKAGE_NAME, fileInfo.packageName);
849     values.PutString(MediaColumn::MEDIA_OWNER_PACKAGE, fileInfo.bundleName);
850     if (fileInfo.packageName.empty() && fileInfo.bundleName.empty()) {
851         // package_name and owner_package are empty, clear owner_appid
852         values.PutString(MediaColumn::MEDIA_OWNER_APPID, "");
853     }
854     values.PutInt(PhotoColumn::PHOTO_QUALITY, fileInfo.photoQuality);
855     values.PutLong(MediaColumn::MEDIA_DATE_TRASHED, fileInfo.recycledTime);
856     values.PutInt(MediaColumn::MEDIA_HIDDEN, fileInfo.hidden);
857     values.PutString(PhotoColumn::PHOTO_SOURCE_PATH, fileInfo.sourcePath);
858     GetThumbnailInsertValue(fileInfo, values);
859 
860     unordered_map<string, string> commonColumnInfoMap = GetValueFromMap(tableCommonColumnInfoMap_,
861         PhotoColumn::PHOTOS_TABLE);
862     for (auto it = fileInfo.valMap.begin(); it != fileInfo.valMap.end(); ++it) {
863         string columnName = it->first;
864         auto columnVal = it->second;
865         if (columnName == PhotoColumn::PHOTO_EDIT_TIME) {
866             PrepareEditTimeVal(values, get<int64_t>(columnVal), fileInfo, commonColumnInfoMap);
867             continue;
868         }
869         if (columnName == PhotoColumn::MEDIA_DATE_TAKEN) {
870             if (get<int64_t>(columnVal) > SECONDS_LEVEL_LIMIT) {
871                 values.PutLong(MediaColumn::MEDIA_DATE_TAKEN, get<int64_t>(columnVal));
872             } else {
873                 values.PutLong(MediaColumn::MEDIA_DATE_TAKEN, get<int64_t>(columnVal) * MSEC_TO_SEC);
874             }
875             continue;
876         }
877         PrepareCommonColumnVal(values, columnName, columnVal, commonColumnInfoMap);
878     }
879     return values;
880 }
881 
PrepareCommonColumnInfoMap(const string & tableName,const unordered_map<string,string> & srcColumnInfoMap,const unordered_map<string,string> & dstColumnInfoMap)882 bool CloneRestore::PrepareCommonColumnInfoMap(const string &tableName,
883     const unordered_map<string, string> &srcColumnInfoMap, const unordered_map<string, string> &dstColumnInfoMap)
884 {
885     auto neededColumns = GetValueFromMap(NEEDED_COLUMNS_MAP, tableName);
886     auto neededColumnsException = GetValueFromMap(NEEDED_COLUMNS_EXCEPTION_MAP, tableName);
887     auto excludedColumns = GetValueFromMap(EXCLUDED_COLUMNS_MAP, tableName);
888     auto &commonColumnInfoMap = tableCommonColumnInfoMap_[tableName];
889     if (!HasColumns(dstColumnInfoMap, neededColumns)) {
890         MEDIA_ERR_LOG("Destination lack needed columns");
891         return false;
892     }
893     for (auto it = dstColumnInfoMap.begin(); it != dstColumnInfoMap.end(); ++it) {
894         if (!HasSameColumn(srcColumnInfoMap, it->first, it->second) || excludedColumns.count(it->first) > 0) {
895             continue;
896         }
897         if (neededColumns.count(it->first) > 0 && (neededColumnsException.empty() ||
898             neededColumnsException.count(it->first) == 0)) {
899             continue;
900         }
901         commonColumnInfoMap[it->first] = it->second;
902     }
903     MEDIA_INFO_LOG("Table %{public}s has %{public}zu common columns",
904         BackupDatabaseUtils::GarbleInfoName(tableName).c_str(), commonColumnInfoMap.size());
905     return true;
906 }
907 
HasSameColumn(const unordered_map<string,string> & columnInfoMap,const string & columnName,const string & columnType)908 bool CloneRestore::HasSameColumn(const unordered_map<string, string> &columnInfoMap, const string &columnName,
909     const string &columnType)
910 {
911     auto it = columnInfoMap.find(columnName);
912     return it != columnInfoMap.end() && it->second == columnType;
913 }
914 
GetValFromResultSet(const shared_ptr<NativeRdb::ResultSet> & resultSet,unordered_map<string,variant<int32_t,int64_t,double,string>> & valMap,const string & columnName,const string & columnType)915 void CloneRestore::GetValFromResultSet(const shared_ptr<NativeRdb::ResultSet> &resultSet,
916     unordered_map<string, variant<int32_t, int64_t, double, string>> &valMap, const string &columnName,
917     const string &columnType)
918 {
919     int32_t columnIndex = 0;
920     int32_t errCode = resultSet->GetColumnIndex(columnName, columnIndex);
921     if (errCode) {
922         MEDIA_ERR_LOG("Get column index errCode: %{public}d", errCode);
923         return;
924     }
925     bool isNull = false;
926     errCode = resultSet->IsColumnNull(columnIndex, isNull);
927     if (errCode || isNull) {
928         return;
929     }
930     ResultSetDataType dataType = GetValueFromMap(COLUMN_TYPE_MAP, columnType, ResultSetDataType::TYPE_NULL);
931     switch (dataType) {
932         case ResultSetDataType::TYPE_INT32: {
933             int32_t int32Val;
934             if (resultSet->GetInt(columnIndex, int32Val) == E_OK) {
935                 valMap[columnName] = int32Val;
936             }
937             break;
938         }
939         case ResultSetDataType::TYPE_INT64: {
940             int64_t int64Val;
941             if (resultSet->GetLong(columnIndex, int64Val) == E_OK) {
942                 valMap[columnName] = int64Val;
943             }
944             break;
945         }
946         case ResultSetDataType::TYPE_DOUBLE: {
947             double doubleVal;
948             if (resultSet->GetDouble(columnIndex, doubleVal) == E_OK) {
949                 valMap[columnName] = doubleVal;
950             }
951             break;
952         }
953         case ResultSetDataType::TYPE_STRING: {
954             string stringVal;
955             if (resultSet->GetString(columnIndex, stringVal) == E_OK) {
956                 valMap[columnName] = stringVal;
957             }
958             break;
959         }
960         default:
961             MEDIA_ERR_LOG("No such column type: %{public}s", columnType.c_str());
962     }
963 }
964 
PrepareCommonColumnVal(NativeRdb::ValuesBucket & values,const string & columnName,const variant<int32_t,int64_t,double,string> & columnVal,const unordered_map<string,string> & commonColumnInfoMap) const965 void CloneRestore::PrepareCommonColumnVal(NativeRdb::ValuesBucket &values, const string &columnName,
966     const variant<int32_t, int64_t, double, string> &columnVal,
967     const unordered_map<string, string> &commonColumnInfoMap) const
968 {
969     string columnType = GetValueFromMap(commonColumnInfoMap, columnName);
970     if (columnType.empty()) {
971         MEDIA_ERR_LOG("No such column %{public}s", columnName.c_str());
972         return;
973     }
974     ResultSetDataType dataType = GetValueFromMap(COLUMN_TYPE_MAP, columnType, ResultSetDataType::TYPE_NULL);
975     switch (dataType) {
976         case ResultSetDataType::TYPE_INT32: {
977             values.PutInt(columnName, get<int32_t>(columnVal));
978             break;
979         }
980         case ResultSetDataType::TYPE_INT64: {
981             values.PutLong(columnName, get<int64_t>(columnVal));
982             break;
983         }
984         case ResultSetDataType::TYPE_DOUBLE: {
985             values.PutDouble(columnName, get<double>(columnVal));
986             break;
987         }
988         case ResultSetDataType::TYPE_STRING: {
989             values.PutString(columnName, get<string>(columnVal));
990             break;
991         }
992         default:
993             MEDIA_ERR_LOG("No such column type: %{public}s", columnType.c_str());
994     }
995 }
996 
GetQueryWhereClause(const string & tableName,const unordered_map<string,string> & columnInfoMap)997 void CloneRestore::GetQueryWhereClause(const string &tableName, const unordered_map<string, string> &columnInfoMap)
998 {
999     auto queryWhereClauseMap = GetValueFromMap(TABLE_QUERY_WHERE_CLAUSE_MAP, tableName);
1000     if (queryWhereClauseMap.empty()) {
1001         return;
1002     }
1003     string &queryWhereClause = tableQueryWhereClauseMap_[tableName];
1004     queryWhereClause.clear();
1005     for (auto it = queryWhereClauseMap.begin(); it != queryWhereClauseMap.end(); ++it) {
1006         if (columnInfoMap.count(it->first) == 0) {
1007             continue;
1008         }
1009         if (!queryWhereClause.empty()) {
1010             queryWhereClause += " AND ";
1011         }
1012         queryWhereClause += it->second + " ";
1013     }
1014 }
1015 
GetAlbumExtraQueryWhereClause(const string & tableName)1016 void CloneRestore::GetAlbumExtraQueryWhereClause(const string &tableName)
1017 {
1018     string mapTableName = GetValueFromMap(CLONE_ALBUM_MAP, tableName);
1019     if (mapTableName.empty()) {
1020         MEDIA_ERR_LOG("Get map of table %{public}s failed", BackupDatabaseUtils::GarbleInfoName(tableName).c_str());
1021         return;
1022     }
1023     string albumQueryWhereClause = "EXISTS (SELECT " + PhotoMap::ASSET_ID + " FROM " + mapTableName + " WHERE " +
1024         PhotoMap::ALBUM_ID + " = " + PhotoAlbumColumns::ALBUM_ID + " AND EXISTS (SELECT " + MediaColumn::MEDIA_ID +
1025         " FROM " + PhotoColumn::PHOTOS_TABLE + " WHERE " + MediaColumn::MEDIA_ID + " = " + PhotoMap::ASSET_ID;
1026     string photoQueryWhereClause = GetValueFromMap(tableQueryWhereClauseMap_, PhotoColumn::PHOTOS_TABLE);
1027     if (!photoQueryWhereClause.empty()) {
1028         albumQueryWhereClause += " AND " + photoQueryWhereClause;
1029     }
1030     albumQueryWhereClause += "))";
1031     tableExtraQueryWhereClauseMap_[tableName] = albumQueryWhereClause;
1032 }
1033 
GetInsertValue(const AlbumInfo & albumInfo,const string & tableName) const1034 NativeRdb::ValuesBucket CloneRestore::GetInsertValue(const AlbumInfo &albumInfo, const string &tableName) const
1035 {
1036     NativeRdb::ValuesBucket values;
1037     values.PutInt(PhotoAlbumColumns::ALBUM_TYPE, static_cast<int32_t>(albumInfo.albumType));
1038     values.PutInt(PhotoAlbumColumns::ALBUM_SUBTYPE, static_cast<int32_t>(albumInfo.albumSubType));
1039     values.PutString(PhotoAlbumColumns::ALBUM_NAME, albumInfo.albumName);
1040 
1041     if (tableName == PhotoAlbumColumns::TABLE) {
1042         values.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED,
1043             (albumInfo.dateModified ? albumInfo.dateModified : MediaFileUtils::UTCTimeMilliSeconds()));
1044     }
1045 
1046     unordered_map<string, string> commonColumnInfoMap = GetValueFromMap(tableCommonColumnInfoMap_, tableName);
1047     for (auto it = albumInfo.valMap.begin(); it != albumInfo.valMap.end(); ++it) {
1048         string columnName = it->first;
1049         auto columnVal = it->second;
1050         PrepareCommonColumnVal(values, columnName, columnVal, commonColumnInfoMap);
1051     }
1052     return values;
1053 }
1054 
BatchQueryPhoto(vector<FileInfo> & fileInfos)1055 void CloneRestore::BatchQueryPhoto(vector<FileInfo> &fileInfos)
1056 {
1057     string selection;
1058     unordered_map<string, size_t> fileIndexMap;
1059     for (size_t index = 0; index < fileInfos.size(); index++) {
1060         if (fileInfos[index].cloudPath.empty()) {
1061             continue;
1062         }
1063         BackupDatabaseUtils::UpdateSelection(selection, fileInfos[index].cloudPath, true);
1064         fileIndexMap[fileInfos[index].cloudPath] = index;
1065     }
1066     string querySql = "SELECT " + MediaColumn::MEDIA_ID + ", " + MediaColumn::MEDIA_FILE_PATH + ", " +
1067         MediaColumn::MEDIA_DATE_TAKEN + " FROM " + PhotoColumn::PHOTOS_TABLE +
1068         " WHERE " + MediaColumn::MEDIA_FILE_PATH + " IN (" + selection + ")";
1069     querySql += " LIMIT " + to_string(fileIndexMap.size());
1070     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql);
1071     if (resultSet == nullptr) {
1072         MEDIA_ERR_LOG("Query resultSql is null.");
1073         return;
1074     }
1075     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1076         int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
1077         string cloudPath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
1078         string dateTaken = GetStringVal(MediaColumn::MEDIA_DATE_TAKEN, resultSet);
1079         if (fileId <= 0) {
1080             MEDIA_ERR_LOG("Get fileId invalid: %{public}d", fileId);
1081             continue;
1082         }
1083         if (fileIndexMap.count(cloudPath) == 0) {
1084             continue;
1085         }
1086         size_t index = fileIndexMap.at(cloudPath);
1087         fileInfos[index].fileIdNew = fileId;
1088         fileInfos[index].newAstcDateKey = dateTaken;
1089     }
1090     BackupDatabaseUtils::UpdateAssociateFileId(mediaLibraryRdb_, fileInfos);
1091 }
1092 
BatchNotifyPhoto(const vector<FileInfo> & fileInfos)1093 void CloneRestore::BatchNotifyPhoto(const vector<FileInfo> &fileInfos)
1094 {
1095     auto watch = MediaLibraryNotify::GetInstance();
1096     if (watch == nullptr) {
1097         MEDIA_ERR_LOG("Get MediaLibraryNotify instance failed");
1098         return;
1099     }
1100     for (const auto &fileInfo : fileInfos) {
1101         if (!fileInfo.needMove || fileInfo.cloudPath.empty()) {
1102             continue;
1103         }
1104         string extraUri = MediaFileUtils::GetExtraUri(fileInfo.displayName, fileInfo.cloudPath);
1105         string notifyUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
1106             to_string(fileInfo.fileIdNew), extraUri);
1107         watch->Notify(notifyUri, NotifyType::NOTIFY_ADD);
1108     }
1109 }
1110 
InsertAlbum(vector<AlbumInfo> & albumInfos,const string & tableName)1111 void CloneRestore::InsertAlbum(vector<AlbumInfo> &albumInfos, const string &tableName)
1112 {
1113     if (mediaLibraryRdb_ == nullptr) {
1114         MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
1115         return;
1116     }
1117     if (albumInfos.empty()) {
1118         MEDIA_ERR_LOG("albumInfos are empty");
1119         return;
1120     }
1121     int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
1122     vector<NativeRdb::ValuesBucket> values = GetInsertValues(albumInfos, tableName);
1123     int64_t rowNum = 0;
1124     int32_t errCode = BatchInsertWithRetry(tableName, values, rowNum);
1125     if (errCode != E_OK) {
1126         return;
1127     }
1128     migrateDatabaseAlbumNumber_ += rowNum;
1129 
1130     int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
1131     BatchQueryAlbum(albumInfos, tableName);
1132     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1133     MEDIA_INFO_LOG("insert %{public}ld albums cost %{public}ld, query cost %{public}ld.", (long)rowNum,
1134         (long)(startQuery - startInsert), (long)(end - startQuery));
1135 }
1136 
GetInsertValues(vector<AlbumInfo> & albumInfos,const string & tableName)1137 vector<NativeRdb::ValuesBucket> CloneRestore::GetInsertValues(vector<AlbumInfo> &albumInfos,
1138     const string &tableName)
1139 {
1140     vector<NativeRdb::ValuesBucket> values;
1141     for (size_t i = 0; i < albumInfos.size(); i++) {
1142         if (HasSameAlbum(albumInfos[i], tableName)) {
1143             MEDIA_WARN_LOG("Album (%{public}d, %{public}d, %{public}d, %{public}s) already exists.",
1144                 albumInfos[i].albumIdOld, static_cast<int32_t>(albumInfos[i].albumType),
1145                 static_cast<int32_t>(albumInfos[i].albumSubType), albumInfos[i].albumName.c_str());
1146             continue;
1147         }
1148         NativeRdb::ValuesBucket value = GetInsertValue(albumInfos[i], tableName);
1149         values.emplace_back(value);
1150     }
1151     return values;
1152 }
1153 
HasSameAlbum(const AlbumInfo & albumInfo,const string & tableName)1154 bool CloneRestore::HasSameAlbum(const AlbumInfo &albumInfo, const string &tableName)
1155 {
1156     // check if the album already exists
1157     if (tableName == PhotoAlbumColumns::TABLE) {
1158         return this->photoAlbumClone_.HasSameAlbum(albumInfo.lPath);
1159     }
1160     string querySql = "SELECT " + MEDIA_COLUMN_COUNT_1 + " FROM " + tableName + " WHERE " +
1161         PhotoAlbumColumns::ALBUM_TYPE + " = " + to_string(albumInfo.albumType) + " AND " +
1162         PhotoAlbumColumns::ALBUM_SUBTYPE + " = " + to_string(albumInfo.albumSubType) + " AND " +
1163         PhotoAlbumColumns::ALBUM_NAME + " = '" + albumInfo.albumName + "'";
1164     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql);
1165     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1166         return false;
1167     }
1168     int32_t count = GetInt32Val(MEDIA_COLUMN_COUNT_1, resultSet);
1169     return count > 0;
1170 }
1171 
BatchQueryAlbum(vector<AlbumInfo> & albumInfos,const string & tableName)1172 void CloneRestore::BatchQueryAlbum(vector<AlbumInfo> &albumInfos, const string &tableName)
1173 {
1174     auto &albumIdMap = tableAlbumIdMap_[tableName];
1175     for (auto &albumInfo : albumInfos) {
1176         if (albumInfo.albumIdOld <= 0) {
1177             continue;
1178         }
1179         string querySql = "SELECT " + PhotoAlbumColumns::ALBUM_ID + " FROM " + tableName + " WHERE " +
1180             PhotoAlbumColumns::ALBUM_TYPE + " = " + to_string(albumInfo.albumType) + " AND " +
1181             PhotoAlbumColumns::ALBUM_SUBTYPE + " = " + to_string(albumInfo.albumSubType) + " AND " +
1182             PhotoAlbumColumns::ALBUM_NAME + " = '" + albumInfo.albumName + "'";
1183         auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql);
1184         if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1185             continue;
1186         }
1187         albumInfo.albumIdNew = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
1188         if (albumInfo.albumIdNew <= 0) {
1189             continue;
1190         }
1191         albumIdMap[albumInfo.albumIdOld] = albumInfo.albumIdNew;
1192     }
1193 }
1194 
BatchInsertMap(const vector<FileInfo> & fileInfos,int64_t & totalRowNum)1195 void CloneRestore::BatchInsertMap(const vector<FileInfo> &fileInfos, int64_t &totalRowNum)
1196 {
1197     string selection;
1198     unordered_map<int32_t, int32_t> fileIdMap;
1199     SetFileIdReference(fileInfos, selection, fileIdMap);
1200     std::string tableName = ANALYSIS_ALBUM_TABLE;
1201     string garbledTableName = BackupDatabaseUtils::GarbleInfoName(tableName);
1202     string mapTableName = GetValueFromMap(CLONE_ALBUM_MAP, tableName);
1203     if (mapTableName.empty()) {
1204         MEDIA_ERR_LOG("Get map of table %{public}s failed", garbledTableName.c_str());
1205         return;
1206     }
1207     auto albumIdMap = GetValueFromMap(tableAlbumIdMap_, tableName);
1208     if (albumIdMap.empty()) {
1209         MEDIA_INFO_LOG("Get album id map of table %{public}s empty, skip", garbledTableName.c_str());
1210         return;
1211     }
1212     string albumSelection = GetValueFromMap(tableQueryWhereClauseMap_, tableName);
1213     unordered_set<int32_t> currentTableAlbumSet;
1214     string baseQuerySql = mapTableName + " INNER JOIN " + tableName + " ON " +
1215         mapTableName + "." + PhotoMap::ALBUM_ID + " = " + tableName + "." + PhotoAlbumColumns::ALBUM_ID +
1216         " WHERE " + mapTableName + "." + PhotoMap::ASSET_ID + " IN (" + selection + ")";
1217     baseQuerySql += albumSelection.empty() ? "" : " AND " + albumSelection;
1218     int32_t totalNumber = QueryMapTotalNumber(baseQuerySql);
1219     MEDIA_INFO_LOG("QueryMapTotalNumber of table %{public}s, totalNumber = %{public}d", garbledTableName.c_str(),
1220         totalNumber);
1221     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
1222         int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
1223         vector<MapInfo> mapInfos = QueryMapInfos(mapTableName, baseQuerySql, offset, fileIdMap, albumIdMap);
1224         int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
1225         int64_t rowNum = InsertMapByTable(mapTableName, mapInfos, currentTableAlbumSet);
1226         totalRowNum += rowNum;
1227         int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1228         MEDIA_INFO_LOG("query %{public}zu map infos cost %{public}ld, insert %{public}ld maps cost %{public}ld",
1229             mapInfos.size(), (long)(startInsert - startQuery), (long)rowNum, (long)(end - startInsert));
1230     }
1231     UpdateAlbumToNotifySet(tableName, currentTableAlbumSet);
1232 }
1233 
GetInsertValue(const MapInfo & mapInfo) const1234 NativeRdb::ValuesBucket CloneRestore::GetInsertValue(const MapInfo &mapInfo) const
1235 {
1236     NativeRdb::ValuesBucket values;
1237     values.PutInt(PhotoMap::ASSET_ID, mapInfo.fileId);
1238     values.PutInt(PhotoMap::ALBUM_ID, mapInfo.albumId);
1239     return values;
1240 }
1241 
CheckTableColumnStatus(shared_ptr<NativeRdb::RdbStore> rdbStore,const vector<vector<string>> & cloneTableList)1242 void CloneRestore::CheckTableColumnStatus(shared_ptr<NativeRdb::RdbStore> rdbStore,
1243     const vector<vector<string>> &cloneTableList)
1244 {
1245     unordered_map<string, unordered_map<string, string>> tableColumnInfoMap;
1246     for (const auto &tableList : cloneTableList) {
1247         bool columnStatusGlobal = true;
1248         for (const auto &tableName : tableList) {
1249             auto &columnInfoMap = tableColumnInfoMap[tableName];
1250             columnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(rdbStore, tableName);
1251             auto neededColumns = GetValueFromMap(NEEDED_COLUMNS_MAP, tableName);
1252             columnStatusGlobal = columnStatusGlobal && HasColumns(columnInfoMap, neededColumns);
1253         }
1254         for (const auto &tableName : tableList) {
1255             tableColumnStatusMap_[tableName] = columnStatusGlobal;
1256         }
1257     }
1258     for (const auto &tableList : cloneTableList) {
1259         for (const auto &tableName : tableList) {
1260             if (!IsReadyForRestore(tableName)) {
1261                 MEDIA_ERR_LOG("Column status is false");
1262                 break;
1263             }
1264             auto columnInfoMap = GetValueFromMap(tableColumnInfoMap, tableName);
1265             GetQueryWhereClause(tableName, columnInfoMap);
1266         }
1267     }
1268 }
1269 
HasColumns(const unordered_map<string,string> & columnInfoMap,const unordered_set<string> & columnSet)1270 bool CloneRestore::HasColumns(const unordered_map<string, string> &columnInfoMap,
1271     const unordered_set<string> &columnSet)
1272 {
1273     for (const auto &columnName : columnSet) {
1274         if (!HasColumn(columnInfoMap, columnName)) {
1275             MEDIA_ERR_LOG("Lack of column %{public}s", columnName.c_str());
1276             return false;
1277         }
1278     }
1279     return true;
1280 }
1281 
HasColumn(const unordered_map<string,string> & columnInfoMap,const string & columnName)1282 bool CloneRestore::HasColumn(const unordered_map<string, string> &columnInfoMap, const string &columnName)
1283 {
1284     return columnInfoMap.count(columnName) > 0;
1285 }
1286 
IsReadyForRestore(const string & tableName)1287 bool CloneRestore::IsReadyForRestore(const string &tableName)
1288 {
1289     return GetValueFromMap(tableColumnStatusMap_, tableName, false);
1290 }
1291 
UpdateAlbumToNotifySet(const string & tableName,const unordered_set<int32_t> & albumSet)1292 void CloneRestore::UpdateAlbumToNotifySet(const string &tableName, const unordered_set<int32_t> &albumSet)
1293 {
1294     string albumUriPrefix = GetValueFromMap(ALBUM_URI_PREFIX_MAP, tableName);
1295     if (albumUriPrefix.empty()) {
1296         MEDIA_ERR_LOG("Get album uri prefix of %{public}s failed",
1297             BackupDatabaseUtils::GarbleInfoName(tableName).c_str());
1298         return;
1299     }
1300     for (auto albumId : albumSet) {
1301         string albumUri = MediaFileUtils::GetUriByExtrConditions(albumUriPrefix, to_string(albumId));
1302         albumToNotifySet_.insert(albumUri);
1303     }
1304 }
1305 
NotifyAlbum()1306 void CloneRestore::NotifyAlbum()
1307 {
1308     auto watch = MediaLibraryNotify::GetInstance();
1309     if (watch == nullptr) {
1310         MEDIA_ERR_LOG("Get MediaLibraryNotify instance failed");
1311         return;
1312     }
1313     for (const auto &albumUri : albumToNotifySet_) {
1314         watch->Notify(albumUri, NotifyType::NOTIFY_ADD);
1315     }
1316     for (int32_t systemAlbumId = SYSTEM_ALBUM_ID_START; systemAlbumId <= SYSTEM_ALBUM_ID_END; systemAlbumId++) {
1317         watch->Notify(PhotoAlbumColumns::ALBUM_URI_PREFIX + to_string(systemAlbumId), NotifyType::NOTIFY_UPDATE);
1318     }
1319     MEDIA_INFO_LOG("System albums and %{public}zu albums notified", albumToNotifySet_.size());
1320 }
1321 
PrepareEditTimeVal(NativeRdb::ValuesBucket & values,int64_t editTime,const FileInfo & fileInfo,const unordered_map<string,string> & commonColumnInfoMap) const1322 void CloneRestore::PrepareEditTimeVal(NativeRdb::ValuesBucket &values, int64_t editTime, const FileInfo &fileInfo,
1323     const unordered_map<string, string> &commonColumnInfoMap) const
1324 {
1325     string editDataPath = backupRestoreDir_ +
1326         BackupFileUtils::GetFullPathByPrefixType(PrefixType::LOCAL_EDIT_DATA, fileInfo.relativePath);
1327     int64_t newEditTime = editTime > 0 && IsFilePathExist(editDataPath) ? editTime : 0;
1328     PrepareCommonColumnVal(values, PhotoColumn::PHOTO_EDIT_TIME, newEditTime, commonColumnInfoMap);
1329 }
1330 
RestoreGallery()1331 void CloneRestore::RestoreGallery()
1332 {
1333     CheckTableColumnStatus(mediaRdb_, CLONE_TABLE_LISTS_PHOTO);
1334     // Upgrade original MediaLibrary Database
1335     DataTransfer::MediaLibraryDbUpgrade medialibraryDbUpgrade;
1336     medialibraryDbUpgrade.OnUpgrade(*this->mediaRdb_);
1337     // Report the old db info.
1338     DatabaseReport()
1339         .SetSceneCode(this->sceneCode_)
1340         .SetTaskId(this->taskId_)
1341         .ReportMedia(this->mediaRdb_, DatabaseReport::PERIOD_OLD)
1342         .ReportMedia(this->mediaLibraryRdb_, DatabaseReport::PERIOD_BEFORE);
1343     // Restore the backup db info.
1344     RestoreAlbum();
1345     RestorePhoto();
1346     MEDIA_INFO_LOG("migrate database photo number: %{public}lld, file number: %{public}lld (%{public}lld + "
1347         "%{public}lld), duplicate number: %{public}lld + %{public}lld, album number: %{public}lld, map number: "
1348         "%{public}lld", (long long)migrateDatabaseNumber_, (long long)migrateFileNumber_,
1349         (long long)(migrateFileNumber_ - migrateVideoFileNumber_), (long long)migrateVideoFileNumber_,
1350         (long long)migratePhotoDuplicateNumber_, (long long)migrateVideoDuplicateNumber_,
1351         (long long)migrateDatabaseAlbumNumber_, (long long)migrateDatabaseMapNumber_);
1352     MEDIA_INFO_LOG("Start update group tags");
1353     BackupDatabaseUtils::UpdateFaceGroupTagsUnion(mediaLibraryRdb_);
1354 }
1355 
PrepareCloudPath(const string & tableName,FileInfo & fileInfo)1356 bool CloneRestore::PrepareCloudPath(const string &tableName, FileInfo &fileInfo)
1357 {
1358     fileInfo.cloudPath = BackupFileUtils::GetFullPathByPrefixType(PrefixType::CLOUD, fileInfo.relativePath);
1359     if (fileInfo.cloudPath.empty()) {
1360         MEDIA_ERR_LOG("Get cloudPath empty");
1361         return false;
1362     }
1363     if (IsSameFileForClone(tableName, fileInfo)) {
1364         // should not delete the file, if the FileInfo is came from PhotoMap.
1365         if (fileInfo.isRelatedToPhotoMap != 1) {
1366             MEDIA_INFO_LOG("File (%{public}s) already exists. delete it.",
1367                 BackupFileUtils::GarbleFilePath(fileInfo.filePath, CLONE_RESTORE_ID, garbagePath_).c_str());
1368             (void)MediaFileUtils::DeleteFile(fileInfo.filePath);
1369         }
1370         UpdateDuplicateNumber(fileInfo.fileType);
1371         return false;
1372     }
1373     if (MediaFileUtils::IsFileExists(fileInfo.cloudPath) || fileInfo.isRelatedToPhotoMap == 1) {
1374         int32_t uniqueId = GetUniqueId(fileInfo.fileType);
1375         int32_t errCode = BackupFileUtils::CreateAssetPathById(uniqueId, fileInfo.fileType,
1376             MediaFileUtils::GetExtensionFromPath(fileInfo.displayName), fileInfo.cloudPath);
1377         if (errCode != E_OK) {
1378             ErrorInfo errorInfo(RestoreError::CREATE_PATH_FAILED, 1, std::to_string(errCode),
1379                 BackupLogUtils::FileInfoToString(sceneCode_, fileInfo));
1380             UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
1381             fileInfo.cloudPath.clear();
1382             return false;
1383         }
1384     }
1385     int32_t errCode = BackupFileUtils::PreparePath(
1386         BackupFileUtils::GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL, fileInfo.cloudPath));
1387     if (errCode != E_OK) {
1388         MEDIA_ERR_LOG("Prepare cloudPath failed, path: %{public}s, cloudPath: %{public}s",
1389             BackupFileUtils::GarbleFilePath(fileInfo.filePath, CLONE_RESTORE_ID, garbagePath_).c_str(),
1390             BackupFileUtils::GarbleFilePath(fileInfo.cloudPath, DEFAULT_RESTORE_ID, garbagePath_).c_str());
1391         ErrorInfo errorInfo(RestoreError::PREPARE_PATH_FAILED, 1, std::to_string(errCode),
1392             BackupLogUtils::FileInfoToString(sceneCode_, fileInfo));
1393         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
1394         fileInfo.cloudPath.clear();
1395         return false;
1396     }
1397     return true;
1398 }
1399 
RestoreMusic()1400 void CloneRestore::RestoreMusic()
1401 {
1402     CheckTableColumnStatus(mediaRdb_, CLONE_TABLE_LISTS_AUDIO);
1403     RestoreAudio();
1404     MEDIA_INFO_LOG("migrate database audio number: %{public}lld, file number: %{public}lld, duplicate number: "
1405         "%{public}lld", (long long)migrateAudioDatabaseNumber_, (long long)migrateAudioFileNumber_,
1406         (long long)migrateAudioDuplicateNumber_);
1407 }
1408 
RestoreAudio(void)1409 void CloneRestore::RestoreAudio(void)
1410 {
1411     MEDIA_INFO_LOG("Start clone restore: audio");
1412     if (!IsReadyForRestore(AudioColumn::AUDIOS_TABLE)) {
1413         MEDIA_ERR_LOG("Column status is not ready for restore audio, quit");
1414         return;
1415     }
1416     unordered_map<string, string> srcColumnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(mediaRdb_,
1417         AudioColumn::AUDIOS_TABLE);
1418     unordered_map<string, string> dstColumnInfoMap = BackupDatabaseUtils::GetColumnInfoMap(mediaLibraryRdb_,
1419         AudioColumn::AUDIOS_TABLE);
1420     if (!PrepareCommonColumnInfoMap(AudioColumn::AUDIOS_TABLE, srcColumnInfoMap, dstColumnInfoMap)) {
1421         MEDIA_ERR_LOG("Prepare common column info failed");
1422         return;
1423     }
1424     if (!MediaFileUtils::IsFileExists(RESTORE_MUSIC_LOCAL_DIR)) {
1425         MEDIA_INFO_LOG("music dir is not exists!!!");
1426         MediaFileUtils::CreateDirectory(RESTORE_MUSIC_LOCAL_DIR);
1427     }
1428     int32_t totalNumber = QueryTotalNumber(AudioColumn::AUDIOS_TABLE);
1429     MEDIA_INFO_LOG("QueryAudioTotalNumber, totalNumber = %{public}d", totalNumber);
1430     audioTotalNumber_ += static_cast<uint64_t>(totalNumber);
1431     MEDIA_INFO_LOG("onProcess Update audioTotalNumber_: %{public}lld", (long long)audioTotalNumber_);
1432     for (int32_t offset = 0; offset < totalNumber; offset += CLONE_QUERY_COUNT) {
1433         ffrt::submit([this, offset]() { RestoreAudioBatch(offset); }, { &offset }, {},
1434             ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
1435     }
1436     ffrt::wait();
1437 }
1438 
QueryFileInfos(const string & tableName,int32_t offset)1439 vector<FileInfo> CloneRestore::QueryFileInfos(const string &tableName, int32_t offset)
1440 {
1441     vector<FileInfo> result;
1442     result.reserve(CLONE_QUERY_COUNT);
1443     string querySql = "SELECT * FROM " + tableName;
1444     string whereClause = GetQueryWhereClauseByTable(tableName);
1445     querySql += whereClause.empty() ? "" : " WHERE " + whereClause;
1446     querySql += " LIMIT " + to_string(offset) + ", " + to_string(CLONE_QUERY_COUNT);
1447     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
1448     if (resultSet == nullptr) {
1449         MEDIA_ERR_LOG("Query resultSql is null.");
1450         return result;
1451     }
1452     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1453         FileInfo fileInfo;
1454         if (ParseResultSet(tableName, resultSet, fileInfo)) {
1455             result.emplace_back(fileInfo);
1456         }
1457     }
1458     return result;
1459 }
1460 
ParseResultSet(const string & tableName,const shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & fileInfo)1461 bool CloneRestore::ParseResultSet(const string &tableName, const shared_ptr<NativeRdb::ResultSet> &resultSet,
1462     FileInfo &fileInfo)
1463 {
1464     fileInfo.fileType = GetInt32Val(MediaColumn::MEDIA_TYPE, resultSet);
1465     fileInfo.fileIdOld = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
1466     fileInfo.displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
1467     fileInfo.oldPath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
1468     if (!ConvertPathToRealPath(fileInfo.oldPath, filePath_, fileInfo.filePath, fileInfo.relativePath)) {
1469         ErrorInfo errorInfo(RestoreError::PATH_INVALID, 1, "", BackupLogUtils::FileInfoToString(sceneCode_, fileInfo));
1470         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
1471         return false;
1472     }
1473     fileInfo.fileSize = GetInt64Val(MediaColumn::MEDIA_SIZE, resultSet);
1474     if (fileInfo.fileSize <= 0) {
1475         ErrorInfo errorInfo(RestoreError::SIZE_INVALID, 1, "Db size <= 0",
1476             BackupLogUtils::FileInfoToString(sceneCode_, fileInfo));
1477         UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
1478         return false;
1479     }
1480 
1481     fileInfo.dateAdded = GetInt64Val(MediaColumn::MEDIA_DATE_ADDED, resultSet);
1482     fileInfo.dateModified = GetInt64Val(MediaColumn::MEDIA_DATE_MODIFIED, resultSet);
1483     fileInfo.dateTaken = GetInt64Val(MediaColumn::MEDIA_DATE_TAKEN, resultSet);
1484     fileInfo.thumbnailReady = GetInt64Val(PhotoColumn::PHOTO_THUMBNAIL_READY, resultSet);
1485     fileInfo.lcdVisitTime = GetInt32Val(PhotoColumn::PHOTO_LCD_VISIT_TIME, resultSet);
1486     fileInfo.oldAstcDateKey = to_string(fileInfo.dateTaken);
1487     SetSpecialAttributes(tableName, resultSet, fileInfo);
1488 
1489     auto commonColumnInfoMap = GetValueFromMap(tableCommonColumnInfoMap_, tableName);
1490     for (auto it = commonColumnInfoMap.begin(); it != commonColumnInfoMap.end(); ++it) {
1491         string columnName = it->first;
1492         string columnType = it->second;
1493         GetValFromResultSet(resultSet, fileInfo.valMap, columnName, columnType);
1494     }
1495     return true;
1496 }
1497 
ParseResultSetForAudio(const shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & fileInfo)1498 bool CloneRestore::ParseResultSetForAudio(const shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &fileInfo)
1499 {
1500     return ParseResultSet(AudioColumn::AUDIOS_TABLE, resultSet, fileInfo);
1501 }
1502 
InsertAudio(vector<FileInfo> & fileInfos)1503 void CloneRestore::InsertAudio(vector<FileInfo> &fileInfos)
1504 {
1505     if (mediaLibraryRdb_ == nullptr) {
1506         MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
1507         return;
1508     }
1509     if (fileInfos.empty()) {
1510         MEDIA_ERR_LOG("fileInfos are empty");
1511         return;
1512     }
1513     int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
1514     int64_t fileMoveCount = 0;
1515     for (auto& fileInfo : fileInfos) {
1516         if (BackupFileUtils::IsFileValid(fileInfo.filePath, CLONE_RESTORE_ID) != E_OK) {
1517             MEDIA_ERR_LOG("File is invalid: size: %{public}lld, name: %{public}s, filePath: %{public}s",
1518                 (long long)fileInfo.fileSize, BackupFileUtils::GarbleFileName(fileInfo.displayName).c_str(),
1519                 BackupFileUtils::GarbleFilePath(fileInfo.filePath, CLONE_RESTORE_ID, garbagePath_).c_str());
1520             continue;
1521         }
1522         if (!PrepareCloudPath(AudioColumn::AUDIOS_TABLE, fileInfo)) {
1523             continue;
1524         }
1525         string localPath = RESTORE_MUSIC_LOCAL_DIR + fileInfo.displayName;
1526         if (MediaFileUtils::IsFileExists(localPath)) {
1527             MEDIA_INFO_LOG("localPath %{public}s already exists.",
1528                 BackupFileUtils::GarbleFilePath(fileInfo.filePath, CLONE_RESTORE_ID, garbagePath_).c_str());
1529             UpdateDuplicateNumber(fileInfo.fileType);
1530             continue;
1531         }
1532         int32_t moveErrCode = MoveFile(fileInfo.filePath, localPath);
1533         if (moveErrCode != E_OK) {
1534             MEDIA_ERR_LOG("MoveFile failed, filePath: %{public}s, errCode: %{public}d, errno: %{public}d",
1535                 BackupFileUtils::GarbleFilePath(fileInfo.filePath, CLONE_RESTORE_ID, garbagePath_).c_str(), moveErrCode,
1536                 errno);
1537             UpdateFailedFiles(fileInfo.fileType, fileInfo, RestoreError::MOVE_FAILED);
1538             continue;
1539         }
1540         BackupFileUtils::ModifyFile(localPath, fileInfo.dateModified / MSEC_TO_SEC);
1541         fileMoveCount++;
1542     }
1543     migrateAudioFileNumber_ += fileMoveCount;
1544     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1545     MEDIA_INFO_LOG("move %{public}ld files cost %{public}ld.", (long)fileMoveCount, (long)(end - startMove));
1546 }
1547 
GetBackupInfo()1548 string CloneRestore::GetBackupInfo()
1549 {
1550     if (BaseRestore::Init() != E_OK) {
1551         MEDIA_ERR_LOG("GetBackupInfo init failed");
1552         return "";
1553     }
1554     if (mediaLibraryRdb_ == nullptr) {
1555         MEDIA_ERR_LOG("GetBackupInfo Rdbstore is null");
1556         return "";
1557     }
1558     CheckTableColumnStatus(mediaLibraryRdb_, CLONE_TABLE_LISTS_OLD_DEVICE);
1559     int32_t photoCount = QueryTotalNumberByMediaType(mediaLibraryRdb_, PhotoColumn::PHOTOS_TABLE,
1560         MediaType::MEDIA_TYPE_IMAGE);
1561     int32_t videoCount = QueryTotalNumberByMediaType(mediaLibraryRdb_, PhotoColumn::PHOTOS_TABLE,
1562         MediaType::MEDIA_TYPE_VIDEO);
1563     int32_t audioCount = QueryTotalNumberByMediaType(mediaLibraryRdb_, AudioColumn::AUDIOS_TABLE,
1564         MediaType::MEDIA_TYPE_AUDIO);
1565     MEDIA_INFO_LOG("QueryTotalNumber, photo: %{public}d, video: %{public}d, audio: %{public}d", photoCount, videoCount,
1566         audioCount);
1567     return GetBackupInfoByCount(photoCount, videoCount, audioCount);
1568 }
1569 
QueryTotalNumberByMediaType(shared_ptr<NativeRdb::RdbStore> rdbStore,const string & tableName,MediaType mediaType)1570 int32_t CloneRestore::QueryTotalNumberByMediaType(shared_ptr<NativeRdb::RdbStore> rdbStore, const string &tableName,
1571     MediaType mediaType)
1572 {
1573     string querySql = "SELECT " + MEDIA_COLUMN_COUNT_1 + " FROM " + tableName + " WHERE " + MediaColumn::MEDIA_TYPE +
1574         " = " + to_string(static_cast<int32_t>(mediaType));
1575     string whereClause = GetQueryWhereClauseByTable(tableName);
1576     querySql += whereClause.empty() ? "" : " AND " + whereClause;
1577     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(rdbStore, querySql);
1578     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1579         return 0;
1580     }
1581     int32_t result = GetInt32Val(MEDIA_COLUMN_COUNT_1, resultSet);
1582     return result;
1583 }
1584 
GetBackupInfoByCount(int32_t photoCount,int32_t videoCount,int32_t audioCount)1585 string CloneRestore::GetBackupInfoByCount(int32_t photoCount, int32_t videoCount, int32_t audioCount)
1586 {
1587     nlohmann::json jsonObject = {
1588         {
1589             { STAT_KEY_BACKUP_INFO, STAT_TYPE_PHOTO },
1590             { STAT_KEY_NUMBER, photoCount }
1591         },
1592         {
1593             { STAT_KEY_BACKUP_INFO, STAT_TYPE_VIDEO },
1594             { STAT_KEY_NUMBER, videoCount }
1595         },
1596         {
1597             { STAT_KEY_BACKUP_INFO, STAT_TYPE_AUDIO },
1598             { STAT_KEY_NUMBER, audioCount }
1599         }
1600     };
1601     return jsonObject.dump();
1602 }
1603 
RestorePhotoBatch(int32_t offset,int32_t isRelatedToPhotoMap)1604 void CloneRestore::RestorePhotoBatch(int32_t offset, int32_t isRelatedToPhotoMap)
1605 {
1606     MEDIA_INFO_LOG(
1607         "start restore photo, offset: %{public}d, isRelatedToPhotoMap: %{public}d", offset, isRelatedToPhotoMap);
1608     vector<FileInfo> fileInfos = QueryFileInfos(offset, isRelatedToPhotoMap);
1609     if (InsertPhoto(fileInfos) != E_OK) {
1610         photosFailedOffsets.push_back(offset);
1611     }
1612     BatchNotifyPhoto(fileInfos);
1613     RestoreImageFaceInfo(fileInfos);
1614 
1615     auto fileIdPairs = BackupDatabaseUtils::CollectFileIdPairs(fileInfos);
1616     BackupDatabaseUtils::UpdateAnalysisTotalTblStatus(mediaLibraryRdb_, fileIdPairs);
1617     MEDIA_INFO_LOG("end restore photo, offset: %{public}d", offset);
1618 }
1619 
RestoreAudioBatch(int32_t offset)1620 void CloneRestore::RestoreAudioBatch(int32_t offset)
1621 {
1622     MEDIA_INFO_LOG("start restore audio, offset: %{public}d", offset);
1623     vector<FileInfo> fileInfos = QueryFileInfos(AudioColumn::AUDIOS_TABLE, offset);
1624     InsertAudio(fileInfos);
1625     MEDIA_INFO_LOG("end restore audio, offset: %{public}d", offset);
1626 }
1627 
InsertPhotoRelated(vector<FileInfo> & fileInfos)1628 void CloneRestore::InsertPhotoRelated(vector<FileInfo> &fileInfos)
1629 {
1630     int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
1631     BatchQueryPhoto(fileInfos);
1632     int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
1633     int64_t mapRowNum = 0;
1634     BatchInsertMap(fileInfos, mapRowNum);
1635     migrateDatabaseMapNumber_ += mapRowNum;
1636     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1637     MEDIA_INFO_LOG("query new file_id cost %{public}ld, insert %{public}ld maps cost %{public}ld",
1638         (long)(startInsert - startQuery), (long)mapRowNum, (long)(end - startInsert));
1639 }
1640 
SetFileIdReference(const vector<FileInfo> & fileInfos,string & selection,unordered_map<int32_t,int32_t> & fileIdMap)1641 void CloneRestore::SetFileIdReference(const vector<FileInfo> &fileInfos, string &selection,
1642     unordered_map<int32_t, int32_t> &fileIdMap)
1643 {
1644     for (const auto &fileInfo : fileInfos) {
1645         if (fileInfo.fileIdOld <= 0 || fileInfo.fileIdNew <= 0) {
1646             continue;
1647         }
1648         BackupDatabaseUtils::UpdateSelection(selection, to_string(fileInfo.fileIdOld), false);
1649         fileIdMap[fileInfo.fileIdOld] = fileInfo.fileIdNew;
1650     }
1651 }
1652 
QueryMapTotalNumber(const string & baseQuerySql)1653 int32_t CloneRestore::QueryMapTotalNumber(const string &baseQuerySql)
1654 {
1655     string querySql = "SELECT count(1) as count FROM " + baseQuerySql;
1656     return BackupDatabaseUtils::QueryInt(mediaRdb_, querySql, CUSTOM_COUNT);
1657 }
1658 
QueryMapInfos(const string & tableName,const string & baseQuerySql,int32_t offset,const unordered_map<int32_t,int32_t> & fileIdMap,const unordered_map<int32_t,int32_t> & albumIdMap)1659 vector<MapInfo> CloneRestore::QueryMapInfos(const string &tableName, const string &baseQuerySql, int32_t offset,
1660     const unordered_map<int32_t, int32_t> &fileIdMap, const unordered_map<int32_t, int32_t> &albumIdMap)
1661 {
1662     vector<MapInfo> mapInfos;
1663     mapInfos.reserve(CLONE_QUERY_COUNT);
1664     string columnMapAlbum = tableName + "." + PhotoMap::ALBUM_ID;
1665     string columnMapAsset = tableName + "." + PhotoMap::ASSET_ID;
1666     string querySql = "SELECT " + columnMapAlbum + ", " + columnMapAsset + " FROM " + baseQuerySql;
1667     querySql += " LIMIT " + to_string(offset) + ", " + to_string(CLONE_QUERY_COUNT);
1668     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
1669     if (resultSet == nullptr) {
1670         MEDIA_ERR_LOG("Query resultSql is null.");
1671         return mapInfos;
1672     }
1673     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1674         int32_t albumIdOld = GetInt32Val(columnMapAlbum, resultSet);
1675         int32_t fileIdOld = GetInt32Val(columnMapAsset, resultSet);
1676         if (albumIdOld <= 0 || albumIdMap.count(albumIdOld) == 0 || fileIdOld <= 0 || fileIdMap.count(fileIdOld) <= 0) {
1677             continue;
1678         }
1679         MapInfo mapInfo;
1680         mapInfo.albumId = albumIdMap.at(albumIdOld);
1681         mapInfo.fileId = fileIdMap.at(fileIdOld);
1682         mapInfos.emplace_back(mapInfo);
1683     }
1684     return mapInfos;
1685 }
1686 
InsertMapByTable(const string & tableName,const vector<MapInfo> & mapInfos,unordered_set<int32_t> & albumSet)1687 int64_t CloneRestore::InsertMapByTable(const string &tableName, const vector<MapInfo> &mapInfos,
1688     unordered_set<int32_t> &albumSet)
1689 {
1690     vector<NativeRdb::ValuesBucket> values = GetInsertValues(mapInfos);
1691     int64_t rowNum = 0;
1692     int32_t errCode = BatchInsertWithRetry(tableName, values, rowNum);
1693     if (errCode != E_OK) {
1694         MEDIA_ERR_LOG("Batch insert map failed, errCode: %{public}d", errCode);
1695         return 0;
1696     }
1697     for (const auto &mapInfo : mapInfos) {
1698         albumSet.insert(mapInfo.albumId);
1699     }
1700     return rowNum;
1701 }
1702 
GetInsertValues(const vector<MapInfo> & mapInfos)1703 vector<NativeRdb::ValuesBucket> CloneRestore::GetInsertValues(const vector<MapInfo> &mapInfos)
1704 {
1705     vector<NativeRdb::ValuesBucket> values;
1706     for (const auto &mapInfo : mapInfos) {
1707         NativeRdb::ValuesBucket value = GetInsertValue(mapInfo);
1708         values.emplace_back(value);
1709     }
1710     return values;
1711 }
1712 
GetQueryWhereClauseByTable(const string & tableName)1713 string CloneRestore::GetQueryWhereClauseByTable(const string &tableName)
1714 {
1715     string whereClause;
1716     if (tableQueryWhereClauseMap_.count(tableName)) {
1717         whereClause += tableQueryWhereClauseMap_.at(tableName);
1718     }
1719     if (tableExtraQueryWhereClauseMap_.count(tableName)) {
1720         whereClause += whereClause.empty() ? "" : " AND " + tableExtraQueryWhereClauseMap_.at(tableName);
1721     }
1722     return whereClause;
1723 }
1724 
SetSpecialAttributes(const string & tableName,const shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & fileInfo)1725 void CloneRestore::SetSpecialAttributes(const string &tableName, const shared_ptr<NativeRdb::ResultSet> &resultSet,
1726     FileInfo &fileInfo)
1727 {
1728     if (tableName != PhotoColumn::PHOTOS_TABLE) {
1729         return;
1730     }
1731     fileInfo.lPath = GetStringVal(PhotoAlbumColumns::ALBUM_LPATH, resultSet);
1732     fileInfo.sourcePath = GetStringVal(PhotoColumn::PHOTO_SOURCE_PATH, resultSet);
1733     fileInfo.orientation = GetInt32Val(PhotoColumn::PHOTO_ORIENTATION, resultSet);
1734     fileInfo.subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
1735     fileInfo.associateFileId = GetInt32Val(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, resultSet);
1736     fileInfo.photoQuality = GetInt32Val(PhotoColumn::PHOTO_QUALITY, resultSet);
1737     fileInfo.recycledTime = GetInt64Val(MediaColumn::MEDIA_DATE_TRASHED, resultSet);
1738     fileInfo.hidden = GetInt32Val(MediaColumn::MEDIA_HIDDEN, resultSet);
1739     // find PhotoAlbum info in target database. PackageName and BundleName should be fixed after clone.
1740     fileInfo.lPath = this->photosClone_.FindlPath(fileInfo);
1741     fileInfo.ownerAlbumId = this->photosClone_.FindAlbumId(fileInfo);
1742     fileInfo.packageName = this->photosClone_.FindPackageName(fileInfo);
1743     fileInfo.bundleName = this->photosClone_.FindBundleName(fileInfo);
1744     fileInfo.photoQuality = this->photosClone_.FindPhotoQuality(fileInfo);
1745     fileInfo.sourcePath = this->photosClone_.FindSourcePath(fileInfo);
1746 }
1747 
IsSameFileForClone(const string & tableName,FileInfo & fileInfo)1748 bool CloneRestore::IsSameFileForClone(const string &tableName, FileInfo &fileInfo)
1749 {
1750     if (tableName != PhotoColumn::PHOTOS_TABLE) {
1751         return IsSameAudioFile(mediaLibraryRdb_, tableName, fileInfo);
1752     }
1753     PhotosDao::PhotosRowData rowData = this->photosClone_.FindSameFile(fileInfo);
1754     int32_t fileId = rowData.fileId;
1755     std::string cloudPath = rowData.data;
1756     if (fileId <= 0 || cloudPath.empty()) {
1757         return false;
1758     }
1759     fileInfo.isNew = false;
1760     fileInfo.fileIdNew = fileId;
1761     fileInfo.cloudPath = cloudPath;
1762     bool isInCloud = rowData.cleanFlag == 1 && rowData.position == static_cast<int32_t>(PhotoPositionType::CLOUD);
1763     // If the file was in cloud previously, only require update flags.
1764     if (fileId > 0 && isInCloud) {
1765         fileInfo.updateMap["clean_flag"] = "0";
1766         fileInfo.updateMap["position"] = to_string(static_cast<int32_t>(PhotoPositionType::LOCAL_AND_CLOUD));
1767         return false;
1768     }
1769     fileInfo.needMove = false;
1770     return true;
1771 }
1772 
RestoreFromGalleryPortraitAlbum()1773 void CloneRestore::RestoreFromGalleryPortraitAlbum()
1774 {
1775     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
1776     RecordOldPortraitAlbumDfx();
1777 
1778     std::string querySql =   "SELECT count(1) AS count FROM " + ANALYSIS_ALBUM_TABLE + " WHERE ";
1779     std::string whereClause = "(" + SMARTALBUM_DB_ALBUM_TYPE + " = " + std::to_string(SMART) + " AND " +
1780         "album_subtype" + " = " + std::to_string(PORTRAIT) + ")";
1781     AppendExtraWhereClause(whereClause, ANALYSIS_ALBUM_TABLE);
1782     querySql += whereClause;
1783 
1784     int32_t totalNumber = BackupDatabaseUtils::QueryInt(mediaRdb_, querySql, CUSTOM_COUNT);
1785     MEDIA_INFO_LOG("QueryPortraitAlbum totalNumber = %{public}d", totalNumber);
1786 
1787     std::vector<std::string> commonColumn = BackupDatabaseUtils::GetCommonColumnInfos(mediaRdb_, mediaLibraryRdb_,
1788         ANALYSIS_ALBUM_TABLE);
1789     std::vector<std::string> commonColumns = BackupDatabaseUtils::filterColumns(commonColumn,
1790         EXCLUDED_PORTRAIT_COLUMNS);
1791 
1792     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
1793         std::vector<AnalysisAlbumTbl> analysisAlbumTbl = QueryPortraitAlbumTbl(offset, commonColumns);
1794         for (const auto& album : analysisAlbumTbl) {
1795             if (album.tagId.has_value() && album.coverUri.has_value()) {
1796                 coverUriInfo_.emplace_back(album.tagId.value(),
1797                     std::make_pair(album.coverUri.value(),
1798                     album.isCoverSatisfied.value_or(INVALID_COVER_SATISFIED_STATUS)));
1799             }
1800         }
1801 
1802         InsertPortraitAlbum(analysisAlbumTbl);
1803     }
1804 
1805     LogPortraitCloneDfx();
1806     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1807     migratePortraitTotalTimeCost_ += end - start;
1808 }
1809 
QueryPortraitAlbumTbl(int32_t offset,const std::vector<std::string> & commonColumns)1810 vector<AnalysisAlbumTbl> CloneRestore::QueryPortraitAlbumTbl(int32_t offset,
1811     const std::vector<std::string>& commonColumns)
1812 {
1813     vector<AnalysisAlbumTbl> result;
1814     result.reserve(QUERY_COUNT);
1815 
1816     std::string inClause = BackupDatabaseUtils::JoinValues<string>(commonColumns, ", ");
1817     std::string querySql =
1818         "SELECT " + inClause +
1819         " FROM " + ANALYSIS_ALBUM_TABLE +
1820         " WHERE ";
1821     std::string whereClause = "(" +
1822         SMARTALBUM_DB_ALBUM_TYPE + " = " + std::to_string(SMART) + " AND " +
1823         "album_subtype" + " = " + std::to_string(PORTRAIT) + ")";
1824     AppendExtraWhereClause(whereClause, ANALYSIS_ALBUM_TABLE);
1825     querySql += whereClause;
1826     querySql += " LIMIT " + std::to_string(offset) + ", " + std::to_string(QUERY_COUNT);
1827 
1828     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
1829     if (resultSet == nullptr) {
1830         MEDIA_ERR_LOG("Query resultSql is null.");
1831         return result;
1832     }
1833 
1834     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1835         AnalysisAlbumTbl analysisAlbumTbl;
1836         ParsePortraitAlbumResultSet(resultSet, analysisAlbumTbl);
1837         result.emplace_back(analysisAlbumTbl);
1838     }
1839 
1840     return result;
1841 }
1842 
ParsePortraitAlbumResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,AnalysisAlbumTbl & analysisAlbumTbl)1843 void CloneRestore::ParsePortraitAlbumResultSet(const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
1844     AnalysisAlbumTbl &analysisAlbumTbl)
1845 {
1846     analysisAlbumTbl.albumType = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, ANALYSIS_COL_ALBUM_TYPE);
1847     analysisAlbumTbl.albumSubtype = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet,
1848         ANALYSIS_COL_ALBUM_SUBTYPE);
1849     analysisAlbumTbl.albumName = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_ALBUM_NAME);
1850     analysisAlbumTbl.coverUri = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_COVER_URI);
1851     analysisAlbumTbl.tagId = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_TAG_ID);
1852     analysisAlbumTbl.userOperation = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet,
1853         ANALYSIS_COL_USER_OPERATION);
1854     analysisAlbumTbl.groupTag = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_GROUP_TAG);
1855     analysisAlbumTbl.userDisplayLevel = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet,
1856         ANALYSIS_COL_USER_DISPLAY_LEVEL);
1857     analysisAlbumTbl.isMe = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, ANALYSIS_COL_IS_ME);
1858     analysisAlbumTbl.isRemoved = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, ANALYSIS_COL_IS_REMOVED);
1859     analysisAlbumTbl.renameOperation = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet,
1860         ANALYSIS_COL_RENAME_OPERATION);
1861     analysisAlbumTbl.isLocal = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, ANALYSIS_COL_IS_LOCAL);
1862     analysisAlbumTbl.isCoverSatisfied = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet,
1863         ANALYSIS_COL_IS_COVER_SATISFIED);
1864 }
1865 
ParseFaceTagResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FaceTagTbl & faceTagTbl)1866 void CloneRestore::ParseFaceTagResultSet(const std::shared_ptr<NativeRdb::ResultSet>& resultSet, FaceTagTbl& faceTagTbl)
1867 {
1868     faceTagTbl.tagId = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, FACE_TAG_COL_TAG_ID);
1869     faceTagTbl.tagName = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, FACE_TAG_COL_TAG_NAME);
1870     faceTagTbl.groupTag = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, FACE_TAG_COL_GROUP_TAG);
1871     faceTagTbl.centerFeatures = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet,
1872         FACE_TAG_COL_CENTER_FEATURES);
1873     faceTagTbl.tagVersion = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, FACE_TAG_COL_TAG_VERSION);
1874     faceTagTbl.analysisVersion = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet,
1875         FACE_TAG_COL_ANALYSIS_VERSION);
1876 }
1877 
InsertPortraitAlbum(std::vector<AnalysisAlbumTbl> & analysisAlbumTbl)1878 void CloneRestore::InsertPortraitAlbum(std::vector<AnalysisAlbumTbl> &analysisAlbumTbl)
1879 {
1880     if (mediaLibraryRdb_ == nullptr) {
1881         MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
1882         return;
1883     }
1884 
1885     if (analysisAlbumTbl.empty()) {
1886         MEDIA_ERR_LOG("analysisAlbumTbl are empty");
1887         return;
1888     }
1889 
1890     std::vector<std::string> albumNames;
1891     std::vector<std::string> tagIds;
1892 
1893     for (const auto &album : analysisAlbumTbl) {
1894         if (album.albumName.has_value()) {
1895             albumNames.emplace_back(album.albumName.value());
1896         }
1897         if (album.tagId.has_value()) {
1898             tagIds.emplace_back(album.tagId.value());
1899         }
1900     }
1901     MEDIA_INFO_LOG("Total albums: %{public}zu, Albums with names: %{public}zu, Albums with tagIds: %{public}zu",
1902                    analysisAlbumTbl.size(), albumNames.size(), tagIds.size());
1903 
1904     if (!BackupDatabaseUtils::DeleteDuplicatePortraitAlbum(albumNames, tagIds, mediaLibraryRdb_)) {
1905         MEDIA_ERR_LOG("Batch delete failed.");
1906         return;
1907     }
1908 
1909     int32_t albumRowNum = InsertPortraitAlbumByTable(analysisAlbumTbl);
1910     if (albumRowNum == E_ERR) {
1911         MEDIA_ERR_LOG("Failed to insert album");
1912     }
1913 
1914     migratePortraitAlbumNumber_ += static_cast<uint64_t>(albumRowNum);
1915     return ;
1916 }
1917 
InsertPortraitAlbumByTable(std::vector<AnalysisAlbumTbl> & analysisAlbumTbl)1918 int32_t CloneRestore::InsertPortraitAlbumByTable(std::vector<AnalysisAlbumTbl> &analysisAlbumTbl)
1919 {
1920     std::vector<NativeRdb::ValuesBucket> valuesBuckets = GetInsertValues(analysisAlbumTbl);
1921 
1922     int64_t rowNum = 0;
1923     int32_t ret = BatchInsertWithRetry(ANALYSIS_ALBUM_TABLE, valuesBuckets, rowNum);
1924     if (ret != E_OK) {
1925         return E_ERR;
1926     }
1927     return rowNum;
1928 }
1929 
GetInsertValues(std::vector<AnalysisAlbumTbl> & analysisAlbumTbl)1930 std::vector<NativeRdb::ValuesBucket> CloneRestore::GetInsertValues(std::vector<AnalysisAlbumTbl> &analysisAlbumTbl)
1931 {
1932     std::vector<NativeRdb::ValuesBucket> values;
1933     for (auto &portraitAlbumInfo : analysisAlbumTbl) {
1934         NativeRdb::ValuesBucket value = GetInsertValue(portraitAlbumInfo);
1935         values.emplace_back(value);
1936     }
1937     return values;
1938 }
1939 
GetInsertValue(const AnalysisAlbumTbl & portraitAlbumInfo)1940 NativeRdb::ValuesBucket CloneRestore::GetInsertValue(const AnalysisAlbumTbl &portraitAlbumInfo)
1941 {
1942     NativeRdb::ValuesBucket values;
1943 
1944     PutIfPresent(values, ANALYSIS_COL_ALBUM_TYPE, portraitAlbumInfo.albumType);
1945     PutIfPresent(values, ANALYSIS_COL_ALBUM_SUBTYPE, portraitAlbumInfo.albumSubtype);
1946     PutIfPresent(values, ANALYSIS_COL_ALBUM_NAME, portraitAlbumInfo.albumName);
1947     PutIfPresent(values, ANALYSIS_COL_TAG_ID, portraitAlbumInfo.tagId);
1948     PutIfPresent(values, ANALYSIS_COL_USER_OPERATION, portraitAlbumInfo.userOperation);
1949     PutIfPresent(values, ANALYSIS_COL_GROUP_TAG, portraitAlbumInfo.groupTag);
1950     PutIfPresent(values, ANALYSIS_COL_USER_DISPLAY_LEVEL, portraitAlbumInfo.userDisplayLevel);
1951     PutIfPresent(values, ANALYSIS_COL_IS_ME, portraitAlbumInfo.isMe);
1952     PutIfPresent(values, ANALYSIS_COL_IS_REMOVED, portraitAlbumInfo.isRemoved);
1953     PutIfPresent(values, ANALYSIS_COL_RENAME_OPERATION, portraitAlbumInfo.renameOperation);
1954     PutIfPresent(values, ANALYSIS_COL_IS_LOCAL, portraitAlbumInfo.isLocal);
1955 
1956     return values;
1957 }
1958 
CreateValuesBucketFromFaceTagTbl(const FaceTagTbl & faceTagTbl)1959 NativeRdb::ValuesBucket CloneRestore::CreateValuesBucketFromFaceTagTbl(const FaceTagTbl& faceTagTbl)
1960 {
1961     NativeRdb::ValuesBucket values;
1962 
1963     PutIfPresent(values, FACE_TAG_COL_TAG_ID, faceTagTbl.tagId);
1964     PutIfPresent(values, FACE_TAG_COL_TAG_NAME, faceTagTbl.tagName);
1965     PutIfPresent(values, FACE_TAG_COL_CENTER_FEATURES, faceTagTbl.centerFeatures);
1966     PutIfPresent(values, FACE_TAG_COL_TAG_VERSION, faceTagTbl.tagVersion);
1967     PutIfPresent(values, FACE_TAG_COL_ANALYSIS_VERSION, faceTagTbl.analysisVersion);
1968 
1969     return values;
1970 }
1971 
QueryAllPortraitAlbum(int32_t & offset,int32_t & rowCount)1972 std::vector<PortraitAlbumDfx> CloneRestore::QueryAllPortraitAlbum(int32_t& offset, int32_t& rowCount)
1973 {
1974     std::vector<PortraitAlbumDfx> result;
1975     result.reserve(QUERY_COUNT);
1976 
1977     const std::string querySql = "SELECT album_name, cover_uri, tag_id, count "
1978         "FROM AnalysisAlbum "
1979         "WHERE album_type = ? "
1980         "AND album_subtype = ? "
1981         "LIMIT ?, ?";
1982 
1983     std::vector<NativeRdb::ValueObject> bindArgs = { SMART, PORTRAIT, offset, QUERY_COUNT };
1984     if (this->mediaRdb_ == nullptr) {
1985         MEDIA_ERR_LOG("Media_Restore: mediaRdb_ is null.");
1986         return result;
1987     }
1988     auto resultSet = mediaRdb_->QuerySql(querySql, bindArgs);
1989     if (resultSet == nullptr) {
1990         MEDIA_ERR_LOG("Query resultSql is null.");
1991         return result;
1992     }
1993 
1994     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1995         PortraitAlbumDfx dfxInfo;
1996         dfxInfo.albumName = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_ALBUM_NAME);
1997         dfxInfo.coverUri = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_COVER_URI);
1998         dfxInfo.tagId = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_TAG_ID);
1999         dfxInfo.count = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, ANALYSIS_COL_COUNT);
2000 
2001         result.push_back(dfxInfo);
2002     }
2003     resultSet->GetRowCount(rowCount);
2004     return result;
2005 }
2006 
RecordOldPortraitAlbumDfx()2007 void CloneRestore::RecordOldPortraitAlbumDfx()
2008 {
2009     int32_t offset {0};
2010     int32_t rowCount {0};
2011     std::vector<PortraitAlbumDfx> albums;
2012 
2013     do {
2014         auto batchResults =  QueryAllPortraitAlbum(offset, rowCount);
2015         if (!batchResults.empty()) {
2016             albums.insert(albums.end(), batchResults.begin(), batchResults.end());
2017         }
2018 
2019         offset += QUERY_COUNT;
2020     } while (rowCount > 0);
2021 
2022     for (const auto& album : albums) {
2023         PortraitAlbumDfx dfxInfo;
2024         if (album.albumName.has_value()) {
2025             dfxInfo.albumName = album.albumName.value();
2026         }
2027         if (album.coverUri.has_value()) {
2028             auto uriParts = BackupDatabaseUtils::SplitString(album.coverUri.value(), '/');
2029             if (uriParts.size() >= COVER_URI_NUM) {
2030                 std::string fileName = uriParts[uriParts.size() - 1];
2031                 dfxInfo.coverUri = BackupFileUtils::GarbleFileName(fileName);
2032             }
2033         }
2034         if (album.tagId.has_value()) {
2035             dfxInfo.tagId = album.tagId.value();
2036         }
2037         if (album.count.has_value()) {
2038             dfxInfo.count = album.count.value();
2039         }
2040 
2041         portraitAlbumDfx_.push_back(dfxInfo);
2042     }
2043 }
2044 
QueryAllPortraitAlbum()2045 std::unordered_set<std::string> CloneRestore::QueryAllPortraitAlbum()
2046 {
2047     std::unordered_set<std::string> result;
2048     std::vector<std::string> tagIds;
2049     for (const auto& oldAlbum : portraitAlbumDfx_) {
2050         if (oldAlbum.tagId.has_value()) {
2051             tagIds.push_back(oldAlbum.tagId.value());
2052         }
2053     }
2054 
2055     if (tagIds.empty()) {
2056         MEDIA_INFO_LOG("No valid tag_ids found in old albums");
2057         return result;
2058     }
2059 
2060     std::string querySql = "SELECT tag_id FROM " + ANALYSIS_ALBUM_TABLE +
2061         " WHERE tag_id IN (" + BackupDatabaseUtils::JoinSQLValues<string>(tagIds, ", ") + ")";
2062 
2063     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql);
2064     if (resultSet == nullptr) {
2065         MEDIA_ERR_LOG("Query resultSql is null.");
2066         return result;
2067     }
2068 
2069     std::string dfxInfo;
2070     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2071         dfxInfo =
2072             BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, ANALYSIS_COL_TAG_ID).value_or("");
2073         result.insert(dfxInfo);
2074     }
2075 
2076     return result;
2077 }
2078 
LogPortraitCloneDfx()2079 void CloneRestore::LogPortraitCloneDfx()
2080 {
2081     std::vector<std::string> failedAlbums;
2082     std::unordered_set<std::string> existingTagIds = QueryAllPortraitAlbum();
2083 
2084     for (const auto& oldAlbum : portraitAlbumDfx_) {
2085         if (!oldAlbum.tagId.has_value()) {
2086             continue;
2087         }
2088 
2089         if (existingTagIds.find(oldAlbum.tagId.value()) == existingTagIds.end()) {
2090             std::string albumInfo = "Album: " + oldAlbum.albumName.value_or("Unknown") +
2091                 ", TagId: " + oldAlbum.tagId.value() +
2092                 ", Cover: " + oldAlbum.coverUri.value_or("Unknown") +
2093                 ", Count: " + std::to_string(oldAlbum.count.value_or(0));
2094             failedAlbums.push_back(albumInfo);
2095         }
2096     }
2097 
2098     if (!failedAlbums.empty()) {
2099         MEDIA_ERR_LOG("Following portrait albums failed to clone completely:");
2100         for (const auto& failedAlbum : failedAlbums) {
2101             MEDIA_ERR_LOG("%{public}s", failedAlbum.c_str());
2102         }
2103     } else {
2104         MEDIA_INFO_LOG("All portrait albums cloned successfully");
2105     }
2106 
2107     MEDIA_INFO_LOG("Stat: Total albums: %{public}zu, Failed albums count: %{public}zu",
2108         portraitAlbumDfx_.size(), failedAlbums.size());
2109 }
2110 
RestorePortraitClusteringInfo()2111 void CloneRestore::RestorePortraitClusteringInfo()
2112 {
2113     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
2114     int32_t totalNumber = BackupDatabaseUtils::QueryInt(mediaRdb_, QUERY_FACE_TAG_COUNT, CUSTOM_COUNT);
2115     MEDIA_INFO_LOG("QueryPortraitClustering totalNumber = %{public}d", totalNumber);
2116 
2117     std::vector<std::string> commonColumn = BackupDatabaseUtils::GetCommonColumnInfos(mediaRdb_, mediaLibraryRdb_,
2118         VISION_FACE_TAG_TABLE);
2119     std::vector<std::string> commonColumns = BackupDatabaseUtils::filterColumns(commonColumn,
2120         EXCLUDED_FACE_TAG_COLUMNS);
2121     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
2122         vector<FaceTagTbl> faceTagTbls = QueryFaceTagTbl(offset, commonColumns);
2123         BatchInsertFaceTags(faceTagTbls);
2124     }
2125     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
2126     migratePortraitTotalTimeCost_ += end - start;
2127 }
2128 
QueryFaceTagTbl(int32_t offset,std::vector<std::string> & commonColumns)2129 vector<FaceTagTbl> CloneRestore::QueryFaceTagTbl(int32_t offset, std::vector<std::string> &commonColumns)
2130 {
2131     vector<FaceTagTbl> result;
2132     result.reserve(QUERY_COUNT);
2133 
2134     std::string inClause = BackupDatabaseUtils::JoinValues<string>(commonColumns, ", ");
2135     std::string querySql = "SELECT DISTINCT " + inClause +
2136         " FROM " + VISION_FACE_TAG_TABLE + " vft" +
2137         " WHERE EXISTS (" +
2138         "   SELECT 1" +
2139         "   FROM AnalysisAlbum aa" +
2140         "   JOIN AnalysisPhotoMap apm ON aa.album_id = apm.map_album" +
2141         "   JOIN Photos ph ON ph.file_id = apm.map_asset" +
2142         "   WHERE aa.tag_id = vft.tag_id" +
2143         "   AND ph.position IN (1, 3)" +
2144         " )";
2145     querySql += " LIMIT " + std::to_string(offset) + ", " + std::to_string(QUERY_COUNT);
2146 
2147     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
2148     if (resultSet == nullptr) {
2149         MEDIA_ERR_LOG("Query resultSet is null.");
2150         return result;
2151     }
2152 
2153     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2154         FaceTagTbl faceTagTbl;
2155         ParseFaceTagResultSet(resultSet, faceTagTbl);
2156         result.emplace_back(faceTagTbl);
2157     }
2158 
2159     return result;
2160 }
2161 
BatchInsertFaceTags(const std::vector<FaceTagTbl> & faceTagTbls)2162 void CloneRestore::BatchInsertFaceTags(const std::vector<FaceTagTbl>& faceTagTbls)
2163 {
2164     std::vector<NativeRdb::ValuesBucket> valuesBuckets;
2165     for (const auto& faceTagTbl : faceTagTbls) {
2166         valuesBuckets.push_back(CreateValuesBucketFromFaceTagTbl(faceTagTbl));
2167     }
2168 
2169     int64_t rowNum = 0;
2170     int32_t ret = BatchInsertWithRetry(VISION_FACE_TAG_TABLE, valuesBuckets, rowNum);
2171     if (ret != E_OK) {
2172         MEDIA_ERR_LOG("Failed to batch insert face tags");
2173         return;
2174     }
2175 }
2176 
RestoreImageFaceInfo(std::vector<FileInfo> & fileInfos)2177 void CloneRestore::RestoreImageFaceInfo(std::vector<FileInfo> &fileInfos)
2178 {
2179     int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
2180     auto uniqueFileIdPairs = BackupDatabaseUtils::CollectFileIdPairs(fileInfos);
2181     auto [oldFileIds, newFileIds] = BackupDatabaseUtils::UnzipFileIdPairs(uniqueFileIdPairs);
2182 
2183     std::string fileIdOldInClause = "(" + BackupDatabaseUtils::JoinValues<int>(oldFileIds, ", ") + ")";
2184 
2185     std::string querySql = QUERY_IMAGE_FACE_COUNT;
2186     querySql += " WHERE " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdOldInClause;
2187     int32_t totalNumber = BackupDatabaseUtils::QueryInt(mediaRdb_, querySql, CUSTOM_COUNT);
2188     MEDIA_INFO_LOG("QueryImageFaceTotalNumber, totalNumber = %{public}d", totalNumber);
2189     if (totalNumber == 0) {
2190         int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
2191         migratePortraitTotalTimeCost_ += end - start;
2192         return;
2193     }
2194 
2195     std::vector<std::string> commonColumn = BackupDatabaseUtils::GetCommonColumnInfos(mediaRdb_, mediaLibraryRdb_,
2196         VISION_IMAGE_FACE_TABLE);
2197     std::vector<std::string> commonColumns = BackupDatabaseUtils::filterColumns(commonColumn,
2198         EXCLUDED_IMAGE_FACE_COLUMNS);
2199 
2200     BackupDatabaseUtils::DeleteExistingImageFaceData(mediaLibraryRdb_, uniqueFileIdPairs);
2201     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
2202         std::vector<ImageFaceTbl> imageFaceTbls = QueryImageFaceTbl(offset, fileIdOldInClause, commonColumns);
2203         auto imageFaces = ProcessImageFaceTbls(imageFaceTbls, uniqueFileIdPairs);
2204         BatchInsertImageFaces(imageFaces);
2205     }
2206 
2207     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
2208     migratePortraitTotalTimeCost_ += end - start;
2209 
2210     GenNewCoverUris(coverUriInfo_, fileInfos);
2211 }
2212 
QueryImageFaceTbl(int32_t offset,std::string & fileIdClause,const std::vector<std::string> & commonColumns)2213 std::vector<ImageFaceTbl> CloneRestore::QueryImageFaceTbl(int32_t offset, std::string &fileIdClause,
2214     const std::vector<std::string> &commonColumns)
2215 {
2216     std::vector<ImageFaceTbl> result;
2217     result.reserve(QUERY_COUNT);
2218 
2219     std::string inClause = BackupDatabaseUtils::JoinValues<string>(commonColumns, ", ");
2220     std::string querySql =
2221         "SELECT " + inClause +
2222         " FROM " + VISION_IMAGE_FACE_TABLE;
2223     querySql += " WHERE " + IMAGE_FACE_COL_FILE_ID + " IN " + fileIdClause;
2224     querySql += " LIMIT " + std::to_string(offset) + ", " + std::to_string(QUERY_COUNT);
2225 
2226     auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaRdb_, querySql);
2227     if (resultSet == nullptr) {
2228         MEDIA_ERR_LOG("Query resultSet is null.");
2229         return result;
2230     }
2231 
2232     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
2233         ImageFaceTbl imageFaceTbl;
2234         ParseImageFaceResultSet(resultSet, imageFaceTbl);
2235         result.emplace_back(imageFaceTbl);
2236     }
2237 
2238     return result;
2239 }
2240 
GetFileInfoByFileId(int32_t fileId,const std::vector<FileInfo> & fileInfos,FileInfo & outFileInfo)2241 bool CloneRestore::GetFileInfoByFileId(int32_t fileId, const std::vector<FileInfo>& fileInfos, FileInfo& outFileInfo)
2242 {
2243     auto it = std::find_if(fileInfos.begin(), fileInfos.end(),
2244         [fileId](const FileInfo& info) { return info.fileIdNew == fileId; });
2245     if (it != fileInfos.end()) {
2246         outFileInfo = *it;
2247         return true;
2248     }
2249 
2250     return false;
2251 }
2252 
GenNewCoverUris(const std::vector<CloneRestore::CoverUriInfo> & coverUriInfo,std::vector<FileInfo> & fileInfos)2253 void CloneRestore::GenNewCoverUris(const std::vector<CloneRestore::CoverUriInfo>& coverUriInfo,
2254     std::vector<FileInfo> &fileInfos)
2255 {
2256     if (coverUriInfo.empty() && fileInfos.empty()) {
2257         MEDIA_WARN_LOG("Empty coverUriInfo or fileIdPairs, skipping.");
2258         return;
2259     }
2260 
2261     std::unordered_map<std::string, std::pair<std::string, int32_t>> tagIdToCoverInfo;
2262     for (const auto& [tagId, coverInfo] : coverUriInfo) {
2263         tagIdToCoverInfo[tagId] = coverInfo;
2264     }
2265 
2266     auto fileIdPairs = BackupDatabaseUtils::CollectFileIdPairs(fileInfos);
2267     std::unordered_map<std::string, int32_t> oldToNewFileId;
2268     for (const auto& [oldId, newId] : fileIdPairs) {
2269         oldToNewFileId[std::to_string(oldId)] = newId;
2270     }
2271 
2272     std::vector<std::string> tagIds;
2273     std::string updateSql = GenCoverUriUpdateSql(tagIdToCoverInfo, oldToNewFileId, fileInfos, tagIds);
2274     if (updateSql.empty()) {
2275         return;
2276     }
2277 
2278     BackupDatabaseUtils::ExecuteSQL(mediaLibraryRdb_, updateSql);
2279 }
2280 
GenCoverUriUpdateSql(const std::unordered_map<std::string,std::pair<std::string,int32_t>> & tagIdToCoverInfo,const std::unordered_map<std::string,int32_t> & oldToNewFileId,const std::vector<FileInfo> & fileInfos,std::vector<std::string> & tagIds)2281 std::string CloneRestore::GenCoverUriUpdateSql(const std::unordered_map<std::string, std::pair<std::string, int32_t>>&
2282     tagIdToCoverInfo, const std::unordered_map<std::string, int32_t>& oldToNewFileId,
2283     const std::vector<FileInfo>& fileInfos, std::vector<std::string>& tagIds)
2284 {
2285     std::unordered_map<std::string, std::string> coverUriUpdates;
2286     std::unordered_map<std::string, int32_t> isCoverSatisfiedUpdates;
2287 
2288     for (const auto& [tagId, coverInfo] : tagIdToCoverInfo) {
2289         const auto& [oldCoverUri, isCoverSatisfied] = coverInfo;
2290         std::string newUri = ProcessUriAndGenNew(tagId, oldCoverUri, oldToNewFileId, fileInfos);
2291         if (!newUri.empty()) {
2292             coverUriUpdates[tagId] = newUri;
2293             isCoverSatisfiedUpdates[tagId] = isCoverSatisfied;
2294             tagIds.push_back(tagId);
2295         }
2296     }
2297 
2298     if (coverUriUpdates.empty() || isCoverSatisfiedUpdates.empty()) {
2299         return "";
2300     }
2301 
2302     std::string updateSql = "UPDATE AnalysisAlbum SET ";
2303 
2304     updateSql += "cover_uri = CASE ";
2305     for (const auto& [tagId, newUri] : coverUriUpdates) {
2306         updateSql += "WHEN tag_id = '" + tagId + "' THEN '" + newUri + "' ";
2307     }
2308     updateSql += "ELSE cover_uri END";
2309 
2310     bool hasValidIsCoverSatisfied = false;
2311     std::string isCoverSatisfiedSql = ", is_cover_satisfied = CASE ";
2312     for (const auto& [tagId, isCoverSatisfied] : isCoverSatisfiedUpdates) {
2313         if (isCoverSatisfied != INVALID_COVER_SATISFIED_STATUS) {
2314             hasValidIsCoverSatisfied = true;
2315             isCoverSatisfiedSql += "WHEN tag_id = '" + tagId + "' THEN " + std::to_string(isCoverSatisfied) + " ";
2316         }
2317     }
2318 
2319     isCoverSatisfiedSql += "ELSE is_cover_satisfied END ";
2320     if (hasValidIsCoverSatisfied) {
2321         updateSql += isCoverSatisfiedSql;
2322     }
2323 
2324     updateSql += "WHERE tag_id IN ('" +
2325         BackupDatabaseUtils::JoinValues(tagIds, "','") + "')";
2326 
2327     return updateSql;
2328 }
2329 
ProcessUriAndGenNew(const std::string & tagId,const std::string & oldCoverUri,const std::unordered_map<std::string,int32_t> & oldToNewFileId,const std::vector<FileInfo> & fileInfos)2330 std::string CloneRestore::ProcessUriAndGenNew(const std::string& tagId, const std::string& oldCoverUri,
2331     const std::unordered_map<std::string, int32_t>& oldToNewFileId, const std::vector<FileInfo>& fileInfos)
2332 {
2333     auto uriParts = BackupDatabaseUtils::SplitString(oldCoverUri, '/');
2334     if (uriParts.size() >= COVER_URI_NUM) {
2335         std::string fileIdOld = uriParts[uriParts.size() - 3];
2336         auto it = oldToNewFileId.find(fileIdOld);
2337         if (it != oldToNewFileId.end()) {
2338             int32_t fileIdNew = it->second;
2339             FileInfo fileInfo {};
2340             if (GetFileInfoByFileId(fileIdNew, fileInfos, fileInfo)) {
2341                 std::string extraUri = MediaFileUtils::GetExtraUri(fileInfo.displayName, fileInfo.cloudPath);
2342                 return MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX,
2343                     std::to_string(fileIdNew), extraUri);
2344             }
2345         }
2346     }
2347     return "";
2348 }
2349 
ProcessImageFaceTbls(const std::vector<ImageFaceTbl> & imageFaceTbls,const std::vector<FileIdPair> & fileIdPairs)2350 std::vector<ImageFaceTbl> CloneRestore::ProcessImageFaceTbls(const std::vector<ImageFaceTbl>& imageFaceTbls,
2351     const std::vector<FileIdPair>& fileIdPairs)
2352 {
2353     if (imageFaceTbls.empty()) {
2354         MEDIA_ERR_LOG("image faces tbl empty");
2355         return {};
2356     }
2357 
2358     std::vector<ImageFaceTbl> imageFaceNewTbls;
2359     imageFaceNewTbls.reserve(imageFaceTbls.size());
2360 
2361     for (const auto& imageFaceTbl : imageFaceTbls) {
2362         if (imageFaceTbl.fileId.has_value()) {
2363             int32_t oldFileId = imageFaceTbl.fileId.value();
2364             auto it = std::find_if(fileIdPairs.begin(), fileIdPairs.end(),
2365                 [oldFileId](const FileIdPair& pair) { return pair.first == oldFileId; });
2366             if (it != fileIdPairs.end()) {
2367                 ImageFaceTbl updatedFace = imageFaceTbl;
2368                 updatedFace.fileId = it->second;
2369                 imageFaceNewTbls.push_back(std::move(updatedFace));
2370             }
2371         }
2372     }
2373 
2374     return imageFaceNewTbls;
2375 }
2376 
BatchInsertImageFaces(const std::vector<ImageFaceTbl> & imageFaceTbls)2377 void CloneRestore::BatchInsertImageFaces(const std::vector<ImageFaceTbl>& imageFaceTbls)
2378 {
2379     std::vector<NativeRdb::ValuesBucket> valuesBuckets;
2380     std::unordered_set<int32_t> fileIdSet;
2381     for (const auto& imageFaceTbl : imageFaceTbls) {
2382         valuesBuckets.push_back(CreateValuesBucketFromImageFaceTbl(imageFaceTbl));
2383     }
2384 
2385     int64_t rowNum = 0;
2386     int32_t ret = BatchInsertWithRetry(VISION_IMAGE_FACE_TABLE, valuesBuckets, rowNum);
2387     if (ret != E_OK) {
2388         MEDIA_ERR_LOG("Failed to batch insert image faces");
2389         return;
2390     }
2391 
2392     for (const auto& imageFaceTbl : imageFaceTbls) {
2393         if (imageFaceTbl.fileId.has_value()) {
2394             fileIdSet.insert(imageFaceTbl.fileId.value());
2395         }
2396     }
2397 
2398     migratePortraitFaceNumber_ += rowNum;
2399     migratePortraitPhotoNumber_ += fileIdSet.size();
2400 }
2401 
CreateValuesBucketFromImageFaceTbl(const ImageFaceTbl & imageFaceTbl)2402 NativeRdb::ValuesBucket CloneRestore::CreateValuesBucketFromImageFaceTbl(const ImageFaceTbl& imageFaceTbl)
2403 {
2404     NativeRdb::ValuesBucket values;
2405 
2406     PutIfPresent(values, IMAGE_FACE_COL_FILE_ID, imageFaceTbl.fileId);
2407     PutIfPresent(values, IMAGE_FACE_COL_FACE_ID, imageFaceTbl.faceId);
2408     PutIfPresent(values, IMAGE_FACE_COL_TAG_ID, imageFaceTbl.tagId);
2409     PutIfPresent(values, IMAGE_FACE_COL_SCALE_X, imageFaceTbl.scaleX);
2410     PutIfPresent(values, IMAGE_FACE_COL_SCALE_Y, imageFaceTbl.scaleY);
2411     PutIfPresent(values, IMAGE_FACE_COL_SCALE_WIDTH, imageFaceTbl.scaleWidth);
2412     PutIfPresent(values, IMAGE_FACE_COL_SCALE_HEIGHT, imageFaceTbl.scaleHeight);
2413     PutIfPresent(values, IMAGE_FACE_COL_LANDMARKS, imageFaceTbl.landmarks);
2414     PutIfPresent(values, IMAGE_FACE_COL_PITCH, imageFaceTbl.pitch);
2415     PutIfPresent(values, IMAGE_FACE_COL_YAW, imageFaceTbl.yaw);
2416     PutIfPresent(values, IMAGE_FACE_COL_ROLL, imageFaceTbl.roll);
2417     PutIfPresent(values, IMAGE_FACE_COL_PROB, imageFaceTbl.prob);
2418     PutIfPresent(values, IMAGE_FACE_COL_TOTAL_FACES, imageFaceTbl.totalFaces);
2419     PutIfPresent(values, IMAGE_FACE_COL_FACE_VERSION, imageFaceTbl.faceVersion);
2420     PutIfPresent(values, IMAGE_FACE_COL_FEATURES_VERSION, imageFaceTbl.featuresVersion);
2421     PutIfPresent(values, IMAGE_FACE_COL_FEATURES, imageFaceTbl.features);
2422     PutIfPresent(values, IMAGE_FACE_COL_FACE_OCCLUSION, imageFaceTbl.faceOcclusion);
2423     PutIfPresent(values, IMAGE_FACE_COL_ANALYSIS_VERSION, imageFaceTbl.analysisVersion);
2424     PutIfPresent(values, IMAGE_FACE_COL_BEAUTY_BOUNDER_X, imageFaceTbl.beautyBounderX);
2425     PutIfPresent(values, IMAGE_FACE_COL_BEAUTY_BOUNDER_Y, imageFaceTbl.beautyBounderY);
2426     PutIfPresent(values, IMAGE_FACE_COL_BEAUTY_BOUNDER_WIDTH, imageFaceTbl.beautyBounderWidth);
2427     PutIfPresent(values, IMAGE_FACE_COL_BEAUTY_BOUNDER_HEIGHT, imageFaceTbl.beautyBounderHeight);
2428     PutIfPresent(values, IMAGE_FACE_COL_AESTHETICS_SCORE, imageFaceTbl.aestheticsScore);
2429     PutIfPresent(values, IMAGE_FACE_COL_BEAUTY_BOUNDER_VERSION, imageFaceTbl.beautyBounderVersion);
2430     PutWithDefault(values, IMAGE_FACE_COL_IS_EXCLUDED, imageFaceTbl.isExcluded, 0);
2431 
2432     return values;
2433 }
2434 
ParseImageFaceResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,ImageFaceTbl & imageFaceTbl)2435 void CloneRestore::ParseImageFaceResultSet(const std::shared_ptr<NativeRdb::ResultSet>& resultSet,
2436     ImageFaceTbl& imageFaceTbl)
2437 {
2438     imageFaceTbl.fileId = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, IMAGE_FACE_COL_FILE_ID);
2439     imageFaceTbl.faceId = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, IMAGE_FACE_COL_FACE_ID);
2440     imageFaceTbl.tagId = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, IMAGE_FACE_COL_TAG_ID);
2441     imageFaceTbl.scaleX = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_SCALE_X);
2442     imageFaceTbl.scaleY = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_SCALE_Y);
2443     imageFaceTbl.scaleWidth = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_SCALE_WIDTH);
2444     imageFaceTbl.scaleHeight = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_SCALE_HEIGHT);
2445     imageFaceTbl.landmarks = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, IMAGE_FACE_COL_LANDMARKS);
2446     imageFaceTbl.pitch = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_PITCH);
2447     imageFaceTbl.yaw = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_YAW);
2448     imageFaceTbl.roll = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_ROLL);
2449     imageFaceTbl.prob = BackupDatabaseUtils::GetOptionalValue<double>(resultSet, IMAGE_FACE_COL_PROB);
2450     imageFaceTbl.totalFaces = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, IMAGE_FACE_COL_TOTAL_FACES);
2451     imageFaceTbl.faceVersion = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet,
2452         IMAGE_FACE_COL_FACE_VERSION);
2453     imageFaceTbl.featuresVersion = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet,
2454         IMAGE_FACE_COL_FEATURES_VERSION);
2455     imageFaceTbl.features = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet, IMAGE_FACE_COL_FEATURES);
2456     imageFaceTbl.faceOcclusion = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet,
2457         IMAGE_FACE_COL_FACE_OCCLUSION);
2458     imageFaceTbl.analysisVersion = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet,
2459         IMAGE_FACE_COL_ANALYSIS_VERSION);
2460     imageFaceTbl.beautyBounderX = BackupDatabaseUtils::GetOptionalValue<double>(resultSet,
2461         IMAGE_FACE_COL_BEAUTY_BOUNDER_X);
2462     imageFaceTbl.beautyBounderY = BackupDatabaseUtils::GetOptionalValue<double>(resultSet,
2463         IMAGE_FACE_COL_BEAUTY_BOUNDER_Y);
2464     imageFaceTbl.beautyBounderWidth = BackupDatabaseUtils::GetOptionalValue<double>(resultSet,
2465         IMAGE_FACE_COL_BEAUTY_BOUNDER_WIDTH);
2466     imageFaceTbl.beautyBounderHeight = BackupDatabaseUtils::GetOptionalValue<double>(resultSet,
2467         IMAGE_FACE_COL_BEAUTY_BOUNDER_HEIGHT);
2468     imageFaceTbl.aestheticsScore = BackupDatabaseUtils::GetOptionalValue<double>(resultSet,
2469         IMAGE_FACE_COL_AESTHETICS_SCORE);
2470     imageFaceTbl.beautyBounderVersion = BackupDatabaseUtils::GetOptionalValue<std::string>(resultSet,
2471         IMAGE_FACE_COL_BEAUTY_BOUNDER_VERSION);
2472     imageFaceTbl.isExcluded = BackupDatabaseUtils::GetOptionalValue<int32_t>(resultSet, IMAGE_FACE_COL_IS_EXCLUDED);
2473 }
2474 
ReportPortraitCloneStat(int32_t sceneCode)2475 void CloneRestore::ReportPortraitCloneStat(int32_t sceneCode)
2476 {
2477     if (sceneCode != CLONE_RESTORE_ID) {
2478         MEDIA_ERR_LOG("err scencecode %{public}d", sceneCode);
2479         return;
2480     }
2481 
2482     MEDIA_INFO_LOG("PortraitStat: album %{public}lld, photo %{public}lld, face %{public}lld, cost %{public}lld",
2483         (long long)migratePortraitAlbumNumber_, (long long)migratePortraitPhotoNumber_,
2484         (long long)migratePortraitFaceNumber_, (long long)migratePortraitTotalTimeCost_);
2485 
2486     BackupDfxUtils::PostPortraitStat(static_cast<uint32_t>(migratePortraitAlbumNumber_), migratePortraitPhotoNumber_,
2487         migratePortraitFaceNumber_, migratePortraitTotalTimeCost_);
2488 }
2489 
AppendExtraWhereClause(std::string & whereClause,const std::string & tableName)2490 void CloneRestore::AppendExtraWhereClause(std::string& whereClause, const std::string& tableName)
2491 {
2492     auto it = tableExtraQueryWhereClauseMap_.find(tableName);
2493     if (it != tableExtraQueryWhereClauseMap_.end()) {
2494         whereClause += whereClause.empty() ? "" : " AND ";
2495         whereClause += it->second;
2496     }
2497 }
2498 
InitAllKvStore()2499 bool CloneRestore::InitAllKvStore()
2500 {
2501     std::string oldBaseDir = backupRestoreDir_ + CLONE_KVDB_BACKUP_DIR;
2502     std::string newBaseDir = MEDIA_KVDB_DIR;
2503     oldMonthKvStorePtr_ = MediaLibraryKvStoreManager::GetInstance()
2504         .GetSingleKvStore(KvStoreRoleType::OWNER, CLONE_KVSTORE_MONTH_STOREID, oldBaseDir);
2505     oldYearKvStorePtr_ = MediaLibraryKvStoreManager::GetInstance()
2506         .GetSingleKvStore(KvStoreRoleType::OWNER, CLONE_KVSTORE_YEAR_STOREID, oldBaseDir);
2507     newMonthKvStorePtr_ = MediaLibraryKvStoreManager::GetInstance()
2508         .GetSingleKvStore(KvStoreRoleType::OWNER, MEDIA_KVSTORE_MONTH_STOREID, newBaseDir);
2509     newYearKvStorePtr_ = MediaLibraryKvStoreManager::GetInstance()
2510         .GetSingleKvStore(KvStoreRoleType::OWNER, MEDIA_KVSTORE_YEAR_STOREID, newBaseDir);
2511     if (oldMonthKvStorePtr_ == nullptr || oldYearKvStorePtr_ == nullptr ||
2512         newMonthKvStorePtr_ == nullptr || newYearKvStorePtr_ == nullptr) {
2513         MEDIA_ERR_LOG("Init all kvstore failed");
2514         return false;
2515     }
2516     return true;
2517 }
2518 
CloseAllKvStore()2519 void CloneRestore::CloseAllKvStore()
2520 {
2521     oldMonthKvStorePtr_ != nullptr && oldMonthKvStorePtr_->Close();
2522     oldYearKvStorePtr_ != nullptr && oldYearKvStorePtr_->Close();
2523     newMonthKvStorePtr_ != nullptr && newMonthKvStorePtr_->Close();
2524     newYearKvStorePtr_ != nullptr && newYearKvStorePtr_->Close();
2525 }
2526 
StartBackup()2527 void CloneRestore::StartBackup()
2528 {
2529     MEDIA_INFO_LOG("Start clone backup");
2530     if (!BackupKvStore() && !MediaFileUtils::DeleteDir(CLONE_KVDB_BACKUP_DIR)) {
2531         MEDIA_ERR_LOG("BackupKvStore failed and delete old backup kvdb failed, errno:%{public}d", errno);
2532     }
2533     MEDIA_INFO_LOG("End clone backup");
2534 }
2535 
BackupKvStore()2536 bool CloneRestore::BackupKvStore()
2537 {
2538     MEDIA_INFO_LOG("Start BackupKvstore");
2539     if (MediaFileUtils::IsFileExists(CLONE_KVDB_BACKUP_DIR)) {
2540         // Delete only redundant data and do not need to be returned.
2541         MediaFileUtils::DeleteDir(CLONE_KVDB_BACKUP_DIR);
2542     }
2543 
2544     std::string backupKvdbPath = CLONE_KVDB_BACKUP_DIR + "/kvdb";
2545     if (BackupFileUtils::PreparePath(backupKvdbPath) != E_OK) {
2546         MEDIA_ERR_LOG("Prepare backup dir failed");
2547         return false;
2548     }
2549 
2550     int32_t status = MediaLibraryKvStoreManager::GetInstance().CloneKvStore(
2551         MEDIA_KVSTORE_MONTH_STOREID, MEDIA_KVDB_DIR, CLONE_KVSTORE_MONTH_STOREID, CLONE_KVDB_BACKUP_DIR);
2552     if (status != E_OK) {
2553         return false;
2554     }
2555     status = MediaLibraryKvStoreManager::GetInstance().CloneKvStore(
2556         MEDIA_KVSTORE_YEAR_STOREID, MEDIA_KVDB_DIR, CLONE_KVSTORE_YEAR_STOREID, CLONE_KVDB_BACKUP_DIR);
2557     if (status != E_OK) {
2558         return false;
2559     }
2560     MEDIA_INFO_LOG("End BackupKvstore");
2561     return true;
2562 }
2563 
GetNoNeedMigrateCount()2564 int32_t CloneRestore::GetNoNeedMigrateCount()
2565 {
2566     return this->photosClone_.GetNoNeedMigrateCount();
2567 }
2568 } // namespace Media
2569 } // namespace OHOS
2570