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