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