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