• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 #define MLOG_TAG "MediaLibraryMetaRecovery"
16 
17 #include "medialibrary_meta_recovery.h"
18 
19 #include <cerrno>
20 #include <dirent.h>
21 #include <fcntl.h>
22 
23 #include "acl.h"
24 #ifdef HAS_BATTERY_MANAGER_PART
25 #include "battery_srv_client.h"
26 #endif
27 #include "cloud_sync_helper.h"
28 #include "dfx_database_utils.h"
29 #include "dfx_utils.h"
30 #include "directory_ex.h"
31 #include "hisysevent.h"
32 #include "media_file_uri.h"
33 #include "media_file_utils.h"
34 #include "media_log.h"
35 #include "media_scanner_const.h"
36 #include "media_scanner_db.h"
37 #include "media_scanner_manager.h"
38 #include "metadata.h"
39 #include "metadata_extractor.h"
40 #include "medialibrary_album_fusion_utils.h"
41 #include "medialibrary_data_manager.h"
42 #include "medialibrary_db_const.h"
43 #include "medialibrary_errno.h"
44 #include "medialibrary_kvstore_manager.h"
45 #include "medialibrary_notify.h"
46 #include "medialibrary_photo_operations.h"
47 #include "medialibrary_rdb_transaction.h"
48 #include "medialibrary_rdb_utils.h"
49 #include "medialibrary_type_const.h"
50 #include "medialibrary_unistore_manager.h"
51 #include "mimetype_utils.h"
52 #include "parameter.h"
53 #include "photo_album_column.h"
54 #include "photo_file_utils.h"
55 #include "photo_map_column.h"
56 #include "post_event_utils.h"
57 #include "preferences.h"
58 #include "preferences_helper.h"
59 #include "result_set_utils.h"
60 #ifdef HAS_THERMAL_MANAGER_PART
61 #include "thermal_mgr_client.h"
62 #endif
63 #include "vision_column.h"
64 
65 namespace OHOS {
66 namespace Media {
67 using namespace std;
68 using json = nlohmann::json;
69 
70 namespace {
71     const string META_RECOVERY_ROOT_DIR = ROOT_MEDIA_DIR + ".meta/";
72     const string META_RECOVERY_META_PATH = ROOT_MEDIA_DIR + ".meta/Photo";
73     const string META_RECOVERY_ALBUM_PATH = META_RECOVERY_ROOT_DIR + "album.json";
74     const string META_STATUS_PATH = META_RECOVERY_ROOT_DIR + "status.json";
75     constexpr int32_t QUERY_BATCH_SIZE = 500;
76     constexpr int32_t META_RETRY_MAX_COUNTS = 10;
77     constexpr int32_t META_RETRY_INTERVAL = 100;
78     const std::string RDB_CONFIG = "/data/storage/el2/base/preferences/recovery_config.xml";
79     const std::string BACKUP_PHOTO_COUNT = "BACKUP_PHOTO_COUNT";
80     const std::string BACKUP_COST_TIME = "BACKUP_COST_TIME";
81     const std::string REBUILT_COUNT = "REBUILT_COUNT";
82     const std::string RECOVERY_BACKUP_TOTAL_COUNT = "RECOVERY_BACKUP_TOTAL_COUNT";
83     const std::string RECOVERY_SUCC_PHOTO_COUNT = "RECOVERY_SUCC_PHOTO_COUNT";
84     const std::string RECOVERY_COST_TIME = "RECOVERY_COST_TIME";
85     static const std::unordered_set<std::string> EXCLUDED_COLUMNS = {
86         MediaColumn::MEDIA_ID,
87         MediaColumn::MEDIA_VIRTURL_PATH,
88         PhotoColumn::PHOTO_THUMBNAIL_READY,
89         PhotoColumn::PHOTO_METADATA_FLAGS,
90     };
91 }  // namespace
92 
SetStartupParam()93 static void SetStartupParam()
94 {
95     static constexpr uint32_t BASE_USER_RANGE = 200000; // for get uid
96     uid_t uid = getuid() / BASE_USER_RANGE;
97     const string key = "multimedia.medialibrary.startup." + to_string(uid);
98     string value = "true";
99     int ret = SetParameter(key.c_str(), value.c_str());
100     if (ret != 0) {
101         MEDIA_ERR_LOG("Failed to set startup, result: %{public}d", ret);
102     } else {
103         MEDIA_INFO_LOG("Set startup success: %{public}s", to_string(uid).c_str());
104     }
105 }
106 
RefreshThumbnail()107 static int32_t RefreshThumbnail()
108 {
109     MediaLibraryKvStoreManager::GetInstance().RebuildInvalidKvStore(KvStoreValueType::MONTH_ASTC);
110     MediaLibraryKvStoreManager::GetInstance().RebuildInvalidKvStore(KvStoreValueType::YEAR_ASTC);
111     Acl::AclSetDatabase();
112     return E_OK;
113 }
114 
RefreshAlbumCount()115 static int32_t RefreshAlbumCount()
116 {
117     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
118     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "RefreshAlbumCount: failed to get rdb store handler");
119 
120     MediaLibraryRdbUtils::UpdateAllAlbums(rdbStore);
121     auto watch = MediaLibraryNotify::GetInstance();
122     CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
123 
124     watch->Notify(PhotoAlbumColumns::ALBUM_URI_PREFIX, NotifyType::NOTIFY_ADD);
125     watch->Notify(PhotoAlbumColumns::ALBUM_URI_PREFIX, NotifyType::NOTIFY_UPDATE);
126     return E_OK;
127 }
128 
GetStringFromJson(const nlohmann::json & j,const std::string & key)129 static std::optional<std::string> GetStringFromJson(const nlohmann::json &j, const std::string &key)
130 {
131     if (j.contains(key) && j.at(key).is_string()) {
132         std::string value = j.at(key);
133         MEDIA_DEBUG_LOG("get string json ok, %{private}s: %{private}s", key.c_str(), value.c_str());
134         return std::optional<std::string>(value);
135     } else {
136         MEDIA_ERR_LOG("get key: %{private}s failed", key.c_str());
137         return std::nullopt;
138     }
139 }
140 
GetNumberFromJson(const nlohmann::json & j,const std::string & key)141 static std::optional<int64_t> GetNumberFromJson(const nlohmann::json &j, const std::string &key)
142 {
143     if (j.contains(key) && j.at(key).is_number_integer()) {
144         int64_t value = j.at(key);
145         return std::optional<int64_t>(value);
146     } else {
147         MEDIA_ERR_LOG("get key: %{private}s failed", key.c_str());
148         return std::nullopt;
149     }
150 }
151 
GetDoubleFromJson(const nlohmann::json & j,const std::string & key)152 static std::optional<double> GetDoubleFromJson(const nlohmann::json &j, const std::string &key)
153 {
154     if (j.contains(key) && j.at(key).is_number_float()) {
155         double value = j.at(key);
156         MEDIA_DEBUG_LOG("get double json ok, %{private}s: %{private}f", key.c_str(), value);
157         return std::optional<double>(value);
158     } else {
159         MEDIA_ERR_LOG("get key: %{private}s failed", key.c_str());
160         return std::nullopt;
161     }
162 }
163 
SetValuesFromFileAsset(const FileAsset & fileAsset,NativeRdb::ValuesBucket & values,const std::unordered_map<std::string,ResultSetDataType> & columnInfoMap)164 static void SetValuesFromFileAsset(const FileAsset &fileAsset, NativeRdb::ValuesBucket &values,
165     const std::unordered_map<std::string, ResultSetDataType> &columnInfoMap)
166 {
167     for (const auto &[name, type] : columnInfoMap) {
168         if (type == TYPE_STRING) {
169             values.PutString(name, fileAsset.GetStrMember(name));
170         } else if (type == TYPE_INT32) {
171             values.PutInt(name, fileAsset.GetInt32Member(name));
172         } else if (type == TYPE_INT64) {
173             values.PutLong(name, fileAsset.GetInt64Member(name));
174         } else if (type == TYPE_DOUBLE) {
175             values.PutDouble(name, fileAsset.GetDoubleMember(name));
176         } else {
177             MEDIA_DEBUG_LOG("Invalid fileasset value type, name = %{private}s, type = %{public}d", name.c_str(), type);
178         }
179     }
180 }
181 
SetValuesFromPhotoAlbum(shared_ptr<PhotoAlbum> & photoAlbumPtr,NativeRdb::ValuesBucket & values)182 static void SetValuesFromPhotoAlbum(shared_ptr<PhotoAlbum> &photoAlbumPtr, NativeRdb::ValuesBucket &values)
183 {
184     values.PutInt(PhotoAlbumColumns::ALBUM_TYPE, photoAlbumPtr->GetPhotoAlbumType());
185     values.PutInt(PhotoAlbumColumns::ALBUM_SUBTYPE, photoAlbumPtr->GetPhotoAlbumSubType());
186     values.PutString(PhotoAlbumColumns::ALBUM_NAME, photoAlbumPtr->GetAlbumName());
187     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_MODIFIED, photoAlbumPtr->GetDateModified());
188     values.PutInt(PhotoAlbumColumns::CONTAINS_HIDDEN, photoAlbumPtr->GetContainsHidden());
189     values.PutString(PhotoAlbumColumns::ALBUM_BUNDLE_NAME, photoAlbumPtr->GetBundleName());
190     values.PutString(PhotoAlbumColumns::ALBUM_LOCAL_LANGUAGE, photoAlbumPtr->GetLocalLanguage());
191     values.PutInt(PhotoAlbumColumns::ALBUM_IS_LOCAL, photoAlbumPtr->GetIsLocal());
192     values.PutLong(PhotoAlbumColumns::ALBUM_DATE_ADDED, photoAlbumPtr->GetDateAdded());
193     values.PutString(PhotoAlbumColumns::ALBUM_LPATH, photoAlbumPtr->GetLPath());
194     values.PutInt(PhotoAlbumColumns::ALBUM_PRIORITY, photoAlbumPtr->GetPriority());
195 }
196 
GetPhotoAlbumFromJsonPart1(const nlohmann::json & j,PhotoAlbum & photoAlbum)197 static bool GetPhotoAlbumFromJsonPart1(const nlohmann::json &j, PhotoAlbum &photoAlbum)
198 {
199     bool ret = true;
200 
201     optional<string> bundleName = GetStringFromJson(j, PhotoAlbumColumns::ALBUM_BUNDLE_NAME);
202     if (bundleName.has_value()) {
203         photoAlbum.SetBundleName(bundleName.value());
204     } else {
205         ret = false;
206     }
207 
208     optional<string> localLanguage = GetStringFromJson(j, PhotoAlbumColumns::ALBUM_LOCAL_LANGUAGE);
209     if (localLanguage.has_value()) {
210         photoAlbum.SetLocalLanguage(localLanguage.value());
211     } else {
212         ret = false;
213     }
214 
215     optional<int64_t> dateAdded = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_DATE_ADDED);
216     if (dateAdded.has_value()) {
217         photoAlbum.SetDateAdded(dateAdded.value());
218     } else {
219         ret = false;
220     }
221 
222     optional<int64_t> isLocal = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_IS_LOCAL);
223     if (isLocal.has_value()) {
224         photoAlbum.SetIsLocal((int32_t)isLocal.value());
225     } else {
226         ret = false;
227     }
228 
229     optional<string> lPath = GetStringFromJson(j, PhotoAlbumColumns::ALBUM_LPATH);
230     if (lPath.has_value()) {
231         photoAlbum.SetLPath(lPath.value());
232     } else {
233         ret = false;
234     }
235 
236     optional<int64_t> priority = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_PRIORITY);
237     if (priority.has_value()) {
238         photoAlbum.SetPriority((int32_t)priority.value());
239     } else {
240         ret = false;
241     }
242 
243     return ret;
244 }
245 
GetInstance()246 MediaLibraryMetaRecovery &MediaLibraryMetaRecovery::GetInstance()
247 {
248     static MediaLibraryMetaRecovery instance;
249     return instance;
250 }
251 
CheckRecoveryState()252 void MediaLibraryMetaRecovery::CheckRecoveryState()
253 {
254     MediaLibraryMetaRecoveryState expect = MediaLibraryMetaRecoveryState::STATE_NONE;
255     if (recoveryState_.compare_exchange_strong(expect, MediaLibraryMetaRecoveryState::STATE_BACKING_UP)) {
256         std::thread([this]() {
257             int64_t backupStartTime = MediaFileUtils::UTCTimeMilliSeconds();
258             this->DoBackupMetadata();
259             int64_t backupTotalTime = MediaFileUtils::UTCTimeMilliSeconds() - backupStartTime;
260             backupCostTime_ += backupTotalTime;
261             MediaLibraryMetaRecoveryState expect = MediaLibraryMetaRecoveryState::STATE_BACKING_UP;
262             if (recoveryState_.compare_exchange_strong(expect, MediaLibraryMetaRecoveryState::STATE_NONE)) {
263                 MEDIA_INFO_LOG("End backing up normaly");
264             } else {
265                 MEDIA_INFO_LOG("End backing up interrupted");
266             }
267         }).detach();
268     } else {
269         MEDIA_INFO_LOG("Ignore backing up, current status = %{public}d", expect);
270     }
271 }
272 
InterruptRecovery()273 void MediaLibraryMetaRecovery::InterruptRecovery()
274 {
275     switch (recoveryState_.load()) {
276         case MediaLibraryMetaRecoveryState::STATE_BACKING_UP: {
277             MediaLibraryMetaRecoveryState expect = MediaLibraryMetaRecoveryState::STATE_BACKING_UP;
278             if (recoveryState_.compare_exchange_strong(expect, MediaLibraryMetaRecoveryState::STATE_NONE)) {
279                 MEDIA_INFO_LOG("InterruptRecovery: success send interrupt request");
280             } else {
281                 MEDIA_INFO_LOG("InterruptRecovery: backup process is finished, no need to interrupt");
282             }
283             break;
284         }
285         case MediaLibraryMetaRecoveryState::STATE_RECOVERING: {
286             MEDIA_INFO_LOG("InterruptRecovery: need to interrupt recovery process");
287             break;
288         }
289         default: {
290             MEDIA_INFO_LOG("InterruptRecovery: nother recovery or backup is processing, ignore");
291             break;
292         }
293     }
294 }
295 
LoadAlbumMaps(const string & path)296 void MediaLibraryMetaRecovery::LoadAlbumMaps(const string &path)
297 {
298     // 1. album.json to oldAlbumIdToLpath
299     int32_t ret = E_OK;
300     std::vector<shared_ptr<PhotoAlbum>> vecPhotoAlbum;
301     ret = ReadPhotoAlbumFromFile(path, vecPhotoAlbum);
302     CHECK_AND_RETURN_LOG(ret == E_OK, "read album file failed, path=%{public}s", DfxUtils::GetSafePath(path).c_str());
303 
304     for (auto it : vecPhotoAlbum) {
305         oldAlbumIdToLpath[it->GetAlbumId()] = it->GetLPath();
306         MEDIA_INFO_LOG("oldAlbumIdToLpath, json id %{public}d, path=%{public}s", it->GetAlbumId(),
307             DfxUtils::GetSafePath(it->GetLPath()).c_str());
308     }
309     // 2. db PhotoAlbum to lpathToNewAlbumId
310     NativeRdb::RdbPredicates predicates(PhotoAlbumColumns::TABLE);
311     vector<string> columns = {PhotoAlbumColumns::ALBUM_ID,
312         PhotoAlbumColumns::ALBUM_LPATH};
313     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
314     CHECK_AND_RETURN_LOG(resultSet != nullptr, "resultSet == nullptr)");
315 
316     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
317         int albumId = GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet);
318         string lPath = GetStringVal(PhotoAlbumColumns::ALBUM_LPATH, resultSet);
319         lpathToNewAlbumId[lPath] = albumId;
320         MEDIA_INFO_LOG("lpathToNewAlbumId, path=%{public}s db id %{public}d, ",
321             DfxUtils::GetSafePath(lPath).c_str(), albumId);
322     }
323     return;
324 }
325 
DoDataBaseRecovery()326 void MediaLibraryMetaRecovery::DoDataBaseRecovery()
327 {
328     SetStartupParam();
329     StopCloudSync();
330     RefreshThumbnail();
331     MEDIA_INFO_LOG("Album recovery start");
332     if (AlbumRecovery(ROOT_MEDIA_DIR + ".meta/album.json") != E_OK) {
333         MEDIA_ERR_LOG("Recovery Album failed");
334     }
335     MEDIA_INFO_LOG("Album recovery end");
336 
337     LoadAlbumMaps(ROOT_MEDIA_DIR+".meta/album.json");
338 
339     MEDIA_INFO_LOG("Photo recovery start");
340     if (PhotoRecovery(META_RECOVERY_META_PATH) != E_OK) {
341         MEDIA_ERR_LOG("Recover Photo failed");
342     }
343     MEDIA_INFO_LOG("Photo recovery end");
344 
345     RefreshAlbumCount();
346     RestartCloudSync();
347     oldAlbumIdToLpath.clear();
348     lpathToNewAlbumId.clear();
349 }
350 
AlbumRecovery(const string & path)351 int32_t MediaLibraryMetaRecovery::AlbumRecovery(const string &path)
352 {
353     int32_t ret = E_OK;
354     std::vector<shared_ptr<PhotoAlbum>> vecPhotoAlbum;
355 
356     do {
357         ret = access(path.c_str(), F_OK | R_OK);
358         if (ret != E_OK) {
359             MEDIA_ERR_LOG("file is not exist or no read access, path=%{public}s", DfxUtils::GetSafePath(path).c_str());
360             break;
361         }
362 
363         ret = ReadPhotoAlbumFromFile(path, vecPhotoAlbum);
364         if (ret != E_OK) {
365             MEDIA_ERR_LOG("read album file failed, errCode = %{public}d", ret);
366             break;
367         }
368 
369         ret = InsertMetadataInDb(vecPhotoAlbum);
370         if (ret != E_OK) {
371             MEDIA_ERR_LOG("AlbumRecovery: insert album failed, errCode = %{public}d", ret);
372             break;
373         }
374 
375         MEDIA_INFO_LOG("AlbumRecovery: photo album is recovered successful");
376     } while (false);
377 
378     return ret;
379 }
380 
GetTotalBackupFileCount()381 static int32_t GetTotalBackupFileCount()
382 {
383     int count = 0;
384     if (access(META_RECOVERY_META_PATH.c_str(), F_OK) != E_OK) {
385         return count;
386     }
387 
388     filesystem::path dir(META_RECOVERY_META_PATH);
389     for (const auto& entry : filesystem::recursive_directory_iterator(dir)) {
390         if (entry.is_regular_file() && entry.path().extension() == ".json") {
391             ++count;
392         }
393     }
394 
395     return count;
396 }
397 
PhotoRecovery(const string & path)398 int32_t MediaLibraryMetaRecovery::PhotoRecovery(const string &path)
399 {
400     string realPath;
401     int32_t bucket_id = -1;
402 
403     if (!PathToRealPath(path, realPath)) {
404         if (errno == ENOENT) {
405             // Delte Metastatus Json;
406             remove(META_STATUS_PATH.c_str());
407             // Delete status
408             metaStatus.clear();
409             MEDIA_ERR_LOG("no meta file no need to recovery");
410             return E_OK;
411         }
412         MEDIA_ERR_LOG("Failed to get real path %{private}s, errno %{public}d", path.c_str(), errno);
413         return E_INVALID_PATH;
414     }
415 
416     recoveryTotalBackupCnt_ = GetTotalBackupFileCount();
417     MEDIA_INFO_LOG("recovery success total backup");
418 
419     if (!ScannerUtils::IsDirectory(realPath)) {
420         MEDIA_ERR_LOG("The path %{private}s is not a directory", realPath.c_str());
421         return E_INVALID_PATH;
422     }
423 
424     int err = ScanMetaDir(path, bucket_id);
425     if (err != E_OK) {
426         MEDIA_ERR_LOG("Failed to ScanMetaDir, errCode=%{public}d", err);
427     }
428 
429     recoverySuccCnt_ += ReadMetaRecoveryCountFromFile();
430 
431     // Delte Metastatus Json;
432     err = remove(META_STATUS_PATH.c_str());
433     if (err != E_OK) {
434         MEDIA_WARN_LOG("Remove META_STATUS_PATH failed, errCode=%{public}d", err);
435     }
436     // Delete status
437     metaStatus.clear();
438 
439     return err;
440 }
441 
WriteSingleMetaDataById(int32_t rowId)442 int32_t MediaLibraryMetaRecovery::WriteSingleMetaDataById(int32_t rowId)
443 {
444     int ret = E_OK;
445 
446     MEDIA_DEBUG_LOG("WriteSingleMetaDataById : rowId %{public}d", rowId);
447     auto asset = MediaLibraryAssetOperations::QuerySinglePhoto(rowId);
448     CHECK_AND_RETURN_RET_LOG(asset != nullptr, E_HAS_DB_ERROR, "QuerySinglePhoto : rowId %{public}d failed", rowId);
449 
450     ret = WriteSingleMetaData(*asset);
451     if (ret == E_OK) {
452         backupSuccCnt_++;
453     }
454     return ret;
455 }
456 
WriteSingleMetaData(const FileAsset & asset)457 int32_t MediaLibraryMetaRecovery::WriteSingleMetaData(const FileAsset &asset)
458 {
459     string metaFilePath;
460     int32_t ret = E_OK;
461 
462     ret = PhotoFileUtils::GetMetaPathFromOrignalPath(asset.GetPath(), metaFilePath);
463     if (ret != E_OK) {
464         MEDIA_ERR_LOG("invalid photo path, path = %{public}s", DfxUtils::GetSafePath(asset.GetPath()).c_str());
465         return ret;
466     }
467 
468     // Create direcotry
469     const string metaParentPath = MediaFileUtils::GetParentPath(metaFilePath);
470     if (!MediaFileUtils::CreateDirectory(metaParentPath)) {
471         MEDIA_ERR_LOG("photo: CreateDirectory failed, filePath = %{public}s",
472             DfxUtils::GetSafePath(metaParentPath).c_str());
473         return E_HAS_FS_ERROR;
474     }
475 
476     // Create metadata file
477     ret = WriteMetadataToFile(metaFilePath, asset);
478     if (ret != E_OK) {
479         MEDIA_ERR_LOG("photo: WriteMetadataToFile failed, filePath = %{public}s",
480             DfxUtils::GetSafePath(metaFilePath).c_str());
481         return ret;
482     }
483 
484     // Up to date
485     ret = UpdateMetadataFlagInDb(asset.GetId(), MetadataFlags::TYPE_UPTODATE);
486     if (ret != E_OK) {
487         MEDIA_ERR_LOG("photo: Up to date failed, filePath = %{public}s", DfxUtils::GetSafePath(metaFilePath).c_str());
488         return ret;
489     }
490 
491     return ret;
492 }
493 
DoBackupMetadata()494 void MediaLibraryMetaRecovery::DoBackupMetadata()
495 {
496     int32_t temp = 0;
497     int32_t tempLevel = 0;
498     int32_t batteryCapacity = 0;
499 
500 #ifdef HAS_THERMAL_MANAGER_PART
501     auto& thermalMgrClient = PowerMgr::ThermalMgrClient::GetInstance();
502     temp = static_cast<int32_t>(thermalMgrClient.GetThermalSensorTemp(PowerMgr::SensorType::SHELL));
503     tempLevel = static_cast<int32_t>(thermalMgrClient.GetThermalLevel());
504 #endif
505 #ifdef HAS_BATTERY_MANAGER_PART
506     batteryCapacity = PowerMgr::BatterySrvClient::GetInstance().GetCapacity();
507 #endif
508     MEDIA_INFO_LOG("Start backing up, batteryCap = %{public}d, temp = %{public}d(%{public}d)",
509         batteryCapacity, temp, tempLevel);
510 
511     // Backing up photo albums
512     AlbumBackup();
513 
514     // Backing up photos
515     PhotoBackupBatch();
516 }
517 
AlbumBackup()518 void MediaLibraryMetaRecovery::AlbumBackup()
519 {
520     vector<shared_ptr<PhotoAlbum>> photoAlbumVector;
521     MediaLibraryAssetOperations::QueryTotalAlbum(photoAlbumVector);
522     int photoAlbumCount = photoAlbumVector.size();
523     if (photoAlbumCount <= 0) {
524         MEDIA_INFO_LOG("AlbumBackup: no photo albums need to backup");
525         return;
526     }
527 
528     MEDIA_INFO_LOG("AlbumBackup: album count = %{public}d", photoAlbumCount);
529     if (E_OK != WritePhotoAlbumToFile(META_RECOVERY_ALBUM_PATH, photoAlbumVector)) {
530         MEDIA_ERR_LOG("AlbumBackup: WritePhotoAlbumToFile failed");
531     }
532 }
533 
PhotoBackupBatch()534 void MediaLibraryMetaRecovery::PhotoBackupBatch()
535 {
536     int32_t photoTotalCount = 0;
537     int32_t photoProcessedCount = 0;
538     int32_t photoSuccessedCount = 0;
539     vector<shared_ptr<FileAsset>> photoVector;
540     do {
541         if (recoveryState_.load() != MediaLibraryMetaRecoveryState::STATE_BACKING_UP) {
542             MEDIA_INFO_LOG("Photo backing up process is interrupted");
543             break;
544         }
545 
546         photoVector.clear();
547         MediaLibraryAssetOperations::QueryTotalPhoto(photoVector, QUERY_BATCH_SIZE);
548         if (photoVector.size() > 0) {
549             photoTotalCount += photoVector.size();
550             PhotoBackup(photoVector, photoProcessedCount, photoSuccessedCount);
551         }
552     } while (photoVector.size() == QUERY_BATCH_SIZE);
553     MEDIA_INFO_LOG("Photo backup end, result = %{public}d/%{public}d/%{public}d",
554         photoSuccessedCount, photoProcessedCount, photoTotalCount);
555     backupSuccCnt_ += photoSuccessedCount;
556 }
557 
PhotoBackup(const vector<shared_ptr<FileAsset>> & photoVector,int32_t & processCount,int32_t & successCount)558 void MediaLibraryMetaRecovery::PhotoBackup(const vector<shared_ptr<FileAsset>> &photoVector,
559                                            int32_t &processCount,
560                                            int32_t &successCount)
561 {
562     for (auto &asset : photoVector) {
563         // Check interrupt request
564         if (recoveryState_.load() != MediaLibraryMetaRecoveryState::STATE_BACKING_UP) {
565             MEDIA_INFO_LOG("Photo backing up process is interrupted");
566             break;
567         }
568 
569         processCount++;
570 
571         if (!asset) {
572             MEDIA_ERR_LOG("Photo asset pointer is null");
573             continue;
574         }
575 
576         if (E_OK != WriteSingleMetaData(*asset)) {
577             MEDIA_ERR_LOG("WriteSingleMetaData failed");
578             continue;
579         }
580 
581         successCount++;
582     }
583 }
584 
ScanMetaDir(const string & path,int32_t bucket_id)585 int32_t MediaLibraryMetaRecovery::ScanMetaDir(const string &path, int32_t bucket_id)
586 {
587     int err = E_OK;
588     DIR *dirPath = nullptr;
589     struct dirent *ent = nullptr;
590     size_t len = path.length();
591     struct stat statInfo;
592 
593     if (len >= FILENAME_MAX - 1) {
594         return ERR_INCORRECT_PATH;
595     }
596 
597     auto fName = (char *)calloc(FILENAME_MAX, sizeof(char));
598     if (fName == nullptr) {
599         return ERR_MEM_ALLOC_FAIL;
600     }
601 
602     if (strcpy_s(fName, FILENAME_MAX, path.c_str()) != ERR_SUCCESS) {
603         FREE_MEMORY_AND_SET_NULL(fName);
604         return ERR_MEM_ALLOC_FAIL;
605     }
606     fName[len++] = '/';
607     if ((dirPath = opendir(path.c_str())) == nullptr) {
608         MEDIA_ERR_LOG("Failed to opendir %{private}s, errno %{private}d", path.c_str(), errno);
609         FREE_MEMORY_AND_SET_NULL(fName);
610         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, -errno},
611             {KEY_OPT_FILE, path}, {KEY_OPT_TYPE, OptType::SCAN}};
612         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
613         return ERR_NOT_ACCESSIBLE;
614     }
615 
616     int32_t recoverySuccessCnt = 0;
617     while ((ent = readdir(dirPath)) != nullptr) {
618         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
619             continue;
620         }
621 
622         if (strncpy_s(fName + len, FILENAME_MAX - len, ent->d_name, FILENAME_MAX - len)) {
623             continue;
624         }
625 
626         if (lstat(fName, &statInfo) == -1) {
627             continue;
628         }
629 
630         string currentPath = fName;
631         if (S_ISDIR(statInfo.st_mode)) {
632             int32_t cur_bucket = atoi(ent->d_name);
633             MEDIA_INFO_LOG("currentPath=%{public}s, path=%{public}s, cur_bucket %{public}d recovery start",
634                            DfxUtils::GetSafePath(currentPath).c_str(), DfxUtils::GetSafePath(path).c_str(), cur_bucket);
635 
636             // Recovery after interrupt, skip bucket which scanned.
637             if (metaStatus.find(cur_bucket) != metaStatus.end()) {
638                 MEDIA_INFO_LOG("skip bucket id=%{public}d", cur_bucket);
639                 continue;
640             }
641             (void)ScanMetaDir(currentPath, cur_bucket);
642             RefreshAlbumCount();
643             continue;
644         }
645 
646         MEDIA_DEBUG_LOG("currentPath=%{public}s, path=%{public}s",
647             DfxUtils::GetSafePath(currentPath).c_str(), DfxUtils::GetSafePath(path).c_str());
648 
649         FileAsset fileAsset;
650         if (ReadMetadataFromFile(currentPath, fileAsset) != E_OK) {
651             MEDIA_ERR_LOG("ScanMetaDir: ReadMetadataFrom file failed");
652             continue;
653         }
654 
655         // Insert fileAsset to DB
656         if (InsertMetadataInDbRetry(fileAsset) == E_OK) {
657             recoverySuccessCnt++;
658         }
659     }
660 
661     closedir(dirPath);
662     FREE_MEMORY_AND_SET_NULL(fName);
663 
664     if (bucket_id != -1) {
665         err = WriteMetaStatusToFile(to_string(bucket_id), recoverySuccessCnt);
666         if (err != E_OK) {
667             MEDIA_ERR_LOG("write meta status failed");
668         }
669         MEDIA_INFO_LOG("cur_bucket %{public}d recovery end", bucket_id);
670     }
671 
672     return err;
673 }
674 
WriteJsonFile(const std::string & filePath,const nlohmann::json & j)675 bool MediaLibraryMetaRecovery::WriteJsonFile(const std::string &filePath, const nlohmann::json &j)
676 {
677     const string parentDir = MediaFileUtils::GetParentPath(filePath);
678     if (!MediaFileUtils::CreateDirectory(parentDir)) {
679         MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
680         return false;
681     }
682 
683     std::ofstream outFile(filePath, std::ofstream::out | std::ofstream::trunc);
684     if (!outFile.is_open()) {
685         MEDIA_ERR_LOG("open filePath: %{private}s failed", filePath.c_str());
686         return false;
687     }
688     std::string jsonString = j.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
689     outFile << jsonString << std::endl;
690     outFile.close();
691     return true;
692 }
693 
ReadJsonFile(const std::string & filePath,nlohmann::json & j)694 bool MediaLibraryMetaRecovery::ReadJsonFile(const std::string &filePath, nlohmann::json &j)
695 {
696     std::ifstream inFile(filePath);
697     if (!inFile.is_open()) {
698         MEDIA_ERR_LOG("open filePath: %{private}s failed", filePath.c_str());
699         return false;
700     }
701     std::string buffer = std::string((istreambuf_iterator<char>(inFile)), istreambuf_iterator<char>());
702     j = json::parse(buffer, nullptr, false);
703     inFile.close();
704     return !j.is_discarded();
705 }
706 
WriteMetadataToFile(const string & filePath,const FileAsset & fileAsset)707 int32_t MediaLibraryMetaRecovery::WriteMetadataToFile(const string &filePath, const FileAsset &fileAsset)
708 {
709     json jsonMetadata;
710     AddMetadataToJson(jsonMetadata, fileAsset);
711     if (!WriteJsonFile(filePath, jsonMetadata)) {
712         MEDIA_ERR_LOG("WriteJsonFile failed");
713         return E_FILE_OPER_FAIL;
714     }
715     return E_OK;
716 }
717 
AddMetadataToJson(nlohmann::json & j,const FileAsset & fileAsset)718 void MediaLibraryMetaRecovery::AddMetadataToJson(nlohmann::json &j, const FileAsset &fileAsset)
719 {
720     const std::unordered_map<std::string, ResultSetDataType> &columnInfoMap = GetRecoveryPhotosTableColumnInfo();
721     if (columnInfoMap.empty()) {
722         MEDIA_ERR_LOG("GetRecoveryPhotosTableColumnInfo failed");
723         return;
724     }
725 
726     for (const auto &[key, type] : columnInfoMap) {
727         if (type == TYPE_STRING) {
728             string value = fileAsset.GetStrMember(key);
729             MEDIA_DEBUG_LOG("Writejson string: %{private}s: %{private}s", key.c_str(), value.c_str());
730             j[key] = json::string_t(value);
731         } else if (type == TYPE_INT32) {
732             int32_t value = fileAsset.GetInt32Member(key);
733             MEDIA_DEBUG_LOG("Writejson int32_t: %{private}s: %{public}d", key.c_str(), value);
734             j[key] = json::number_integer_t(value);
735         } else if (type == TYPE_INT64) {
736             int64_t value = fileAsset.GetInt64Member(key);
737             j[key] = json::number_integer_t(value);
738         } else if (type == TYPE_DOUBLE) {
739             double value = fileAsset.GetDoubleMember(key);
740             MEDIA_DEBUG_LOG("Writejson double: %{private}s: %{public}f", key.c_str(), value);
741             j[key] = json::number_float_t(value);
742         } else {
743             MEDIA_ERR_LOG("WriteFile: error type: %{public}d", type);
744         }
745     }
746 }
747 
GetMetadataFromJson(const nlohmann::json & j,FileAsset & fileAsset)748 bool MediaLibraryMetaRecovery::GetMetadataFromJson(const nlohmann::json &j, FileAsset &fileAsset)
749 {
750     const std::unordered_map<std::string, ResultSetDataType> &columnInfoMap = GetRecoveryPhotosTableColumnInfo();
751     if (columnInfoMap.empty()) {
752         MEDIA_ERR_LOG("GetRecoveryPhotosTableColumnInfo failed");
753         return false;
754     }
755 
756     bool ret = true;
757     for (const auto &[name, type] : columnInfoMap) {
758         if (type == TYPE_STRING) {
759             optional<string> value = GetStringFromJson(j, name);
760             if (value.has_value()) {
761                 fileAsset.SetMemberValue(name, value.value());
762             } else {
763                 ret = false;
764             }
765         } else if (type == TYPE_INT32) {
766             optional<int64_t> value = GetNumberFromJson(j, name);
767             if (value.has_value()) {
768                 fileAsset.SetMemberValue(name, (int32_t)value.value());
769             } else {
770                 ret = false;
771             }
772         } else if (type == TYPE_INT64) {
773             optional<int64_t> value = GetNumberFromJson(j, name);
774             if (value.has_value()) {
775                 fileAsset.SetMemberValue(name, (int64_t)value.value());
776             } else {
777                 ret = false;
778             }
779         } else if (type == TYPE_DOUBLE) {
780             optional<double> value = GetDoubleFromJson(j, name);
781             if (value.has_value()) {
782                 fileAsset.SetMemberValue(name, (double)value.value());
783             } else {
784                 ret = false;
785             }
786         } else {
787             MEDIA_ERR_LOG("ReadFile: error %{public}d", type);
788         }
789     }
790 
791     return ret;
792 }
793 
ReadMetadataFromFile(const string & filePath,FileAsset & fileAsset)794 int32_t MediaLibraryMetaRecovery::ReadMetadataFromFile(const string &filePath, FileAsset &fileAsset)
795 {
796     int ret = E_OK;
797     json jsonMetadata;
798     if (!ReadJsonFile(filePath, jsonMetadata)) {
799         MEDIA_ERR_LOG("ReadJsonFile failed");
800         return E_FILE_OPER_FAIL;
801     }
802 
803     if (!GetMetadataFromJson(jsonMetadata, fileAsset)) {
804         MEDIA_ERR_LOG("GetMetadataFromJson not all right");
805     }
806 
807     // Meida file path
808     string mediaFilePath = filePath;
809     size_t pos = mediaFilePath.find(META_RECOVERY_META_RELATIVE_PATH);
810     if (pos != string::npos) {
811         mediaFilePath.replace(pos, META_RECOVERY_META_RELATIVE_PATH.length(), META_RECOVERY_PHOTO_RELATIVE_PATH);
812     }
813     if (MediaFileUtils::EndsWith(mediaFilePath, META_RECOVERY_META_FILE_SUFFIX)) {
814         mediaFilePath.erase(mediaFilePath.length() - META_RECOVERY_META_FILE_SUFFIX.length());
815     }
816     fileAsset.SetFilePath(mediaFilePath);
817 
818     struct stat statInfo = { 0 };
819     if (stat(mediaFilePath.c_str(), &statInfo) != 0) {
820         MEDIA_ERR_LOG("ReadMetadataFromFile: stat syscall err %{public}d", errno);
821         ret = E_SYSCALL;
822         if (errno == ENOENT) {
823             remove(filePath.c_str());
824         }
825     }
826 
827     return ret;
828 }
829 
AddPhotoAlbumToJson(nlohmann::json & j,const PhotoAlbum & photoAlbum)830 void MediaLibraryMetaRecovery::AddPhotoAlbumToJson(nlohmann::json &j, const PhotoAlbum &photoAlbum)
831 {
832     j = json {
833         {PhotoAlbumColumns::ALBUM_ID, json::number_integer_t(photoAlbum.GetAlbumId())},
834         {PhotoAlbumColumns::ALBUM_TYPE, json::number_integer_t(photoAlbum.GetPhotoAlbumType())},
835         {PhotoAlbumColumns::ALBUM_SUBTYPE, json::number_integer_t(photoAlbum.GetPhotoAlbumSubType())},
836         {PhotoAlbumColumns::ALBUM_NAME, json::string_t(photoAlbum.GetAlbumName())},
837         {PhotoAlbumColumns::ALBUM_DATE_MODIFIED, json::number_integer_t(photoAlbum.GetDateModified())},
838         {PhotoAlbumColumns::CONTAINS_HIDDEN, json::number_integer_t(photoAlbum.GetContainsHidden())},
839         {PhotoAlbumColumns::ALBUM_ORDER, json::number_integer_t(photoAlbum.GetOrder())},
840         {PhotoAlbumColumns::ALBUM_BUNDLE_NAME, json::string_t(photoAlbum.GetBundleName())},
841         {PhotoAlbumColumns::ALBUM_LOCAL_LANGUAGE, json::string_t(photoAlbum.GetLocalLanguage())},
842         {PhotoAlbumColumns::ALBUM_DATE_ADDED, json::number_integer_t(photoAlbum.GetDateAdded())},
843         {PhotoAlbumColumns::ALBUM_IS_LOCAL, json::number_integer_t(photoAlbum.GetIsLocal())},
844         {PhotoAlbumColumns::ALBUM_LPATH, json::string_t(photoAlbum.GetLPath())},
845         {PhotoAlbumColumns::ALBUM_PRIORITY, json::number_integer_t(photoAlbum.GetPriority())}
846     };
847 }
848 
GetPhotoAlbumFromJson(const nlohmann::json & j,PhotoAlbum & photoAlbum)849 bool MediaLibraryMetaRecovery::GetPhotoAlbumFromJson(const nlohmann::json &j, PhotoAlbum &photoAlbum)
850 {
851     bool ret = true;
852     optional<int64_t> albumId = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_ID);
853     if (albumId.has_value()) {
854         photoAlbum.SetAlbumId((int32_t)albumId.value());
855     } else {
856         ret = false;
857     }
858 
859     optional<int64_t> albumType = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_TYPE);
860     if (albumType.has_value()) {
861         int32_t type = (int32_t)albumType.value();
862         photoAlbum.SetPhotoAlbumType(static_cast<PhotoAlbumType>(type));
863     } else {
864         ret = false;
865     }
866 
867     optional<int64_t> albumSubType = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_SUBTYPE);
868     if (albumSubType.has_value()) {
869         int32_t type = (int32_t)albumSubType.value();
870         photoAlbum.SetPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(type));
871     } else {
872         ret = false;
873     }
874 
875     optional<string> albumName = GetStringFromJson(j, PhotoAlbumColumns::ALBUM_NAME);
876     if (albumName.has_value()) {
877         photoAlbum.SetAlbumName(albumName.value());
878     } else {
879         ret = false;
880     }
881 
882     optional<int64_t> dateModified = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
883     if (dateModified.has_value()) {
884         photoAlbum.SetDateModified(dateModified.value());
885     } else {
886         ret = false;
887     }
888 
889     optional<int64_t> containsHidden = GetNumberFromJson(j, PhotoAlbumColumns::CONTAINS_HIDDEN);
890     if (containsHidden.has_value()) {
891         photoAlbum.SetContainsHidden((int32_t)containsHidden.value());
892     } else {
893         ret = false;
894     }
895 
896     optional<int64_t> order = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_ORDER);
897     if (order.has_value()) {
898         photoAlbum.SetOrder((int32_t)order.value());
899     } else {
900         ret = false;
901     }
902 
903     return (ret && GetPhotoAlbumFromJsonPart1(j, photoAlbum));
904     // !! Do not add upgrade code here !!
905 }
906 
WritePhotoAlbumToFile(const string & filePath,const vector<shared_ptr<PhotoAlbum>> & vecPhotoAlbum)907 int32_t MediaLibraryMetaRecovery::WritePhotoAlbumToFile(const string &filePath,
908                                                         const vector<shared_ptr<PhotoAlbum>> &vecPhotoAlbum)
909 {
910     MEDIA_DEBUG_LOG("WritePhotoAlbumToFile start\n");
911 
912     const string parentDir = MediaFileUtils::GetParentPath(filePath);
913     if (!MediaFileUtils::CreateDirectory(parentDir)) {
914         MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
915         return false;
916     }
917 
918     json jsonArray = json::array();
919     for (auto &album : vecPhotoAlbum) {
920         if (album == nullptr) {
921             MEDIA_ERR_LOG("album == nullptr");
922             continue;
923         }
924 
925         json jsonPhotoAlbumItem;
926         OHOS::Media::PhotoAlbum &photoAlbumRef = *album.get();
927         AddPhotoAlbumToJson(jsonPhotoAlbumItem, photoAlbumRef);
928 
929         jsonArray.push_back(jsonPhotoAlbumItem);
930     }
931 
932     if (!WriteJsonFile(filePath, jsonArray)) {
933         MEDIA_ERR_LOG("WriteJsonFile failed");
934         return E_FILE_OPER_FAIL;
935     }
936 
937     MEDIA_DEBUG_LOG("WritePhotoAlbumToFile end\n");
938     return E_OK;
939 }
940 
ReadPhotoAlbumFromFile(const string & filePath,vector<shared_ptr<PhotoAlbum>> & photoAlbumVector)941 int32_t MediaLibraryMetaRecovery::ReadPhotoAlbumFromFile(const string &filePath,
942                                                          vector<shared_ptr<PhotoAlbum>> &photoAlbumVector)
943 {
944     json jsonArray;
945     if (!ReadJsonFile(filePath, jsonArray)) {
946         MEDIA_ERR_LOG("ReadJsonFile failed");
947         return E_FILE_OPER_FAIL;
948     }
949     if (!jsonArray.is_array()) {
950         MEDIA_ERR_LOG("json not is array");
951         return E_ERR;
952     }
953 
954     int ret = E_OK;
955     for (const json &j : jsonArray) {
956         PhotoAlbum photoAlbum;
957         if (!GetPhotoAlbumFromJson(j, photoAlbum)) {
958             MEDIA_WARN_LOG("GetPhotoAlbumFromJson failed");
959             ret = E_ERR;
960         }
961         if (photoAlbum.GetPhotoAlbumSubType() != 1 && photoAlbum.GetLPath() == "") {
962             continue;
963         }
964         photoAlbumVector.emplace_back(make_shared<PhotoAlbum>(photoAlbum));
965     }
966 
967     return ret;
968 }
969 
WriteMetaStatusToFile(const string & keyPath,const int32_t status)970 int32_t MediaLibraryMetaRecovery::WriteMetaStatusToFile(const string &keyPath, const int32_t status)
971 {
972     json j;
973     if (!ReadJsonFile(META_STATUS_PATH, j)) {
974         MEDIA_WARN_LOG("ReadFile META_STATUS_PATH failed, will write new META_STATUS_PATH file");
975         j = json::object();
976     }
977 
978     j[keyPath] = json::number_integer_t(status);
979 
980     if (!WriteJsonFile(META_STATUS_PATH, j)) {
981         MEDIA_ERR_LOG("WriteJsonFile failed");
982         return E_FILE_OPER_FAIL;
983     }
984 
985     return E_OK;
986 }
987 
ReadMetaStatusFromFile(set<int32_t> & status)988 int32_t MediaLibraryMetaRecovery::ReadMetaStatusFromFile(set<int32_t> &status)
989 {
990     json j;
991     if (!ReadJsonFile(META_STATUS_PATH, j)) {
992         MEDIA_ERR_LOG("ReadFile META_STATUS_PATH failed");
993         return E_FILE_OPER_FAIL;
994     }
995 
996     for (const auto& [key, value] : j.items()) {
997         if (!value.is_number_integer()) {
998             MEDIA_ERR_LOG("key: %{public}s not is number", key.c_str());
999             continue;
1000         }
1001         // Read bucket_id which finish recovery
1002         int32_t val = atoi(key.c_str());
1003         MEDIA_INFO_LOG("finish recovery bucket_id: %{public}s", key.c_str());
1004         status.insert(val);
1005     }
1006 
1007     return E_OK;
1008 }
1009 
ReadMetaRecoveryCountFromFile()1010 int32_t MediaLibraryMetaRecovery::ReadMetaRecoveryCountFromFile()
1011 {
1012     json j;
1013     int32_t recoverySuccessCnt = 0;
1014 
1015     if (!ReadJsonFile(META_STATUS_PATH, j)) {
1016         MEDIA_ERR_LOG("ReadFile META_STATUS_PATH failed");
1017         return E_FILE_OPER_FAIL;
1018     }
1019 
1020     for (const auto& [key, value] : j.items()) {
1021         if (!value.is_number_integer()) {
1022             MEDIA_ERR_LOG("key: %{public}s not is number", key.c_str());
1023             continue;
1024         }
1025         int32_t val = value.get<int32_t>();
1026         recoverySuccessCnt += val;
1027         MEDIA_INFO_LOG("finish recovery bucket_id: %{public}s, recovery success count=%{public}d", key.c_str(), val);
1028     }
1029 
1030     return recoverySuccessCnt;
1031 }
1032 
UpdatePhotoOwnerAlbumId(NativeRdb::ValuesBucket & values)1033 bool MediaLibraryMetaRecovery::UpdatePhotoOwnerAlbumId(NativeRdb::ValuesBucket &values)
1034 {
1035     NativeRdb::ValueObject valueObject;
1036     if (!values.GetObject(PhotoColumn::PHOTO_OWNER_ALBUM_ID, valueObject)) {
1037         return false;
1038     }
1039 
1040     int32_t oldOwnerAlbumId = 0;
1041     valueObject.GetInt(oldOwnerAlbumId);
1042     if (oldAlbumIdToLpath.find(oldOwnerAlbumId) == oldAlbumIdToLpath.end()) {
1043         return false;
1044     }
1045 
1046     const std::string &lpath = oldAlbumIdToLpath[oldOwnerAlbumId];
1047     if (lpathToNewAlbumId.end() == lpathToNewAlbumId.find(lpath)) {
1048         return false;
1049     }
1050 
1051     int32_t newOwnerAlbumId = lpathToNewAlbumId[lpath];
1052     if (newOwnerAlbumId == oldOwnerAlbumId) {
1053         return false;
1054     }
1055 
1056     MEDIA_DEBUG_LOG("convert album %{public}d to %{public}d", oldOwnerAlbumId, newOwnerAlbumId);
1057     values.Delete(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
1058     values.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, newOwnerAlbumId);
1059 
1060     return true;
1061 }
1062 
InsertMetadataInDbRetry(const FileAsset & fileAsset)1063 int32_t MediaLibraryMetaRecovery::InsertMetadataInDbRetry(const FileAsset &fileAsset)
1064 {
1065     int32_t retry_cnt = 0;
1066     do {
1067         if (InsertMetadataInDb(fileAsset) == E_OK) {
1068             break;
1069         }
1070 
1071         retry_cnt++;
1072         MEDIA_ERR_LOG("InsertMetadataInDb failed, retry_cnt = %{public}d", retry_cnt);
1073         this_thread::sleep_for(chrono::milliseconds(META_RETRY_INTERVAL));
1074     } while (retry_cnt < META_RETRY_MAX_COUNTS);
1075 
1076     if (retry_cnt >= META_RETRY_MAX_COUNTS) {
1077         MEDIA_ERR_LOG("InsertMetadataInDb finally failed, retry_cnt = %{public}d", retry_cnt);
1078         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_DB_FAIL},
1079             {KEY_OPT_TYPE, OptType::CREATE}};
1080         PostEventUtils::GetInstance().PostErrorProcess(ErrType::RECOVERY_ERR, map);
1081         return ERR_FAIL;
1082     }
1083 
1084     return E_OK;
1085 }
1086 
InsertMetadataInDb(const FileAsset & fileAsset)1087 int32_t MediaLibraryMetaRecovery::InsertMetadataInDb(const FileAsset &fileAsset)
1088 {
1089     std::string filePath = fileAsset.GetFilePath();
1090     MEDIA_DEBUG_LOG("InsertMetadataInDb: photo filepath = %{public}s", DfxUtils::GetSafePath(filePath).c_str());
1091     if (MediaLibraryAssetOperations::CheckExist(filePath) == E_OK) {
1092         MEDIA_DEBUG_LOG("InsertMetadataInDb: insert: photo is exist in db, ignore");
1093         return E_OK;
1094     }
1095 
1096     const std::unordered_map<std::string, ResultSetDataType> &columnInfoMap = GetRecoveryPhotosTableColumnInfo();
1097     if (columnInfoMap.empty()) {
1098         MEDIA_ERR_LOG("GetRecoveryPhotosTableColumnInfo failed");
1099         return E_ERR;
1100     }
1101 
1102     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1103     if (rdbStore == nullptr) {
1104         MEDIA_ERR_LOG("GetRdbStore failed, return nullptr");
1105         return E_HAS_DB_ERROR;
1106     }
1107 
1108     NativeRdb::ValuesBucket valuesBucket;
1109     SetValuesFromFileAsset(fileAsset, valuesBucket, columnInfoMap);
1110 
1111     // set meta flags uptodate, to avoid backup db into meta again
1112     if (UpdatePhotoOwnerAlbumId(valuesBucket)) {
1113         valuesBucket.PutInt(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_DIRTY));
1114     } else {
1115         valuesBucket.PutInt(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_UPTODATE));
1116     }
1117 
1118     int64_t outRowId = -1;
1119     int32_t errCode = rdbStore->Insert(outRowId, PhotoColumn::PHOTOS_TABLE, valuesBucket);
1120     if (errCode != NativeRdb::E_OK) {
1121         MEDIA_ERR_LOG("Insert photo failed, errCode = %{public}d", errCode);
1122         return errCode;
1123     }
1124 
1125     return E_OK;
1126 }
1127 
InsertMetadataInDb(const std::vector<shared_ptr<PhotoAlbum>> & vecPhotoAlbum)1128 int32_t MediaLibraryMetaRecovery::InsertMetadataInDb(const std::vector<shared_ptr<PhotoAlbum>> &vecPhotoAlbum)
1129 {
1130     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1131     if (rdbStore == nullptr) {
1132         MEDIA_ERR_LOG("GetRdbStore failed, return nullptr)");
1133         return E_HAS_DB_ERROR;
1134     }
1135 
1136     for (auto iter : vecPhotoAlbum) {
1137         MEDIA_INFO_LOG("InsertMetadataInDb: album name = %{private}s", iter->GetAlbumName().c_str());
1138         NativeRdb::RdbPredicates predicates(PhotoAlbumColumns::TABLE);
1139         vector<string> columns = {PhotoAlbumColumns::ALBUM_ID,
1140             PhotoAlbumColumns::ALBUM_LPATH};
1141         predicates.IsNotNull(PhotoAlbumColumns::ALBUM_LPATH)->And()->EqualTo(PhotoAlbumColumns::ALBUM_LPATH,
1142                              iter->GetLPath());
1143         auto resultSet = MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
1144         if (resultSet == nullptr) {
1145             MEDIA_ERR_LOG("resultSet == nullptr)");
1146             continue;
1147         }
1148         if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1149             MEDIA_ERR_LOG("skip duplicate lpath %{public}s", iter->GetLPath().c_str());
1150             continue;
1151         }
1152         std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
1153         int32_t errCode = NativeRdb::E_OK;
1154         std::function<int(void)> func = [&]()->int {
1155             // Insert album item
1156             NativeRdb::ValuesBucket valuesBucket;
1157             SetValuesFromPhotoAlbum(iter, valuesBucket);
1158             int64_t outRowId = -1;
1159             errCode = trans->Insert(outRowId, PhotoColumn::PHOTOS_TABLE, valuesBucket);
1160             if (errCode != NativeRdb::E_OK) {
1161                 MEDIA_ERR_LOG("InsertMetadataInDb: insert album failed, errCode = %{public}d", errCode);
1162                 return errCode;
1163             }
1164 
1165             // Update album order inserted just now
1166             int32_t changedRows = -1;
1167             NativeRdb::RdbPredicates predicatesOrder(PhotoAlbumColumns::TABLE);
1168             predicatesOrder.And()->EqualTo(PhotoAlbumColumns::ALBUM_ID, outRowId)
1169                                  ->And()
1170                                  ->NotEqualTo(PhotoAlbumColumns::ALBUM_ORDER, iter->GetOrder());
1171             valuesBucket.Clear();
1172             valuesBucket.PutInt(PhotoAlbumColumns::ALBUM_ORDER, iter->GetOrder());
1173             errCode = trans->Update(changedRows, valuesBucket, predicatesOrder);
1174             if (errCode != E_OK) {
1175                 MEDIA_ERR_LOG("Update album order failed, err = %{public}d", errCode);
1176                 return E_HAS_DB_ERROR;
1177             }
1178             if (changedRows > 0) {
1179                 MEDIA_INFO_LOG("Update album order");
1180             }
1181             return errCode;
1182         };
1183         errCode = trans->RetryTrans(func);
1184         if (errCode != E_OK) {
1185             MEDIA_ERR_LOG("InsertMetadataInDb: trans retry fail!, ret:%{public}d", errCode);
1186             return errCode;
1187         }
1188     }
1189 
1190     return E_OK;
1191 }
1192 
UpdateMetadataFlagInDb(const int32_t fieldId,const MetadataFlags & flag)1193 int32_t MediaLibraryMetaRecovery::UpdateMetadataFlagInDb(const int32_t fieldId, const MetadataFlags &flag)
1194 {
1195     int32_t errCode = E_OK;
1196 
1197     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1198     if (!rdbStore) {
1199         MEDIA_ERR_LOG("GetRdbStore failed");
1200         return E_HAS_DB_ERROR;
1201     }
1202 
1203     NativeRdb::RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
1204     predicates.EqualTo(MediaColumn::MEDIA_ID, fieldId);
1205 
1206     NativeRdb::ValuesBucket values;
1207     values.PutInt(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(flag));
1208 
1209     int32_t changedRows = -1;
1210     errCode = rdbStore->Update(changedRows, values, predicates);
1211     if (errCode != E_OK) {
1212         MEDIA_ERR_LOG("Database update failed, err = %{public}d", errCode);
1213         return E_HAS_DB_ERROR;
1214     }
1215     return E_OK;
1216 }
1217 
SetRdbRebuiltStatus(bool status)1218 int32_t MediaLibraryMetaRecovery::SetRdbRebuiltStatus(bool status)
1219 {
1220     rdbRebuilt_ = status;
1221     reBuiltCount_++;
1222     return E_OK;
1223 }
1224 
StartAsyncRecovery()1225 int32_t MediaLibraryMetaRecovery::StartAsyncRecovery()
1226 {
1227     StatisticRestore();
1228 
1229     MediaLibraryMetaRecoveryState oldState = recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_RECOVERING);
1230     if (oldState == MediaLibraryMetaRecoveryState::STATE_RECOVERING) {
1231         MEDIA_INFO_LOG("recovery process is already running");
1232         return E_OK;
1233     }
1234 
1235     if (oldState == MediaLibraryMetaRecoveryState::STATE_NONE) {
1236         bool hasStatusFile = bool(access(META_STATUS_PATH.c_str(), F_OK) == E_OK);
1237         MEDIA_INFO_LOG("rebuild status %{public}d, has status file %{public}d", rdbRebuilt_, hasStatusFile);
1238         if (!hasStatusFile && !rdbRebuilt_) {
1239             MEDIA_INFO_LOG("StartAsyncRecovery: no need to recovery");
1240             recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_NONE);
1241             return E_OK;
1242         }
1243         oldState = hasStatusFile ? MediaLibraryMetaRecoveryState::STATE_RECOVERING_ABORT :
1244                                     MediaLibraryMetaRecoveryState::STATE_NONE;
1245     }
1246 
1247     if (oldState == MediaLibraryMetaRecoveryState::STATE_RECOVERING_ABORT) {
1248         ReadMetaStatusFromFile(metaStatus);
1249     } else {
1250         // Create status.json if not exist
1251         const string parentDir = MediaFileUtils::GetParentPath(META_STATUS_PATH);
1252         if (MediaFileUtils::CreateDirectory(parentDir)) {
1253             MediaFileUtils::CreateFile(META_STATUS_PATH);
1254         } else {
1255             MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
1256         }
1257     }
1258 
1259     std::thread([this]() {
1260         MEDIA_INFO_LOG("Start recovery");
1261         int64_t recoveryStartTime = MediaFileUtils::UTCTimeMilliSeconds();
1262         this->DoDataBaseRecovery();
1263         int64_t recoveryTotalTime = MediaFileUtils::UTCTimeMilliSeconds() - recoveryStartTime;
1264         bool isStatusFileExist = bool(access(META_STATUS_PATH.c_str(), F_OK) == E_OK);
1265         if (isStatusFileExist) {
1266             recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_RECOVERING_ABORT);
1267         } else {
1268             recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_NONE);
1269         }
1270         recoveryCostTime_ += recoveryTotalTime;
1271     }).detach();
1272 
1273     return E_OK;
1274 }
1275 
DeleteMetaDataByPath(const string & filePath)1276 int32_t MediaLibraryMetaRecovery::DeleteMetaDataByPath(const string &filePath)
1277 {
1278     string metaFilePath;
1279     if (PhotoFileUtils::GetMetaPathFromOrignalPath(filePath, metaFilePath) != E_OK) {
1280         MEDIA_ERR_LOG("DeleteMetaDataByPath: invalid photo filePath, %{public}s",
1281             DfxUtils::GetSafePath(filePath).c_str());
1282         return E_INVALID_PATH;
1283     }
1284 
1285     if (remove(metaFilePath.c_str()) != 0 && errno != ENOENT) {
1286         MEDIA_ERR_LOG("remove metafile failed %{public}d, path %s", errno, DfxUtils::GetSafePath(metaFilePath).c_str());
1287     }
1288 
1289     MEDIA_INFO_LOG("DeleteMetaDataByPath: metafile removed successful, %{public}s",
1290         DfxUtils::GetSafePath(metaFilePath).c_str());
1291     return E_OK;
1292 }
1293 
StopCloudSync()1294 void MediaLibraryMetaRecovery::StopCloudSync()
1295 {
1296     MEDIA_INFO_LOG("Begin StopCloudSync");
1297     FileManagement::CloudSync::CloudSyncManager::GetInstance().StopSync(BUNDLE_NAME, true);
1298 }
1299 
RestartCloudSync()1300 void MediaLibraryMetaRecovery::RestartCloudSync()
1301 {
1302     MEDIA_INFO_LOG("Begin reset cloud cursor");
1303     static uint32_t baseUserRange = 200000; // uid base offset
1304     uid_t uid = getuid() / baseUserRange;
1305     FileManagement::CloudSync::CloudSyncManager::GetInstance().ResetCursor();
1306 
1307     int32_t ret = FileManagement::CloudSync::CloudSyncManager::GetInstance().StartSync(BUNDLE_NAME);
1308     if (ret != 0) {
1309         MEDIA_ERR_LOG("StartCloudSync fail, errcode=%{public}d", ret);
1310     }
1311     MEDIA_INFO_LOG("End StartCloudSync");
1312 }
1313 
GetDataType(const std::string & name)1314 ResultSetDataType MediaLibraryMetaRecovery::GetDataType(const std::string &name)
1315 {
1316     auto it = FILEASSET_MEMBER_MAP.find(name);
1317     if (it == FILEASSET_MEMBER_MAP.end()) {
1318         MEDIA_ERR_LOG("FILEASSET_MEMBER_MAP not find name: %{public}s", name.c_str());
1319         return TYPE_NULL;
1320     }
1321 
1322     switch (it->second) {
1323         case MEMBER_TYPE_INT32: {
1324             return TYPE_INT32;
1325             break;
1326         }
1327         case MEMBER_TYPE_INT64: {
1328             return TYPE_INT64;
1329             break;
1330         }
1331         case MEMBER_TYPE_STRING: {
1332             return TYPE_STRING;
1333             break;
1334         }
1335         case MEMBER_TYPE_DOUBLE: {
1336             return TYPE_DOUBLE;
1337             break;
1338         }
1339         default: {
1340             return TYPE_NULL;
1341             break;
1342         }
1343     }
1344 }
1345 
GetRecoveryPhotosTableColumnInfo()1346 const std::unordered_map<std::string, ResultSetDataType> &MediaLibraryMetaRecovery::GetRecoveryPhotosTableColumnInfo()
1347 {
1348     MEDIA_DEBUG_LOG("GetRecoveryPhotosTableColumnInfo");
1349     static std::unordered_map<std::string, ResultSetDataType> RECOVERY_PHOTOS_TABLE_COLUMN
1350         = QueryRecoveryPhotosTableColumnInfo();
1351     if (RECOVERY_PHOTOS_TABLE_COLUMN.empty()) {
1352         MEDIA_ERR_LOG("QueryRecoveryPhotosTableColumnInfo failed");
1353         RECOVERY_PHOTOS_TABLE_COLUMN = QueryRecoveryPhotosTableColumnInfo();
1354     }
1355 
1356     return  RECOVERY_PHOTOS_TABLE_COLUMN;
1357 }
1358 
QueryRecoveryPhotosTableColumnInfo()1359 std::unordered_map<std::string, ResultSetDataType> MediaLibraryMetaRecovery::QueryRecoveryPhotosTableColumnInfo()
1360 {
1361     MEDIA_DEBUG_LOG("QueryRecoveryPhotosTableColumnInfo");
1362     std::unordered_map<std::string, ResultSetDataType> columnInfoMap;
1363     const std::vector<std::string> &columnInfo = MediaLibraryAssetOperations::GetPhotosTableColumnInfo();
1364     if (columnInfo.empty()) {
1365         MEDIA_ERR_LOG("GetPhotosTableColumnInfo failed");
1366         return columnInfoMap;
1367     }
1368 
1369     for (const std::string &name : columnInfo) {
1370         if (EXCLUDED_COLUMNS.count(name) > 0) {
1371             continue;
1372         }
1373         ResultSetDataType type = GetDataType(name);
1374         columnInfoMap.emplace(name, type);
1375         MEDIA_DEBUG_LOG("photos table name: %{public}s, type: %{public}d", name.c_str(), type);
1376     }
1377 
1378     return columnInfoMap;
1379 }
1380 
ResetAllMetaDirty()1381 int32_t MediaLibraryMetaRecovery::ResetAllMetaDirty()
1382 {
1383     const std::string RESET_ALL_META_DIRTY_SQL =
1384         " UPDATE " + PhotoColumn::PHOTOS_TABLE + " SET " + PhotoColumn::PHOTO_METADATA_FLAGS +
1385         " = 0 " + " WHERE " + PhotoColumn::PHOTO_METADATA_FLAGS + " == 2; END;";
1386 
1387     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1388     if (rdbStore == nullptr) {
1389         return E_HAS_DB_ERROR;
1390     }
1391 
1392     int32_t err = rdbStore->ExecuteSql(RESET_ALL_META_DIRTY_SQL);
1393     if (err != NativeRdb::E_OK) {
1394         MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s", RESET_ALL_META_DIRTY_SQL.c_str());
1395     }
1396     return err;
1397 }
1398 
QueryInt(const NativeRdb::AbsRdbPredicates & predicates,const std::vector<std::string> & columns,const std::string & queryColumn,int32_t & value)1399 static int32_t QueryInt(const NativeRdb::AbsRdbPredicates &predicates,
1400     const std::vector<std::string> &columns, const std::string &queryColumn, int32_t &value)
1401 {
1402     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
1403     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1404         return E_DB_FAIL;
1405     }
1406     value = GetInt32Val(queryColumn, resultSet);
1407     return E_OK;
1408 }
1409 
QueryAllPhoto(bool backup)1410 static int32_t QueryAllPhoto(bool backup)
1411 {
1412     NativeRdb::RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
1413     predicates.And()->BeginWrap()->EqualTo(PhotoColumn::PHOTO_POSITION, "1")->Or()
1414         ->EqualTo(PhotoColumn::PHOTO_POSITION, "3")->EndWrap();
1415 
1416     if (backup) {
1417         predicates.BeginWrap()
1418                   ->EqualTo(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_NEW))
1419                   ->Or()
1420                   ->EqualTo(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_DIRTY))
1421                   ->Or()
1422                   ->IsNull(PhotoColumn::PHOTO_METADATA_FLAGS)
1423                   ->EndWrap();
1424     }
1425 
1426     std::vector<std::string> columns = { "count(1) AS count" };
1427     std::string queryColumn = "count";
1428     int32_t count;
1429     int32_t errCode = QueryInt(predicates, columns, queryColumn, count);
1430     if (errCode != E_OK) {
1431         MEDIA_ERR_LOG("query local image fail: %{public}d", errCode);
1432     }
1433     return count;
1434 }
1435 
StatisticSave()1436 void MediaLibraryMetaRecovery::StatisticSave()
1437 {
1438     int32_t errCode;
1439     shared_ptr<NativePreferences::Preferences> prefs =
1440         NativePreferences::PreferencesHelper::GetPreferences(RDB_CONFIG, errCode);
1441     if (!prefs) {
1442         MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
1443         return;
1444     }
1445     prefs->PutLong(BACKUP_PHOTO_COUNT, backupSuccCnt_);
1446     prefs->PutLong(BACKUP_COST_TIME, backupCostTime_);
1447     prefs->PutLong(REBUILT_COUNT, reBuiltCount_);
1448     prefs->PutLong(RECOVERY_BACKUP_TOTAL_COUNT, recoveryTotalBackupCnt_);
1449     prefs->PutLong(RECOVERY_SUCC_PHOTO_COUNT, recoverySuccCnt_);
1450     prefs->PutLong(RECOVERY_COST_TIME, recoveryCostTime_);
1451     prefs->FlushSync();
1452 }
1453 
StatisticRestore()1454 void MediaLibraryMetaRecovery::StatisticRestore()
1455 {
1456     int32_t errCode;
1457     shared_ptr<NativePreferences::Preferences> prefs =
1458         NativePreferences::PreferencesHelper::GetPreferences(RDB_CONFIG, errCode);
1459     if (!prefs) {
1460         MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
1461         return;
1462     }
1463     backupSuccCnt_ = prefs->GetLong(BACKUP_PHOTO_COUNT, 0);
1464     backupCostTime_ = prefs->GetLong(BACKUP_COST_TIME, 0);
1465     reBuiltCount_ += prefs->GetLong(REBUILT_COUNT, 0);  // reBuiltCount_ will be set before Restore
1466     recoveryTotalBackupCnt_ = prefs->GetLong(RECOVERY_BACKUP_TOTAL_COUNT, 0);
1467     recoverySuccCnt_ = prefs->GetLong(RECOVERY_SUCC_PHOTO_COUNT, 0);
1468     recoveryCostTime_ = prefs->GetLong(RECOVERY_COST_TIME, 0);
1469 }
1470 
StatisticReset()1471 void MediaLibraryMetaRecovery::StatisticReset()
1472 {
1473     backupSuccCnt_ = 0;
1474     reBuiltCount_ = 0;
1475     backupCostTime_ = 0;
1476     recoverySuccCnt_ = 0;
1477     recoveryCostTime_ = 0;
1478     recoveryTotalBackupCnt_ = 0;
1479     StatisticSave();
1480 }
1481 
RecoveryStatistic()1482 void MediaLibraryMetaRecovery::RecoveryStatistic()
1483 {
1484     static constexpr char MEDIA_LIBRARY[] = "MEDIALIBRARY";
1485     int64_t totalPhotoCount = QueryAllPhoto(false);
1486     int64_t totalbackupCount = GetTotalBackupFileCount();
1487     int ret = HiSysEventWrite(
1488         MEDIA_LIBRARY,
1489         "MEDIALIB_META_RECOVERY_INFO",
1490         HiviewDFX::HiSysEvent::EventType::STATISTIC,
1491         "TOTAL_PHOTO_COUNT", totalPhotoCount,
1492         "TOTAL_BACKUP_COUNT", totalbackupCount,
1493         "BACKUP_PHOTO_COUNT", backupSuccCnt_,
1494         "BACKUP_COST_TIME", backupCostTime_,
1495         "REBUILT_COUNT", reBuiltCount_,
1496         "RECOVERY_BACKUP_TOTAL_COUNT", recoveryTotalBackupCnt_,
1497         "RECOVERY_SUCC_PHOTO_COUNT", recoverySuccCnt_,
1498         "RECOVERY_COST_TIME", recoveryCostTime_);
1499     if (ret != 0) {
1500         MEDIA_ERR_LOG("RecoveryStatistic error:%{public}d", ret);
1501     }
1502     StatisticReset();
1503 }
1504 } // namespace Media
1505 } // namespace OHOS
1506