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