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