1 /*
2 * Copyright (C) 2023-2024 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 "MediaLibraryUpgradeRestore"
17
18 #include "upgrade_restore.h"
19
20 #include "backup_const_column.h"
21 #include "backup_const_map.h"
22 #include "backup_database_utils.h"
23 #include "backup_file_utils.h"
24 #include "ffrt.h"
25 #include "ffrt_inner.h"
26 #include "media_column.h"
27 #include "media_file_utils.h"
28 #include "media_log.h"
29 #include "medialibrary_data_manager.h"
30 #include "medialibrary_errno.h"
31 #include "result_set_utils.h"
32 #include "userfile_manager_types.h"
33 #include "photo_album_restore.h"
34 #include "photos_restore.h"
35 #include "photos_dao.h"
36 #include "gallery_db_upgrade.h"
37 #include "vision_album_column.h"
38 #include "vision_column.h"
39 #include "vision_face_tag_column.h"
40 #include "vision_image_face_column.h"
41 #include "vision_photo_map_column.h"
42 #include "gallery_report.h"
43 #include "medialibrary_rdb_transaction.h"
44
45 #ifdef CLOUD_SYNC_MANAGER
46 #include "cloud_sync_manager.h"
47 #endif
48
49 namespace OHOS {
50 namespace Media {
51 constexpr int32_t PHOTOS_TABLE_ALBUM_ID = -1;
52 constexpr int32_t BASE_TEN_NUMBER = 10;
53 constexpr int32_t SEVEN_NUMBER = 7;
54 constexpr int32_t INTERNAL_PREFIX_LEVEL = 4;
55 constexpr int32_t SD_PREFIX_LEVEL = 3;
56 constexpr int64_t TAR_FILE_LIMIT = 2 * 1024 * 1024;
57 const std::string INTERNAL_PREFIX = "/storage/emulated";
58 constexpr int32_t MAX_THREAD_NUM = 4;
59
UpgradeRestore(const std::string & galleryAppName,const std::string & mediaAppName,int32_t sceneCode)60 UpgradeRestore::UpgradeRestore(const std::string &galleryAppName, const std::string &mediaAppName, int32_t sceneCode)
61 {
62 galleryAppName_ = galleryAppName;
63 mediaAppName_ = mediaAppName;
64 sceneCode_ = sceneCode;
65 audioAppName_ = "Audio";
66 }
67
UpgradeRestore(const std::string & galleryAppName,const std::string & mediaAppName,int32_t sceneCode,const std::string & dualDirName)68 UpgradeRestore::UpgradeRestore(const std::string &galleryAppName, const std::string &mediaAppName, int32_t sceneCode,
69 const std::string &dualDirName)
70 {
71 galleryAppName_ = galleryAppName;
72 mediaAppName_ = mediaAppName;
73 sceneCode_ = sceneCode;
74 dualDirName_ = dualDirName;
75 }
76
Init(const std::string & backupRetoreDir,const std::string & upgradeFilePath,bool isUpgrade)77 int32_t UpgradeRestore::Init(const std::string &backupRetoreDir, const std::string &upgradeFilePath, bool isUpgrade)
78 {
79 appDataPath_ = backupRetoreDir;
80 string photosPreferencesPath;
81 if (sceneCode_ == DUAL_FRAME_CLONE_RESTORE_ID) {
82 filePath_ = backupRetoreDir;
83 galleryDbPath_ = backupRetoreDir + "/" + GALLERY_DB_NAME;
84 audioDbPath_ = backupRetoreDir + INTERNAL_PREFIX + "/0/" + AUDIO_DB_NAME;
85 photosPreferencesPath = backupRetoreDir + "/" + galleryAppName_ + "_preferences.xml";
86 // gallery db may include both internal & external, set flag to differentiate, default false
87 shouldIncludeSd_ = BackupFileUtils::ShouldIncludeSd(filePath_);
88 SetParameterForClone();
89 #ifdef CLOUD_SYNC_MANAGER
90 FileManagement::CloudSync::CloudSyncManager::GetInstance().StopSync("com.ohos.medialibrary.medialibrarydata");
91 #endif
92 } else {
93 filePath_ = upgradeFilePath;
94 galleryDbPath_ = backupRetoreDir + "/" + galleryAppName_ + "/ce/databases/gallery.db";
95 externalDbPath_ = backupRetoreDir + "/" + mediaAppName_ + "/ce/databases/external.db";
96 photosPreferencesPath =
97 backupRetoreDir + "/" + galleryAppName_ + "/ce/shared_prefs/" + galleryAppName_ + "_preferences.xml";
98 shouldIncludeSd_ = false;
99 if (!MediaFileUtils::IsFileExists(externalDbPath_)) {
100 MEDIA_ERR_LOG("External db is not exist.");
101 return EXTERNAL_DB_NOT_EXIST;
102 }
103 int32_t externalErr = BackupDatabaseUtils::InitDb(externalRdb_, EXTERNAL_DB_NAME, externalDbPath_,
104 mediaAppName_, false);
105 if (externalRdb_ == nullptr) {
106 MEDIA_ERR_LOG("External init rdb fail, err = %{public}d", externalErr);
107 return E_FAIL;
108 }
109 if (sceneCode_ == UPGRADE_RESTORE_ID) {
110 MediaLibraryDataManager::GetInstance()->ReCreateMediaDir();
111 }
112 }
113 MEDIA_INFO_LOG("Shoud include Sd: %{public}d", static_cast<int32_t>(shouldIncludeSd_));
114 return InitDbAndXml(photosPreferencesPath, isUpgrade);
115 }
116
InitDbAndXml(std::string xmlPath,bool isUpgrade)117 int32_t UpgradeRestore::InitDbAndXml(std::string xmlPath, bool isUpgrade)
118 {
119 if (isUpgrade && BaseRestore::Init() != E_OK) {
120 return E_FAIL;
121 }
122 if (!MediaFileUtils::IsFileExists(galleryDbPath_)) {
123 MEDIA_ERR_LOG("Gallery media db is not exist.");
124 } else {
125 int32_t galleryErr = BackupDatabaseUtils::InitDb(galleryRdb_, GALLERY_DB_NAME, galleryDbPath_,
126 galleryAppName_, false);
127 if (galleryRdb_ == nullptr) {
128 MEDIA_ERR_LOG("Gallery init rdb fail, err = %{public}d", galleryErr);
129 return E_FAIL;
130 }
131 }
132
133 if (!MediaFileUtils::IsFileExists(audioDbPath_)) {
134 MEDIA_ERR_LOG("audio mediaInfo db is not exist.");
135 } else {
136 int32_t audioErr = BackupDatabaseUtils::InitDb(audioRdb_, AUDIO_DB_NAME, audioDbPath_,
137 audioAppName_, false);
138 if (audioRdb_ == nullptr) {
139 MEDIA_ERR_LOG("audio init rdb fail, err = %{public}d", audioErr);
140 return E_FAIL;
141 }
142 }
143 ParseXml(xmlPath);
144 this->photoAlbumRestore_.OnStart(this->mediaLibraryRdb_, this->galleryRdb_);
145 this->photosRestore_.OnStart(this->mediaLibraryRdb_, this->galleryRdb_);
146 MEDIA_INFO_LOG("Init db succ.");
147 return E_OK;
148 }
149
HasLowQualityImage()150 bool UpgradeRestore::HasLowQualityImage()
151 {
152 std::string sql = "SELECT count(1) AS count FROM gallery_media WHERE (local_media_id != -1) AND \
153 (storage_id IN (0, 65537)) AND relative_bucket_id NOT IN (SELECT DISTINCT relative_bucket_id FROM \
154 garbage_album WHERE type = 1) AND _size = 0 AND photo_quality = 0";
155 int count = BackupDatabaseUtils::QueryInt(galleryRdb_, sql, CUSTOM_COUNT);
156 MEDIA_INFO_LOG("HasLowQualityImage count:%{public}d", count);
157 hasLowQualityImage_ = (count > 0);
158 return hasLowQualityImage_;
159 }
160
StringToInt(const std::string & str)161 int UpgradeRestore::StringToInt(const std::string& str)
162 {
163 if (str.empty()) {
164 return 0;
165 }
166 int base = 0;
167 size_t num = 0;
168 int sign = 1; // positive one
169 size_t len = str.length();
170 while (num < len && str[num] == ' ') {
171 num++;
172 }
173 if (num < len && (str[num] == '-' || str[num] == '+')) {
174 sign = (str[num++] == '-') ? -1 : 1;
175 }
176 while (num < len && std::isdigit(str[num])) {
177 if (base > INT_MAX / BASE_TEN_NUMBER || (base == INT_MAX / BASE_TEN_NUMBER && str[num] - '0' > SEVEN_NUMBER)) {
178 MEDIA_INFO_LOG("The number is INT_MAX");
179 return 0;
180 }
181 base = BASE_TEN_NUMBER * base + (str[num++] - '0');
182 }
183 if (num < len && !std::isdigit(str[num])) {
184 MEDIA_INFO_LOG("Not digit");
185 return 0;
186 }
187 return base * sign;
188 }
189
HandleXmlNode(xmlNodePtr cur)190 int32_t UpgradeRestore::HandleXmlNode(xmlNodePtr cur)
191 {
192 if (cur->type == XML_ELEMENT_NODE) {
193 xmlChar* name = xmlGetProp(cur, BAD_CAST"name");
194 if (name != nullptr && xmlStrcmp(name, BAD_CAST"filter_selected_size") == 0) {
195 xmlChar* value = xmlGetProp(cur, BAD_CAST"value");
196 if (value != nullptr) {
197 fileMinSize_ = StringToInt((const char *)(value));
198 xmlFree(value);
199 return E_SUCCESS;
200 }
201 xmlFree(name);
202 return E_ERR;
203 }
204 xmlFree(name);
205 }
206 return E_ERR;
207 }
208
ParseXml(const std::string & path)209 int32_t UpgradeRestore::ParseXml(const std::string &path)
210 {
211 std::unique_ptr<xmlDoc, decltype(&xmlFreeDoc)> docPtr(
212 xmlReadFile(path.c_str(), nullptr, XML_PARSE_NOBLANKS), xmlFreeDoc);
213 if (docPtr == nullptr) {
214 MEDIA_ERR_LOG("failed to read xml file");
215 return E_ERR;
216 }
217 auto root = xmlDocGetRootElement(docPtr.get());
218 if (root == nullptr) {
219 MEDIA_ERR_LOG("failed to read root node");
220 return E_ERR;
221 }
222 for (xmlNodePtr cur = root->children; cur != NULL; cur = cur->next) {
223 if (HandleXmlNode(cur) == E_SUCCESS) {
224 return E_SUCCESS;
225 }
226 }
227 return E_ERR;
228 }
229
RestoreAudio(void)230 void UpgradeRestore::RestoreAudio(void)
231 {
232 if (sceneCode_ == DUAL_FRAME_CLONE_RESTORE_ID) {
233 if (!MediaFileUtils::IsFileExists(RESTORE_MUSIC_LOCAL_DIR)) {
234 MEDIA_INFO_LOG("music dir is not exists!!!");
235 MediaFileUtils::CreateDirectory(RESTORE_MUSIC_LOCAL_DIR);
236 }
237 RestoreAudioFromFile();
238 }
239 (void)NativeRdb::RdbHelper::DeleteRdbStore(externalDbPath_);
240 (void)NativeRdb::RdbHelper::DeleteRdbStore(audioDbPath_);
241 }
242
RestoreAudioFromFile()243 void UpgradeRestore::RestoreAudioFromFile()
244 {
245 MEDIA_INFO_LOG("start restore audio from audio_MediaInfo0");
246 int32_t totalNumber = BackupDatabaseUtils::QueryInt(audioRdb_, QUERY_DUAL_CLONE_AUDIO_COUNT, CUSTOM_COUNT);
247 MEDIA_INFO_LOG("totalNumber = %{public}d", totalNumber);
248 audioTotalNumber_ += static_cast<uint64_t>(totalNumber);
249 MEDIA_INFO_LOG("onProcess Update audioTotalNumber_: %{public}lld", (long long)audioTotalNumber_);
250 for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
251 ffrt::submit([this, offset]() { RestoreAudioBatch(offset); }, { &offset }, {},
252 ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
253 }
254 ffrt::wait();
255 }
256
RestoreAudioBatch(int32_t offset)257 void UpgradeRestore::RestoreAudioBatch(int32_t offset)
258 {
259 MEDIA_INFO_LOG("start restore audio from external, offset: %{public}d", offset);
260 std::vector<FileInfo> infos = QueryAudioFileInfosFromAudio(offset);
261 InsertAudio(sceneCode_, infos);
262 }
263
QueryAudioFileInfosFromAudio(int32_t offset)264 std::vector<FileInfo> UpgradeRestore::QueryAudioFileInfosFromAudio(int32_t offset)
265 {
266 std::vector<FileInfo> result;
267 result.reserve(QUERY_COUNT);
268 if (audioRdb_ == nullptr) {
269 MEDIA_ERR_LOG("audioRdb_ is nullptr, Maybe init failed.");
270 return result;
271 }
272 std::string queryAllAudioByCount = QUERY_ALL_AUDIOS_FROM_AUDIODB + " limit " + std::to_string(offset) + ", " +
273 std::to_string(QUERY_COUNT);
274 auto resultSet = audioRdb_->QuerySql(queryAllAudioByCount);
275 if (resultSet == nullptr) {
276 MEDIA_ERR_LOG("Query resultSql is null.");
277 return result;
278 }
279 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
280 FileInfo tmpInfo;
281 if (ParseResultSetFromAudioDb(resultSet, tmpInfo)) {
282 result.emplace_back(tmpInfo);
283 }
284 }
285 return result;
286 }
287
ParseResultSetFromAudioDb(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info)288 bool UpgradeRestore::ParseResultSetFromAudioDb(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info)
289 {
290 info.fileType = MediaType::MEDIA_TYPE_AUDIO;
291 info.oldPath = GetStringVal(AUDIO_DATA, resultSet);
292 if (!ConvertPathToRealPath(info.oldPath, filePath_, info.filePath, info.relativePath)) {
293 MEDIA_ERR_LOG("Invalid path: %{public}s.",
294 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
295 return false;
296 }
297 info.showDateToken = GetInt64Val(EXTERNAL_DATE_MODIFIED, resultSet);
298 info.dateModified = GetInt64Val(EXTERNAL_DATE_MODIFIED, resultSet) * MSEC_TO_SEC;
299 info.displayName = BackupFileUtils::GetFileNameFromPath(info.filePath);
300 info.title = BackupFileUtils::GetFileTitle(info.displayName);
301 info.packageName = BackupFileUtils::GetFileFolderFromPath(info.relativePath, false);
302 info.isFavorite = 0;
303 info.recycledTime = 0;
304 return true;
305 }
306
RestorePhoto()307 void UpgradeRestore::RestorePhoto()
308 {
309 AnalyzeSource();
310 InitGarbageAlbum();
311 HandleClone();
312 // upgrade gallery.db
313 if (this->galleryRdb_ != nullptr) {
314 DataTransfer::GalleryDbUpgrade galleryDbUpgrade;
315 galleryDbUpgrade.OnUpgrade(*this->galleryRdb_);
316 } else {
317 MEDIA_WARN_LOG("galleryRdb_ is nullptr, Maybe init failed, skip gallery db upgrade.");
318 }
319 // restore PhotoAlbum
320 this->photoAlbumRestore_.Restore();
321 RestoreFromGalleryPortraitAlbum();
322 // restore Photos
323 RestoreFromGallery();
324 StopParameterForClone(sceneCode_);
325 MEDIA_INFO_LOG("migrate from gallery number: %{public}lld, file number: %{public}lld",
326 (long long) migrateDatabaseNumber_, (long long) migrateFileNumber_);
327 if (sceneCode_ == UPGRADE_RESTORE_ID) {
328 RestoreFromExternal(true);
329 MEDIA_INFO_LOG("migrate from camera number: %{public}lld, file number: %{public}lld",
330 (long long) migrateDatabaseNumber_, (long long) migrateFileNumber_);
331 RestoreFromExternal(false);
332 MEDIA_INFO_LOG("migrate from others number: %{public}lld, file number: %{public}lld",
333 (long long) migrateDatabaseNumber_, (long long) migrateFileNumber_);
334 }
335
336 if (sceneCode_ == UPGRADE_RESTORE_ID) {
337 UpdateFaceAnalysisStatus();
338 } else {
339 UpdateDualCloneFaceAnalysisStatus();
340 }
341
342 ReportPortraitStat(sceneCode_);
343 (void)NativeRdb::RdbHelper::DeleteRdbStore(galleryDbPath_);
344 }
345
AnalyzeSource()346 void UpgradeRestore::AnalyzeSource()
347 {
348 MEDIA_INFO_LOG("start AnalyzeSource.");
349 AnalyzeGalleryErrorSource();
350 AnalyzeGallerySource();
351 MEDIA_INFO_LOG("end AnalyzeSource.");
352 }
353
AnalyzeGalleryErrorSource()354 void UpgradeRestore::AnalyzeGalleryErrorSource()
355 {
356 if (galleryRdb_ == nullptr) {
357 MEDIA_ERR_LOG("galleryRdb_ is nullptr, Maybe init failed.");
358 return;
359 }
360 AnalyzeGalleryDuplicateData();
361 }
362
AnalyzeGalleryDuplicateData()363 void UpgradeRestore::AnalyzeGalleryDuplicateData()
364 {
365 int32_t count = 0;
366 int32_t total = 0;
367 BackupDatabaseUtils::QueryGalleryDuplicateDataCount(galleryRdb_, count, total);
368 MEDIA_INFO_LOG("Duplicate data count: %{public}d, total: %{public}d", count, total);
369 this->photosRestore_.GetDuplicateData(count);
370 }
371
AnalyzeGallerySource()372 void UpgradeRestore::AnalyzeGallerySource()
373 {
374 GalleryReport()
375 .SetGalleryRdb(this->galleryRdb_)
376 .SetExternalRdb(this->externalRdb_)
377 .SetSceneCode(this->sceneCode_)
378 .SetTaskId(this->taskId_)
379 .SetShouldIncludeSd(this->shouldIncludeSd_)
380 .Report();
381 }
382
InitGarbageAlbum()383 void UpgradeRestore::InitGarbageAlbum()
384 {
385 BackupDatabaseUtils::InitGarbageAlbum(galleryRdb_, cacheSet_, nickMap_);
386 }
387
HandleClone()388 void UpgradeRestore::HandleClone()
389 {
390 int32_t cloneCount = BackupDatabaseUtils::QueryGalleryCloneCount(galleryRdb_);
391 MEDIA_INFO_LOG("clone number: %{public}d", cloneCount);
392 if (cloneCount == 0) {
393 return;
394 }
395 int32_t maxId = BackupDatabaseUtils::QueryInt(galleryRdb_, QUERY_MAX_ID, CUSTOM_MAX_ID);
396 std::string queryMayClonePhotoNumber = "SELECT count(1) AS count FROM files WHERE (is_pending = 0) AND\
397 (storage_id IN (0, 65537)) AND " + COMPARE_ID + std::to_string(maxId) + " AND " + QUERY_NOT_SYNC;
398 int32_t totalNumber = BackupDatabaseUtils::QueryInt(externalRdb_, queryMayClonePhotoNumber, CUSTOM_COUNT);
399 MEDIA_INFO_LOG("totalNumber = %{public}d, maxId = %{public}d", totalNumber, maxId);
400 for (int32_t offset = 0; offset < totalNumber; offset += PRE_CLONE_PHOTO_BATCH_COUNT) {
401 ffrt::submit([this, offset, maxId]() {
402 HandleCloneBatch(offset, maxId);
403 }, { &offset }, {}, ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
404 }
405 ffrt::wait();
406 }
407
HandleCloneBatch(int32_t offset,int32_t maxId)408 void UpgradeRestore::HandleCloneBatch(int32_t offset, int32_t maxId)
409 {
410 MEDIA_INFO_LOG("start handle clone batch, offset: %{public}d", offset);
411 if (externalRdb_ == nullptr || galleryRdb_ == nullptr) {
412 MEDIA_ERR_LOG("rdb is nullptr, Maybe init failed.");
413 return;
414 }
415 std::string queryExternalMayClonePhoto = "SELECT _id, _data FROM files WHERE (is_pending = 0) AND\
416 (storage_id IN (0, 65537)) AND " + COMPARE_ID + std::to_string(maxId) + " AND " +
417 QUERY_NOT_SYNC + "limit " + std::to_string(offset) + ", " + std::to_string(PRE_CLONE_PHOTO_BATCH_COUNT);
418 auto resultSet = externalRdb_->QuerySql(queryExternalMayClonePhoto);
419 if (resultSet == nullptr) {
420 MEDIA_ERR_LOG("Query resultSql is null.");
421 return;
422 }
423 int32_t number = 0;
424 UpdateCloneWithRetry(resultSet, number);
425 MEDIA_INFO_LOG("%{public}d rows change clone flag", number);
426 }
427
UpdateCloneWithRetry(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,int32_t & number)428 void UpgradeRestore::UpdateCloneWithRetry(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, int32_t &number)
429 {
430 int32_t errCode = E_ERR;
431 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
432 int32_t id = GetInt32Val(GALLERY_ID, resultSet);
433 std::string data = GetStringVal(GALLERY_FILE_DATA, resultSet);
434 int32_t changeRows = 0;
435 NativeRdb::ValuesBucket valuesBucket;
436 valuesBucket.Put(GALLERY_LOCAL_MEDIA_ID, id);
437 std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
438 make_unique<NativeRdb::AbsRdbPredicates>("gallery_media");
439 predicates->SetWhereClause("local_media_id = -3 AND _data = ?"); // -3 means clone data
440 predicates->SetWhereArgs({data});
441 errCode = BackupDatabaseUtils::Update(galleryRdb_, changeRows, valuesBucket, predicates);
442 if (errCode != E_OK) {
443 MEDIA_ERR_LOG("Failed to execute update, err: %{public}d", errCode);
444 continue;
445 }
446 number += changeRows;
447 }
448 }
449
RestoreFromGallery()450 void UpgradeRestore::RestoreFromGallery()
451 {
452 HasLowQualityImage();
453 int32_t totalNumber = this->photosRestore_.GetGalleryMediaCount(this->shouldIncludeSd_, this->hasLowQualityImage_);
454 MEDIA_INFO_LOG("totalNumber = %{public}d", totalNumber);
455 totalNumber_ += static_cast<uint64_t>(totalNumber);
456 MEDIA_INFO_LOG("onProcess Update totalNumber_: %{public}lld", (long long)totalNumber_);
457 ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_THREAD_NUM);
458 for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
459 ffrt::submit([this, offset]() { RestoreBatch(offset); }, { &offset }, {},
460 ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
461 }
462 ffrt::wait();
463 }
464
RestoreBatch(int32_t offset)465 void UpgradeRestore::RestoreBatch(int32_t offset)
466 {
467 MEDIA_INFO_LOG("start restore from gallery, offset: %{public}d", offset);
468 std::vector<FileInfo> infos = QueryFileInfos(offset);
469 InsertPhoto(sceneCode_, infos, SourceType::GALLERY);
470 auto fileIdPairs = BackupDatabaseUtils::CollectFileIdPairs(infos);
471 BackupDatabaseUtils::UpdateAnalysisTotalTblStatus(mediaLibraryRdb_, fileIdPairs);
472 }
473
RestoreFromExternal(bool isCamera)474 void UpgradeRestore::RestoreFromExternal(bool isCamera)
475 {
476 MEDIA_INFO_LOG("start restore from %{public}s", (isCamera ? "camera" : "others"));
477 int32_t maxId = BackupDatabaseUtils::QueryInt(galleryRdb_, isCamera ?
478 QUERY_MAX_ID_CAMERA_SCREENSHOT : QUERY_MAX_ID_OTHERS, CUSTOM_MAX_ID);
479 int32_t type = isCamera ? SourceType::EXTERNAL_CAMERA : SourceType::EXTERNAL_OTHERS;
480 int32_t totalNumber = QueryNotSyncTotalNumber(maxId, isCamera);
481 MEDIA_INFO_LOG("totalNumber = %{public}d, maxId = %{public}d", totalNumber, maxId);
482 totalNumber_ += static_cast<uint64_t>(totalNumber);
483 MEDIA_INFO_LOG("onProcess Update totalNumber_: %{public}lld", (long long)totalNumber_);
484 ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_THREAD_NUM);
485 for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
486 ffrt::submit([this, offset, maxId, isCamera, type]() {
487 RestoreExternalBatch(offset, maxId, isCamera, type);
488 }, { &offset }, {}, ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
489 }
490 ffrt::wait();
491 }
492
RestoreExternalBatch(int32_t offset,int32_t maxId,bool isCamera,int32_t type)493 void UpgradeRestore::RestoreExternalBatch(int32_t offset, int32_t maxId, bool isCamera, int32_t type)
494 {
495 MEDIA_INFO_LOG("start restore from external, offset: %{public}d", offset);
496 std::vector<FileInfo> infos = QueryFileInfosFromExternal(offset, maxId, isCamera);
497 InsertPhoto(sceneCode_, infos, type);
498 }
499
QueryNotSyncTotalNumber(int32_t maxId,bool isCamera)500 int32_t UpgradeRestore::QueryNotSyncTotalNumber(int32_t maxId, bool isCamera)
501 {
502 std::string queryCamera = isCamera ? IN_CAMERA : NOT_IN_CAMERA;
503 std::string queryNotSyncByCount = QUERY_COUNT_FROM_FILES + queryCamera + " AND " +
504 COMPARE_ID + std::to_string(maxId) + " AND " + QUERY_NOT_SYNC;
505 return BackupDatabaseUtils::QueryInt(externalRdb_, queryNotSyncByCount, CUSTOM_COUNT);
506 }
507
HandleRestData(void)508 void UpgradeRestore::HandleRestData(void)
509 {
510 MEDIA_INFO_LOG("Start to handle rest data in native.");
511 RestoreThumbnail();
512
513 std::string photoData = appDataPath_ + "/" + galleryAppName_;
514 std::string mediaData = appDataPath_ + "/" + mediaAppName_;
515 if (MediaFileUtils::IsFileExists(photoData)) {
516 MEDIA_DEBUG_LOG("Start to delete photo data.");
517 MediaFileUtils::DeleteDir(photoData);
518 }
519 if (MediaFileUtils::IsFileExists(mediaData)) {
520 MEDIA_DEBUG_LOG("Start to delete media data.");
521 MediaFileUtils::DeleteDir(mediaData);
522 }
523 BackupFileUtils::DeleteSdDatabase(filePath_);
524 }
525
QueryFileInfos(int32_t offset)526 std::vector<FileInfo> UpgradeRestore::QueryFileInfos(int32_t offset)
527 {
528 std::vector<FileInfo> result;
529 result.reserve(QUERY_COUNT);
530 if (galleryRdb_ == nullptr) {
531 MEDIA_ERR_LOG("galleryRdb_ is nullptr, Maybe init failed.");
532 return result;
533 }
534 auto resultSet = this->photosRestore_.GetGalleryMedia(
535 offset, QUERY_COUNT, this->shouldIncludeSd_, this->hasLowQualityImage_);
536 if (resultSet == nullptr) {
537 MEDIA_ERR_LOG("Query resultSql is null.");
538 return result;
539 }
540 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
541 FileInfo tmpInfo;
542 if (ParseResultSetFromGallery(resultSet, tmpInfo)) {
543 result.emplace_back(tmpInfo);
544 }
545 }
546 return result;
547 }
548
ParseResultSetForAudio(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info)549 bool UpgradeRestore::ParseResultSetForAudio(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info)
550 {
551 info.oldPath = GetStringVal(EXTERNAL_FILE_DATA, resultSet);
552 int32_t mediaType = GetInt32Val(EXTERNAL_MEDIA_TYPE, resultSet);
553 if (mediaType != DUAL_MEDIA_TYPE::AUDIO_TYPE) {
554 MEDIA_ERR_LOG("Invalid media type: %{public}d, path: %{public}s", mediaType,
555 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
556 return false;
557 }
558 info.fileType = MediaType::MEDIA_TYPE_AUDIO;
559 if (!BaseRestore::ConvertPathToRealPath(info.oldPath, filePath_, info.filePath, info.relativePath)) {
560 MEDIA_ERR_LOG("Invalid path: %{public}s.",
561 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
562 return false;
563 }
564 info.displayName = GetStringVal(EXTERNAL_DISPLAY_NAME, resultSet);
565 info.title = GetStringVal(EXTERNAL_TITLE, resultSet);
566 info.fileSize = GetInt64Val(EXTERNAL_FILE_SIZE, resultSet);
567 if (info.fileSize < GARBAGE_PHOTO_SIZE) {
568 MEDIA_WARN_LOG("maybe garbage path = %{public}s.",
569 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
570 }
571 info.duration = GetInt64Val(GALLERY_DURATION, resultSet);
572 info.isFavorite = GetInt32Val(EXTERNAL_IS_FAVORITE, resultSet);
573 info.dateModified = GetInt64Val(EXTERNAL_DATE_MODIFIED, resultSet) * MSEC_TO_SEC;
574 return true;
575 }
576
QueryFileInfosFromExternal(int32_t offset,int32_t maxId,bool isCamera)577 std::vector<FileInfo> UpgradeRestore::QueryFileInfosFromExternal(int32_t offset, int32_t maxId, bool isCamera)
578 {
579 std::vector<FileInfo> result;
580 result.reserve(QUERY_COUNT);
581 if (externalRdb_ == nullptr) {
582 MEDIA_ERR_LOG("Pointer rdb_ is nullptr, Maybe init failed.");
583 return result;
584 }
585 std::string queryCamera = isCamera ? IN_CAMERA : NOT_IN_CAMERA;
586 std::string queryFilesByCount = QUERY_FILE_COLUMN + queryCamera + " AND " +
587 COMPARE_ID + std::to_string(maxId) + " AND " + QUERY_NOT_SYNC + " limit " + std::to_string(offset) + ", " +
588 std::to_string(QUERY_COUNT);
589 auto resultSet = externalRdb_->QuerySql(queryFilesByCount);
590 if (resultSet == nullptr) {
591 MEDIA_ERR_LOG("Query resultSql is null.");
592 return result;
593 }
594 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
595 FileInfo tmpInfo;
596 if (ParseResultSetFromExternal(resultSet, tmpInfo)) {
597 std::string findPath = tmpInfo.relativePath;
598 bool isValid = IsValidDir(findPath);
599 if (isValid) {
600 result.emplace_back(tmpInfo);
601 }
602 }
603 }
604 return result;
605 }
606
IsValidDir(const string & path)607 bool UpgradeRestore::IsValidDir(const string &path)
608 {
609 bool isValid = true;
610 for (auto &cacheDir : cacheSet_) {
611 if (path.find(cacheDir) == 0) {
612 isValid = false;
613 break;
614 }
615 }
616 return isValid;
617 }
ParseResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info,string dbName)618 bool UpgradeRestore::ParseResultSet(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info,
619 string dbName)
620 {
621 // only parse image and video
622 info.oldPath = GetStringVal(GALLERY_FILE_DATA, resultSet);
623 if (this->photosRestore_.IsDuplicateData(info.oldPath)) {
624 MEDIA_ERR_LOG("Data duplicate and already used, path: %{public}s",
625 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
626 return false;
627 }
628 info.displayName = GetStringVal(GALLERY_DISPLAY_NAME, resultSet);
629 info.fileType = GetInt32Val(GALLERY_MEDIA_TYPE, resultSet);
630 info.fileType = this->photosRestore_.FindMediaType(info);
631 if (info.fileType != MediaType::MEDIA_TYPE_IMAGE && info.fileType != MediaType::MEDIA_TYPE_VIDEO) {
632 MEDIA_ERR_LOG("Invalid media type: %{public}d, path: %{public}s",
633 info.fileType,
634 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
635 return false;
636 }
637 info.fileSize = GetInt64Val(GALLERY_FILE_SIZE, resultSet);
638 if (info.fileSize < fileMinSize_ && dbName == EXTERNAL_DB_NAME) {
639 MEDIA_WARN_LOG("maybe garbage path = %{public}s, minSize:%{public}d.",
640 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str(), fileMinSize_);
641 return false;
642 }
643 if (sceneCode_ == UPGRADE_RESTORE_ID ?
644 !BaseRestore::ConvertPathToRealPath(info.oldPath, filePath_, info.filePath, info.relativePath) :
645 !ConvertPathToRealPath(info.oldPath, filePath_, info.filePath, info.relativePath, info)) {
646 MEDIA_ERR_LOG("Invalid path: %{public}s.",
647 BackupFileUtils::GarbleFilePath(info.oldPath, DEFAULT_RESTORE_ID).c_str());
648 return false;
649 }
650 info.title = GetStringVal(GALLERY_TITLE, resultSet);
651 info.userComment = GetStringVal(GALLERY_DESCRIPTION, resultSet);
652 info.duration = GetInt64Val(GALLERY_DURATION, resultSet);
653 info.isFavorite = GetInt32Val(GALLERY_IS_FAVORITE, resultSet);
654 info.specialFileType = GetInt32Val(GALLERY_SPECIAL_FILE_TYPE, resultSet);
655 if (BackupFileUtils::IsLivePhoto(info) && !BackupFileUtils::ConvertToMovingPhoto(info)) {
656 MEDIA_ERR_LOG("Failed to convert live photo to moving photo, filePath = %{public}s",
657 BackupFileUtils::GarbleFilePath(info.filePath, UPGRADE_RESTORE_ID).c_str());
658 return false;
659 }
660 info.height = GetInt64Val(GALLERY_HEIGHT, resultSet);
661 info.width = GetInt64Val(GALLERY_WIDTH, resultSet);
662 info.orientation = GetInt64Val(GALLERY_ORIENTATION, resultSet);
663 info.dateModified = GetInt64Val(EXTERNAL_DATE_MODIFIED, resultSet) * MSEC_TO_SEC;
664 info.firstUpdateTime = GetInt64Val(GALLERY_FIRST_UPDATE_TIME, resultSet);
665 info.dateTaken = GetInt64Val(GALLERY_DATE_TAKEN, resultSet);
666 info.detailTime = GetStringVal(GALLERY_DETAIL_TIME, resultSet);
667 return true;
668 }
669
ParseResultSetFromGallery(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info)670 bool UpgradeRestore::ParseResultSetFromGallery(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info)
671 {
672 info.localMediaId = GetInt32Val(GALLERY_LOCAL_MEDIA_ID, resultSet);
673 info.hidden = (info.localMediaId == GALLERY_HIDDEN_ID) ? 1 : 0;
674 info.recycledTime = GetInt64Val(GALLERY_RECYCLED_TIME, resultSet);
675 info.showDateToken = GetInt64Val(GALLERY_SHOW_DATE_TOKEN, resultSet);
676 // fetch relative_bucket_id, recycleFlag, is_hw_burst, hash field to generate burst_key
677 info.relativeBucketId = GetStringVal(GALLERY_MEDIA_BUCKET_ID, resultSet);
678 info.recycleFlag = GetInt32Val(GALLERY_RECYCLE_FLAG, resultSet);
679 info.isBurst = GetInt32Val(GALLERY_IS_BURST, resultSet);
680 info.hashCode = GetStringVal(GALLERY_HASH, resultSet);
681 info.fileIdOld = GetInt32Val(GALLERY_ID, resultSet);
682 info.photoQuality = GetInt32Val(PhotoColumn::PHOTO_QUALITY, resultSet);
683
684 bool isSuccess = ParseResultSet(resultSet, info, GALLERY_DB_NAME);
685 if (!isSuccess) {
686 MEDIA_ERR_LOG("ParseResultSetFromGallery fail");
687 return isSuccess;
688 }
689 info.burstKey = burstKeyGenerator_.FindBurstKey(info);
690 // Pre-Fetch: sourcePath, lPath
691 info.sourcePath = GetStringVal(GALLERY_MEDIA_SOURCE_PATH, resultSet);
692 info.lPath = GetStringVal("lPath", resultSet);
693 // Find lPath, bundleName, packageName by sourcePath, lPath
694 info.lPath = this->photosRestore_.FindlPath(info);
695 info.bundleName = this->photosRestore_.FindBundleName(info);
696 info.packageName = this->photosRestore_.FindPackageName(info);
697 info.photoQuality = this->photosRestore_.FindPhotoQuality(info);
698 return isSuccess;
699 }
700
ParseResultSetFromExternal(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FileInfo & info,int mediaType)701 bool UpgradeRestore::ParseResultSetFromExternal(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FileInfo &info,
702 int mediaType)
703 {
704 bool isSuccess;
705 if (mediaType == DUAL_MEDIA_TYPE::AUDIO_TYPE) {
706 isSuccess = ParseResultSetForAudio(resultSet, info);
707 } else {
708 isSuccess = ParseResultSet(resultSet, info, EXTERNAL_DB_NAME);
709 }
710 if (!isSuccess) {
711 MEDIA_ERR_LOG("ParseResultSetFromExternal fail");
712 return isSuccess;
713 }
714 info.showDateToken = GetInt64Val(EXTERNAL_DATE_TAKEN, resultSet);
715 info.dateTaken = GetInt64Val(EXTERNAL_DATE_TAKEN, resultSet);
716 return isSuccess;
717 }
718
GetInsertValue(const FileInfo & fileInfo,const std::string & newPath,int32_t sourceType)719 NativeRdb::ValuesBucket UpgradeRestore::GetInsertValue(const FileInfo &fileInfo, const std::string &newPath,
720 int32_t sourceType)
721 {
722 NativeRdb::ValuesBucket values;
723 values.PutString(MediaColumn::MEDIA_FILE_PATH, newPath);
724 values.PutString(MediaColumn::MEDIA_TITLE, fileInfo.title);
725 values.PutString(MediaColumn::MEDIA_NAME, fileInfo.displayName);
726 values.PutInt(MediaColumn::MEDIA_TYPE, fileInfo.fileType);
727 if (fileInfo.firstUpdateTime != 0) {
728 values.PutLong(MediaColumn::MEDIA_DATE_ADDED, fileInfo.firstUpdateTime);
729 } else if (fileInfo.dateTaken != 0) {
730 values.PutLong(MediaColumn::MEDIA_DATE_ADDED, fileInfo.dateTaken);
731 }
732 if (fileInfo.dateTaken != 0) {
733 values.PutLong(MediaColumn::MEDIA_DATE_TAKEN, fileInfo.dateTaken);
734 }
735 values.PutString(PhotoColumn::PHOTO_DETAIL_TIME, fileInfo.detailTime);
736 values.PutLong(MediaColumn::MEDIA_DURATION, fileInfo.duration);
737 values.PutInt(MediaColumn::MEDIA_IS_FAV, fileInfo.isFavorite);
738 if (fileInfo.isFavorite != 0) {
739 string fileName = fileInfo.displayName;
740 MEDIA_WARN_LOG("the file :%{public}s is favorite.", BackupFileUtils::GarbleFileName(fileName).c_str());
741 }
742 values.PutLong(MediaColumn::MEDIA_DATE_TRASHED, this->photosRestore_.FindDateTrashed(fileInfo));
743 values.PutInt(MediaColumn::MEDIA_HIDDEN, fileInfo.hidden);
744 if (fileInfo.hidden != 0) {
745 string fileName = fileInfo.displayName;
746 MEDIA_WARN_LOG("the file :%{public}s is hidden.", BackupFileUtils::GarbleFileName(fileName).c_str());
747 }
748 values.PutInt(PhotoColumn::PHOTO_HEIGHT, fileInfo.height);
749 values.PutInt(PhotoColumn::PHOTO_WIDTH, fileInfo.width);
750 values.PutString(PhotoColumn::PHOTO_USER_COMMENT, fileInfo.userComment);
751 values.PutInt(PhotoColumn::PHOTO_ORIENTATION, fileInfo.orientation);
752 std::string package_name = fileInfo.packageName;
753 if (package_name != "") {
754 values.PutString(PhotoColumn::MEDIA_PACKAGE_NAME, package_name);
755 }
756 values.PutInt(PhotoColumn::PHOTO_SUBTYPE, this->photosRestore_.FindSubtype(fileInfo));
757 values.PutInt(PhotoColumn::PHOTO_DIRTY, this->photosRestore_.FindDirty(fileInfo));
758 values.PutInt(PhotoColumn::PHOTO_BURST_COVER_LEVEL, this->photosRestore_.FindBurstCoverLevel(fileInfo));
759 values.PutString(PhotoColumn::PHOTO_BURST_KEY, this->photosRestore_.FindBurstKey(fileInfo));
760 // find album_id by lPath.
761 values.PutInt("owner_album_id", this->photosRestore_.FindAlbumId(fileInfo));
762 values.PutInt(PhotoColumn::PHOTO_QUALITY, fileInfo.photoQuality);
763 return values;
764 }
765
ConvertPathToRealPath(const std::string & srcPath,const std::string & prefix,std::string & newPath,std::string & relativePath)766 bool UpgradeRestore::ConvertPathToRealPath(const std::string &srcPath, const std::string &prefix,
767 std::string &newPath, std::string &relativePath)
768 {
769 size_t pos = 0;
770 if (!BackupFileUtils::GetPathPosByPrefixLevel(sceneCode_, srcPath, INTERNAL_PREFIX_LEVEL, pos)) {
771 return false;
772 }
773 newPath = prefix + srcPath;
774 relativePath = srcPath.substr(pos);
775 return true;
776 }
777
ConvertPathToRealPath(const std::string & srcPath,const std::string & prefix,std::string & newPath,std::string & relativePath,FileInfo & fileInfo)778 bool UpgradeRestore::ConvertPathToRealPath(const std::string &srcPath, const std::string &prefix,
779 std::string &newPath, std::string &relativePath, FileInfo &fileInfo)
780 {
781 if (MediaFileUtils::StartsWith(srcPath, INTERNAL_PREFIX)) {
782 return ConvertPathToRealPath(srcPath, prefix, newPath, relativePath);
783 }
784 size_t pos = 0;
785 if (!BackupFileUtils::GetPathPosByPrefixLevel(sceneCode_, srcPath, SD_PREFIX_LEVEL, pos)) {
786 return false;
787 }
788 relativePath = srcPath.substr(pos);
789 if (fileInfo.fileSize < TAR_FILE_LIMIT || fileInfo.localMediaId == GALLERY_HIDDEN_ID ||
790 fileInfo.localMediaId == GALLERY_TRASHED_ID) {
791 newPath = prefix + srcPath; // packed as tar, hidden or trashed, use path in DB
792 } else {
793 newPath = prefix + relativePath; // others, remove sd prefix, use relative path
794 }
795 return true;
796 }
797
798 /**
799 * @brief Update the FileInfo if it has a copy in system.
800 */
HasSameFileForDualClone(FileInfo & fileInfo)801 bool UpgradeRestore::HasSameFileForDualClone(FileInfo &fileInfo)
802 {
803 PhotosDao::PhotosRowData rowData = this->photosRestore_.FindSameFile(fileInfo);
804 int32_t fileId = rowData.fileId;
805 std::string cloudPath = rowData.data;
806 if (fileId <= 0 || cloudPath.empty()) {
807 return false;
808 }
809 fileInfo.fileIdNew = fileId;
810 fileInfo.cloudPath = cloudPath;
811 return true;
812 }
813
RestoreFromGalleryPortraitAlbum()814 void UpgradeRestore::RestoreFromGalleryPortraitAlbum()
815 {
816 int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
817 int32_t totalNumber = QueryPortraitAlbumTotalNumber();
818 MEDIA_INFO_LOG("QueryPortraitAlbumTotalNumber, totalNumber = %{public}d", totalNumber);
819
820 for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
821 std::vector<std::string> tagNameToDeleteSelection;
822 std::vector<std::string> tagIds;
823 vector<PortraitAlbumInfo> portraitAlbumInfos = QueryPortraitAlbumInfos(offset,
824 tagNameToDeleteSelection);
825 if (!BackupDatabaseUtils::DeleteDuplicatePortraitAlbum(tagNameToDeleteSelection, tagIds, mediaLibraryRdb_)) {
826 MEDIA_ERR_LOG("Batch delete duplicate portrait album failed.");
827 return;
828 }
829 InsertPortraitAlbum(portraitAlbumInfos);
830 }
831
832 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
833 migratePortraitTotalTimeCost_ += end - start;
834 }
835
QueryPortraitAlbumTotalNumber()836 int32_t UpgradeRestore::QueryPortraitAlbumTotalNumber()
837 {
838 return BackupDatabaseUtils::QueryInt(galleryRdb_, QUERY_GALLERY_PORTRAIT_ALBUM_COUNT, CUSTOM_COUNT);
839 }
840
QueryPortraitAlbumInfos(int32_t offset,std::vector<std::string> & tagNameToDeleteSelection)841 vector<PortraitAlbumInfo> UpgradeRestore::QueryPortraitAlbumInfos(int32_t offset,
842 std::vector<std::string>& tagNameToDeleteSelection)
843 {
844 vector<PortraitAlbumInfo> result;
845 result.reserve(QUERY_COUNT);
846 std::string querySql = "SELECT " + GALLERY_MERGE_TAG_TAG_ID + ", " + GALLERY_GROUP_TAG + ", " +
847 GALLERY_TAG_NAME + ", " + GALLERY_USER_OPERATION + ", " + GALLERY_RENAME_OPERATION +
848 " FROM " + GALLERY_PORTRAIT_ALBUM_TABLE;
849 querySql += " LIMIT " + std::to_string(offset) + ", " + std::to_string(QUERY_COUNT);
850 auto resultSet = BackupDatabaseUtils::GetQueryResultSet(galleryRdb_, querySql);
851 if (resultSet == nullptr) {
852 MEDIA_ERR_LOG("Query resultSql is null.");
853 return result;
854 }
855 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
856 PortraitAlbumInfo portraitAlbumInfo;
857 if (!ParsePortraitAlbumResultSet(resultSet, portraitAlbumInfo)) {
858 MEDIA_ERR_LOG("Parse portrait album result set failed, exclude %{public}s",
859 portraitAlbumInfo.tagName.c_str());
860 continue;
861 }
862 if (!SetAttributes(portraitAlbumInfo)) {
863 MEDIA_ERR_LOG("Set attributes failed, exclude %{public}s", portraitAlbumInfo.tagName.c_str());
864 continue;
865 }
866 if (!portraitAlbumInfo.tagName.empty()) {
867 tagNameToDeleteSelection.emplace_back(portraitAlbumInfo.tagName);
868 }
869
870 result.emplace_back(portraitAlbumInfo);
871 }
872 return result;
873 }
874
ParsePortraitAlbumResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,PortraitAlbumInfo & portraitAlbumInfo)875 bool UpgradeRestore::ParsePortraitAlbumResultSet(const std::shared_ptr<NativeRdb::ResultSet> &resultSet,
876 PortraitAlbumInfo &portraitAlbumInfo)
877 {
878 portraitAlbumInfo.tagIdOld = GetStringVal(GALLERY_MERGE_TAG_TAG_ID, resultSet);
879 portraitAlbumInfo.groupTagOld = GetStringVal(GALLERY_GROUP_TAG, resultSet);
880 portraitAlbumInfo.tagName = GetStringVal(GALLERY_TAG_NAME, resultSet);
881 portraitAlbumInfo.userOperation = GetInt32Val(GALLERY_USER_OPERATION, resultSet);
882 portraitAlbumInfo.renameOperation = GetInt32Val(GALLERY_RENAME_OPERATION, resultSet);
883 return true;
884 }
885
SetAttributes(PortraitAlbumInfo & portraitAlbumInfo)886 bool UpgradeRestore::SetAttributes(PortraitAlbumInfo &portraitAlbumInfo)
887 {
888 return BackupDatabaseUtils::SetTagIdNew(portraitAlbumInfo, tagIdMap_);
889 }
890
InsertPortraitAlbum(std::vector<PortraitAlbumInfo> & portraitAlbumInfos)891 void UpgradeRestore::InsertPortraitAlbum(std::vector<PortraitAlbumInfo> &portraitAlbumInfos)
892 {
893 if (mediaLibraryRdb_ == nullptr) {
894 MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
895 return;
896 }
897 if (portraitAlbumInfos.empty()) {
898 MEDIA_ERR_LOG("portraitAlbumInfos are empty");
899 return;
900 }
901
902 int64_t startInsertAlbum = MediaFileUtils::UTCTimeMilliSeconds();
903 int32_t albumRowNum = InsertPortraitAlbumByTable(portraitAlbumInfos, true);
904 if (albumRowNum <= 0) {
905 BackupDatabaseUtils::PrintErrorLog("Insert portrait album failed", startInsertAlbum);
906 return;
907 }
908
909 int64_t startInsertTag = MediaFileUtils::UTCTimeMilliSeconds();
910 int32_t tagRowNum = InsertPortraitAlbumByTable(portraitAlbumInfos, false);
911 if (tagRowNum <= 0) {
912 BackupDatabaseUtils::PrintErrorLog("Insert face tag failed", startInsertTag);
913 return;
914 }
915
916 int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
917 BatchQueryAlbum(portraitAlbumInfos);
918 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
919 MEDIA_INFO_LOG("insert %{public}ld albums cost %{public}ld, %{public}ld tags cost %{public}ld, query cost "
920 "%{public}ld.", (long)albumRowNum, (long)(startInsertTag - startInsertAlbum), (long)tagRowNum,
921 (long)(startQuery - startInsertTag), (long)(end - startQuery));
922 }
923
InsertPortraitAlbumByTable(std::vector<PortraitAlbumInfo> & portraitAlbumInfos,bool isAlbum)924 int32_t UpgradeRestore::InsertPortraitAlbumByTable(std::vector<PortraitAlbumInfo> &portraitAlbumInfos,
925 bool isAlbum)
926 {
927 std::vector<NativeRdb::ValuesBucket> values = GetInsertValues(portraitAlbumInfos, isAlbum);
928 int64_t rowNum = 0;
929 std::string tableName = isAlbum ? ANALYSIS_ALBUM_TABLE : VISION_FACE_TAG_TABLE;
930 int32_t errCode = BatchInsertWithRetry(tableName, values, rowNum);
931 if (errCode != E_OK) {
932 return 0;
933 }
934 return rowNum;
935 }
936
GetInsertValues(std::vector<PortraitAlbumInfo> & portraitAlbumInfos,bool isAlbum)937 std::vector<NativeRdb::ValuesBucket> UpgradeRestore::GetInsertValues(std::vector<PortraitAlbumInfo> &portraitAlbumInfos,
938 bool isAlbum)
939 {
940 std::vector<NativeRdb::ValuesBucket> values;
941 for (auto &portraitAlbumInfo : portraitAlbumInfos) {
942 NativeRdb::ValuesBucket value = GetInsertValue(portraitAlbumInfo, isAlbum);
943 values.emplace_back(value);
944 }
945 return values;
946 }
947
GetInsertValue(const PortraitAlbumInfo & portraitAlbumInfo,bool isAlbum)948 NativeRdb::ValuesBucket UpgradeRestore::GetInsertValue(const PortraitAlbumInfo &portraitAlbumInfo, bool isAlbum)
949 {
950 NativeRdb::ValuesBucket values;
951 values.PutString(TAG_ID, portraitAlbumInfo.tagIdNew);
952 values.PutInt(COUNT, 0);
953 if (isAlbum) {
954 values.PutString(ALBUM_NAME, portraitAlbumInfo.tagName);
955 values.PutString(GROUP_TAG, portraitAlbumInfo.groupTagOld);
956 values.PutInt(USER_OPERATION, portraitAlbumInfo.userOperation);
957 values.PutInt(RENAME_OPERATION, RENAME_OPERATION_RENAMED);
958 values.PutInt(ALBUM_TYPE, PhotoAlbumType::SMART);
959 values.PutInt(ALBUM_SUBTYPE, PhotoAlbumSubType::PORTRAIT);
960 values.PutInt(USER_DISPLAY_LEVEL, PortraitPages::FIRST_PAGE);
961 values.PutInt(IS_LOCAL, IS_LOCAL_TRUE);
962 } else {
963 values.PutString(TAG_VERSION, E_VERSION); // updated by analysis service
964 }
965 return values;
966 }
967
BatchQueryAlbum(std::vector<PortraitAlbumInfo> & portraitAlbumInfos)968 void UpgradeRestore::BatchQueryAlbum(std::vector<PortraitAlbumInfo> &portraitAlbumInfos)
969 {
970 std::string tagIdSelection;
971 for (auto &portraitAlbumInfo : portraitAlbumInfos) {
972 BackupDatabaseUtils::UpdateSelection(tagIdSelection, portraitAlbumInfo.tagIdNew, true);
973 }
974 std::string querySql = "SELECT " + ALBUM_ID + ", " + TAG_ID + " FROM " + ANALYSIS_ALBUM_TABLE + " WHERE " +
975 TAG_ID + " IN (" + tagIdSelection + ")";
976 auto resultSet = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql);
977 if (resultSet == nullptr) {
978 return;
979 }
980 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
981 int32_t albumId = GetInt32Val(ALBUM_ID, resultSet);
982 std::string tagId = GetStringVal(TAG_ID, resultSet);
983 if (albumId <= 0 || tagId.empty()) {
984 continue;
985 }
986 portraitAlbumIdMap_[tagId] = albumId;
987 }
988 }
989
NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)990 bool UpgradeRestore::NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
991 {
992 if (portraitAlbumIdMap_.empty()) {
993 return false;
994 }
995 std::string selection;
996 for (const auto &fileInfo : fileInfos) {
997 BackupDatabaseUtils::UpdateSelection(selection, std::to_string(fileInfo.fileIdOld), false);
998 }
999 std::unordered_set<std::string> needQuerySet;
1000 std::string querySql = "SELECT DISTINCT " + GALLERY_MERGE_FACE_HASH + " FROM " + GALLERY_FACE_TABLE_JOIN_TAG +
1001 " HAVING " + GALLERY_MEDIA_ID + " IN (" + selection + ") AND " + GALLERY_TAG_NAME_NOT_NULL_OR_EMPTY;
1002 auto resultSet = BackupDatabaseUtils::GetQueryResultSet(galleryRdb_, querySql);
1003 if (resultSet == nullptr) {
1004 MEDIA_ERR_LOG("Query resultSql is null.");
1005 return false;
1006 }
1007 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1008 std::string hash = GetStringVal(GALLERY_MERGE_FACE_HASH, resultSet);
1009 if (hash.empty()) {
1010 continue;
1011 }
1012 needQuerySet.insert(hash);
1013 }
1014 if (needQuerySet.empty()) {
1015 return false;
1016 }
1017 needQueryMap[PhotoRelatedType::PORTRAIT] = needQuerySet;
1018 return true;
1019 }
1020
InsertFaceAnalysisData(const std::vector<FileInfo> & fileInfos,const NeedQueryMap & needQueryMap,int64_t & faceRowNum,int64_t & mapRowNum,int64_t & photoNum)1021 void UpgradeRestore::InsertFaceAnalysisData(const std::vector<FileInfo> &fileInfos, const NeedQueryMap &needQueryMap,
1022 int64_t &faceRowNum, int64_t &mapRowNum, int64_t &photoNum)
1023 {
1024 int64_t start = MediaFileUtils::UTCTimeMilliSeconds();
1025 if (needQueryMap.count(PhotoRelatedType::PORTRAIT) == 0) {
1026 return;
1027 }
1028 if (mediaLibraryRdb_ == nullptr || fileInfos.empty()) {
1029 MEDIA_ERR_LOG("mediaLibraryRdb_ is null or fileInfos empty");
1030 return;
1031 }
1032
1033 std::string hashSelection;
1034 std::unordered_map<std::string, FileInfo> fileInfoMap;
1035 SetHashReference(fileInfos, needQueryMap, hashSelection, fileInfoMap);
1036
1037 int32_t totalNumber = QueryFaceTotalNumber(hashSelection);
1038 MEDIA_INFO_LOG("Current %{public}zu / %{public}zu have %{public}d faces", fileInfoMap.size(), fileInfos.size(),
1039 totalNumber);
1040 std::unordered_set<std::string> excludedFiles;
1041 std::unordered_set<std::string> filesWithFace;
1042 auto uniqueFileIdPairs = BackupDatabaseUtils::CollectFileIdPairs(fileInfos);
1043 BackupDatabaseUtils::DeleteExistingImageFaceData(mediaLibraryRdb_, uniqueFileIdPairs);
1044
1045 for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
1046 std::vector<FaceInfo> faceInfos = QueryFaceInfos(hashSelection, fileInfoMap, offset, excludedFiles);
1047 int64_t startInsertFace = MediaFileUtils::UTCTimeMilliSeconds();
1048 faceRowNum += InsertFaceAnalysisDataByTable(faceInfos, false, excludedFiles);
1049 if (faceRowNum <= 0) {
1050 BackupDatabaseUtils::PrintErrorLog("Insert face failed", startInsertFace);
1051 continue;
1052 }
1053 int64_t startInsertMap = MediaFileUtils::UTCTimeMilliSeconds();
1054 mapRowNum += InsertFaceAnalysisDataByTable(faceInfos, true, excludedFiles);
1055 if (mapRowNum <= 0) {
1056 BackupDatabaseUtils::PrintErrorLog("Insert map failed", startInsertMap);
1057 continue;
1058 }
1059 UpdateFilesWithFace(filesWithFace, faceInfos);
1060 int64_t endInsert = MediaFileUtils::UTCTimeMilliSeconds();
1061 MEDIA_INFO_LOG("insert %{public}ld faces cost %{public}ld, %{public}ld maps cost %{public}ld", (long)faceRowNum,
1062 (long)(startInsertMap - startInsertFace), (long)mapRowNum, (long)(endInsert - startInsertMap));
1063 }
1064 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1065 photoNum = static_cast<int64_t>(filesWithFace.size());
1066 migratePortraitFaceNumber_ += faceRowNum;
1067 migratePortraitPhotoNumber_ += photoNum;
1068 migratePortraitTotalTimeCost_ += end - start;
1069 }
1070
SetHashReference(const std::vector<FileInfo> & fileInfos,const NeedQueryMap & needQueryMap,std::string & hashSelection,std::unordered_map<std::string,FileInfo> & fileInfoMap)1071 void UpgradeRestore::SetHashReference(const std::vector<FileInfo> &fileInfos, const NeedQueryMap &needQueryMap,
1072 std::string &hashSelection, std::unordered_map<std::string, FileInfo> &fileInfoMap)
1073 {
1074 auto needQuerySet = needQueryMap.at(PhotoRelatedType::PORTRAIT);
1075 for (const auto &fileInfo : fileInfos) {
1076 if (needQuerySet.count(fileInfo.hashCode) == 0 || fileInfo.fileIdNew <= 0) {
1077 continue;
1078 }
1079 if (fileInfoMap.count(fileInfo.hashCode) > 0) {
1080 continue; // select the first one to build map
1081 }
1082 BackupDatabaseUtils::UpdateSelection(hashSelection, fileInfo.hashCode, true);
1083 fileInfoMap[fileInfo.hashCode] = fileInfo;
1084 }
1085 }
1086
QueryFaceTotalNumber(const std::string & hashSelection)1087 int32_t UpgradeRestore::QueryFaceTotalNumber(const std::string &hashSelection)
1088 {
1089 std::string querySql = "SELECT count(1) as count FROM " + GALLERY_FACE_TABLE_FULL + " AND " +
1090 GALLERY_MERGE_FACE_HASH + " IN (" + hashSelection + ")";
1091 return BackupDatabaseUtils::QueryInt(galleryRdb_, querySql, CUSTOM_COUNT);
1092 }
1093
QueryFaceInfos(const std::string & hashSelection,const std::unordered_map<std::string,FileInfo> & fileInfoMap,int32_t offset,std::unordered_set<std::string> & excludedFiles)1094 std::vector<FaceInfo> UpgradeRestore::QueryFaceInfos(const std::string &hashSelection,
1095 const std::unordered_map<std::string, FileInfo> &fileInfoMap, int32_t offset,
1096 std::unordered_set<std::string> &excludedFiles)
1097 {
1098 vector<FaceInfo> result;
1099 result.reserve(QUERY_COUNT);
1100 std::string querySql = "SELECT " + GALLERY_SCALE_X + ", " + GALLERY_SCALE_Y + ", " + GALLERY_SCALE_WIDTH + ", " +
1101 GALLERY_SCALE_HEIGHT + ", " + GALLERY_PITCH + ", " + GALLERY_YAW + ", " + GALLERY_ROLL + ", " +
1102 GALLERY_PROB + ", " + GALLERY_TOTAL_FACE + ", " + GALLERY_MERGE_FACE_HASH + ", " + GALLERY_MERGE_FACE_FACE_ID +
1103 ", " + GALLERY_MERGE_FACE_TAG_ID + ", " + GALLERY_LANDMARKS + " FROM " + GALLERY_FACE_TABLE_FULL + " AND " +
1104 GALLERY_MERGE_FACE_HASH + " IN (" + hashSelection + ") ORDER BY " + GALLERY_MERGE_FACE_HASH + ", " +
1105 GALLERY_MERGE_FACE_FACE_ID;
1106 querySql += " LIMIT " + std::to_string(offset) + ", " + std::to_string(QUERY_COUNT);
1107 auto resultSet = BackupDatabaseUtils::GetQueryResultSet(galleryRdb_, querySql);
1108 if (resultSet == nullptr) {
1109 MEDIA_ERR_LOG("Query resultSql is null.");
1110 return result;
1111 }
1112 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1113 FaceInfo faceInfo;
1114 if (!ParseFaceResultSet(resultSet, faceInfo)) {
1115 MEDIA_ERR_LOG("Parse face result set failed, exclude %{public}s", faceInfo.hash.c_str());
1116 excludedFiles.insert(faceInfo.hash);
1117 continue;
1118 }
1119 if (!SetAttributes(faceInfo, fileInfoMap)) {
1120 MEDIA_ERR_LOG("Set attributes failed, exclude %{public}s", faceInfo.hash.c_str());
1121 excludedFiles.insert(faceInfo.hash);
1122 continue;
1123 }
1124 result.emplace_back(faceInfo);
1125 }
1126 return result;
1127 }
1128
ParseFaceResultSet(const std::shared_ptr<NativeRdb::ResultSet> & resultSet,FaceInfo & faceInfo)1129 bool UpgradeRestore::ParseFaceResultSet(const std::shared_ptr<NativeRdb::ResultSet> &resultSet, FaceInfo &faceInfo)
1130 {
1131 faceInfo.scaleX = GetDoubleVal(GALLERY_SCALE_X, resultSet);
1132 faceInfo.scaleY = GetDoubleVal(GALLERY_SCALE_Y, resultSet);
1133 faceInfo.scaleWidth = GetDoubleVal(GALLERY_SCALE_WIDTH, resultSet);
1134 faceInfo.scaleHeight = GetDoubleVal(GALLERY_SCALE_HEIGHT, resultSet);
1135 faceInfo.pitch = GetDoubleVal(GALLERY_PITCH, resultSet);
1136 faceInfo.yaw = GetDoubleVal(GALLERY_YAW, resultSet);
1137 faceInfo.roll = GetDoubleVal(GALLERY_ROLL, resultSet);
1138 faceInfo.prob = GetDoubleVal(GALLERY_PROB, resultSet);
1139 faceInfo.totalFaces = GetInt32Val(GALLERY_TOTAL_FACE, resultSet);
1140 faceInfo.hash = GetStringVal(GALLERY_MERGE_FACE_HASH, resultSet);
1141 faceInfo.faceId = GetStringVal(GALLERY_MERGE_FACE_FACE_ID, resultSet);
1142 faceInfo.tagIdOld = GetStringVal(GALLERY_MERGE_FACE_TAG_ID, resultSet);
1143 faceInfo.landmarks = BackupDatabaseUtils::GetLandmarksStr(GALLERY_LANDMARKS, resultSet);
1144 if (faceInfo.landmarks.empty()) {
1145 MEDIA_ERR_LOG("Get invalid landmarks for face %{public}s", faceInfo.faceId.c_str());
1146 return false;
1147 }
1148 return true;
1149 }
1150
SetAttributes(FaceInfo & faceInfo,const std::unordered_map<std::string,FileInfo> & fileInfoMap)1151 bool UpgradeRestore::SetAttributes(FaceInfo &faceInfo, const std::unordered_map<std::string, FileInfo> &fileInfoMap)
1152 {
1153 return BackupDatabaseUtils::SetLandmarks(faceInfo, fileInfoMap) &&
1154 BackupDatabaseUtils::SetFileIdNew(faceInfo, fileInfoMap) &&
1155 BackupDatabaseUtils::SetTagIdNew(faceInfo, tagIdMap_) &&
1156 BackupDatabaseUtils::SetAlbumIdNew(faceInfo, portraitAlbumIdMap_);
1157 }
1158
InsertFaceAnalysisDataByTable(const std::vector<FaceInfo> & faceInfos,bool isMap,const std::unordered_set<std::string> & excludedFiles)1159 int32_t UpgradeRestore::InsertFaceAnalysisDataByTable(const std::vector<FaceInfo> &faceInfos, bool isMap,
1160 const std::unordered_set<std::string> &excludedFiles)
1161 {
1162 std::vector<NativeRdb::ValuesBucket> values = GetInsertValues(faceInfos, isMap, excludedFiles);
1163 int64_t rowNum = 0;
1164 std::string tableName = isMap ? ANALYSIS_PHOTO_MAP_TABLE : VISION_IMAGE_FACE_TABLE;
1165 int32_t errCode = BatchInsertWithRetry(tableName, values, rowNum);
1166 if (errCode != E_OK) {
1167 return 0;
1168 }
1169 return rowNum;
1170 }
1171
GetInsertValues(const std::vector<FaceInfo> & faceInfos,bool isMap,const std::unordered_set<std::string> & excludedFiles)1172 std::vector<NativeRdb::ValuesBucket> UpgradeRestore::GetInsertValues(const std::vector<FaceInfo> &faceInfos, bool isMap,
1173 const std::unordered_set<std::string> &excludedFiles)
1174 {
1175 std::vector<NativeRdb::ValuesBucket> values;
1176 for (auto &faceInfo : faceInfos) {
1177 if (excludedFiles.count(faceInfo.hash) > 0) {
1178 continue;
1179 }
1180 if (isMap && faceInfo.tagIdNew == TAG_ID_UNPROCESSED) {
1181 continue;
1182 }
1183 NativeRdb::ValuesBucket value = GetInsertValue(faceInfo, isMap);
1184 values.emplace_back(value);
1185 }
1186 return values;
1187 }
1188
GetInsertValue(const FaceInfo & faceInfo,bool isMap)1189 NativeRdb::ValuesBucket UpgradeRestore::GetInsertValue(const FaceInfo &faceInfo, bool isMap)
1190 {
1191 NativeRdb::ValuesBucket values;
1192 if (isMap) {
1193 values.PutInt(MAP_ALBUM, faceInfo.albumIdNew);
1194 values.PutInt(MAP_ASSET, faceInfo.fileIdNew);
1195 } else {
1196 values.PutDouble(SCALE_X, faceInfo.scaleX);
1197 values.PutDouble(SCALE_Y, faceInfo.scaleY);
1198 values.PutDouble(SCALE_WIDTH, faceInfo.scaleWidth);
1199 values.PutDouble(SCALE_HEIGHT, faceInfo.scaleHeight);
1200 values.PutDouble(PITCH, faceInfo.pitch);
1201 values.PutDouble(YAW, faceInfo.yaw);
1202 values.PutDouble(ROLL, faceInfo.roll);
1203 values.PutDouble(PROB, faceInfo.prob);
1204 values.PutInt(TOTAL_FACES, faceInfo.totalFaces);
1205 values.PutInt(FILE_ID, faceInfo.fileIdNew);
1206 values.PutString(FACE_ID, faceInfo.faceId);
1207 values.PutString(TAG_ID, faceInfo.tagIdNew);
1208 values.PutString(LANDMARKS, faceInfo.landmarks);
1209 values.PutString(IMAGE_FACE_VERSION, DEFAULT_BACKUP_VERSION); // replaced by the latest
1210 values.PutString(IMAGE_FEATURES_VERSION, E_VERSION); // updated by analysis service
1211 }
1212 return values;
1213 }
1214
UpdateFilesWithFace(std::unordered_set<std::string> & filesWithFace,const std::vector<FaceInfo> & faceInfos)1215 void UpgradeRestore::UpdateFilesWithFace(std::unordered_set<std::string> &filesWithFace,
1216 const std::vector<FaceInfo> &faceInfos)
1217 {
1218 for (const auto &faceInfo : faceInfos) {
1219 if (faceInfo.hash.empty()) {
1220 continue;
1221 }
1222 filesWithFace.insert(faceInfo.hash);
1223 }
1224 }
1225
UpdateFaceAnalysisStatus()1226 void UpgradeRestore::UpdateFaceAnalysisStatus()
1227 {
1228 if (portraitAlbumIdMap_.empty()) {
1229 MEDIA_INFO_LOG("There is no need to update face analysis status");
1230 return;
1231 }
1232 int64_t startUpdateGroupTag = MediaFileUtils::UTCTimeMilliSeconds();
1233 BackupDatabaseUtils::UpdateFaceGroupTagOfDualFrame(mediaLibraryRdb_);
1234 int64_t startUpdateTotal = MediaFileUtils::UTCTimeMilliSeconds();
1235 BackupDatabaseUtils::UpdateAnalysisTotalStatus(mediaLibraryRdb_);
1236 int64_t startUpdateFaceTag = MediaFileUtils::UTCTimeMilliSeconds();
1237 BackupDatabaseUtils::UpdateAnalysisFaceTagStatus(mediaLibraryRdb_);
1238 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
1239 MEDIA_INFO_LOG("Update group tag cost %{public}lld, update total table cost %{public}lld, update face tag table "
1240 "cost %{public}lld", (long long)(startUpdateTotal - startUpdateGroupTag),
1241 (long long)(startUpdateFaceTag - startUpdateTotal), (long long)(end - startUpdateFaceTag));
1242 migratePortraitTotalTimeCost_ += end - startUpdateGroupTag;
1243 }
1244
UpdateDualCloneFaceAnalysisStatus()1245 void UpgradeRestore::UpdateDualCloneFaceAnalysisStatus()
1246 {
1247 if (portraitAlbumIdMap_.empty()) {
1248 MEDIA_INFO_LOG("There is no need to update face analysis status");
1249 return;
1250 }
1251
1252 BackupDatabaseUtils::UpdateFaceGroupTagOfDualFrame(mediaLibraryRdb_);
1253 BackupDatabaseUtils::UpdateAnalysisPhotoMapStatus(mediaLibraryRdb_);
1254 BackupDatabaseUtils::UpdateFaceAnalysisTblStatus(mediaLibraryRdb_);
1255 }
1256 } // namespace Media
1257 } // namespace OHOS