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