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