• 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         CHECK_AND_BREAK_ERR_LOG(ret == E_OK,
359             "file is not exist or no read access, path=%{public}s", DfxUtils::GetSafePath(path).c_str());
360 
361         ret = ReadPhotoAlbumFromFile(path, vecPhotoAlbum);
362         CHECK_AND_BREAK_ERR_LOG(ret == E_OK, "read album file failed, errCode = %{public}d", ret);
363 
364         ret = InsertMetadataInDb(vecPhotoAlbum);
365         CHECK_AND_BREAK_ERR_LOG(ret == E_OK, "AlbumRecovery: insert album failed, errCode = %{public}d", ret);
366         MEDIA_INFO_LOG("AlbumRecovery: photo album is recovered successful");
367     } while (false);
368 
369     return ret;
370 }
371 
GetTotalBackupFileCount()372 static int32_t GetTotalBackupFileCount()
373 {
374     int count = 0;
375     if (access(META_RECOVERY_META_PATH.c_str(), F_OK) != E_OK) {
376         return count;
377     }
378 
379     filesystem::path dir(META_RECOVERY_META_PATH);
380     for (const auto& entry : filesystem::recursive_directory_iterator(dir)) {
381         if (entry.is_regular_file() && entry.path().extension() == ".json") {
382             ++count;
383         }
384     }
385 
386     return count;
387 }
388 
PhotoRecovery(const string & path)389 int32_t MediaLibraryMetaRecovery::PhotoRecovery(const string &path)
390 {
391     string realPath;
392     int32_t bucket_id = -1;
393 
394     if (!PathToRealPath(path, realPath)) {
395         if (errno == ENOENT) {
396             // Delte Metastatus Json;
397             remove(META_STATUS_PATH.c_str());
398             // Delete status
399             metaStatus.clear();
400             MEDIA_ERR_LOG("no meta file no need to recovery");
401             return E_OK;
402         }
403         MEDIA_ERR_LOG("Failed to get real path %{private}s, errno %{public}d", path.c_str(), errno);
404         return E_INVALID_PATH;
405     }
406 
407     recoveryTotalBackupCnt_ = GetTotalBackupFileCount();
408     MEDIA_INFO_LOG("recovery success total backup");
409 
410     if (!ScannerUtils::IsDirectory(realPath)) {
411         MEDIA_ERR_LOG("The path %{private}s is not a directory", realPath.c_str());
412         return E_INVALID_PATH;
413     }
414 
415     int err = ScanMetaDir(path, bucket_id);
416     if (err != E_OK) {
417         MEDIA_ERR_LOG("Failed to ScanMetaDir, errCode=%{public}d", err);
418     }
419 
420     recoverySuccCnt_ += ReadMetaRecoveryCountFromFile();
421 
422     // Delte Metastatus Json;
423     err = remove(META_STATUS_PATH.c_str());
424     if (err != E_OK) {
425         MEDIA_WARN_LOG("Remove META_STATUS_PATH failed, errCode=%{public}d", err);
426     }
427     // Delete status
428     metaStatus.clear();
429 
430     return err;
431 }
432 
WriteSingleMetaDataById(int32_t rowId)433 int32_t MediaLibraryMetaRecovery::WriteSingleMetaDataById(int32_t rowId)
434 {
435     int ret = E_OK;
436 
437     MEDIA_DEBUG_LOG("WriteSingleMetaDataById : rowId %{public}d", rowId);
438     auto asset = MediaLibraryAssetOperations::QuerySinglePhoto(rowId);
439     CHECK_AND_RETURN_RET_LOG(asset != nullptr, E_HAS_DB_ERROR, "QuerySinglePhoto : rowId %{public}d failed", rowId);
440 
441     ret = WriteSingleMetaData(*asset);
442     if (ret == E_OK) {
443         backupSuccCnt_++;
444     }
445     return ret;
446 }
447 
WriteSingleMetaData(const FileAsset & asset)448 int32_t MediaLibraryMetaRecovery::WriteSingleMetaData(const FileAsset &asset)
449 {
450     string metaFilePath;
451     int32_t ret = E_OK;
452 
453     ret = PhotoFileUtils::GetMetaPathFromOrignalPath(asset.GetPath(), metaFilePath);
454     if (ret != E_OK) {
455         MEDIA_ERR_LOG("invalid photo path, path = %{public}s", DfxUtils::GetSafePath(asset.GetPath()).c_str());
456         return ret;
457     }
458 
459     // Create direcotry
460     const string metaParentPath = MediaFileUtils::GetParentPath(metaFilePath);
461     if (!MediaFileUtils::CreateDirectory(metaParentPath)) {
462         MEDIA_ERR_LOG("photo: CreateDirectory failed, filePath = %{public}s",
463             DfxUtils::GetSafePath(metaParentPath).c_str());
464         return E_HAS_FS_ERROR;
465     }
466 
467     // Create metadata file
468     ret = WriteMetadataToFile(metaFilePath, asset);
469     if (ret != E_OK) {
470         MEDIA_ERR_LOG("photo: WriteMetadataToFile failed, filePath = %{public}s",
471             DfxUtils::GetSafePath(metaFilePath).c_str());
472         return ret;
473     }
474 
475     // Up to date
476     ret = UpdateMetadataFlagInDb(asset.GetId(), MetadataFlags::TYPE_UPTODATE);
477     if (ret != E_OK) {
478         MEDIA_ERR_LOG("photo: Up to date failed, filePath = %{public}s", DfxUtils::GetSafePath(metaFilePath).c_str());
479         return ret;
480     }
481 
482     return ret;
483 }
484 
DoBackupMetadata()485 void MediaLibraryMetaRecovery::DoBackupMetadata()
486 {
487     int32_t temp = 0;
488     int32_t tempLevel = 0;
489     int32_t batteryCapacity = 0;
490 
491 #ifdef HAS_THERMAL_MANAGER_PART
492     auto& thermalMgrClient = PowerMgr::ThermalMgrClient::GetInstance();
493     temp = static_cast<int32_t>(thermalMgrClient.GetThermalSensorTemp(PowerMgr::SensorType::SHELL));
494     tempLevel = static_cast<int32_t>(thermalMgrClient.GetThermalLevel());
495 #endif
496 #ifdef HAS_BATTERY_MANAGER_PART
497     batteryCapacity = PowerMgr::BatterySrvClient::GetInstance().GetCapacity();
498 #endif
499     MEDIA_INFO_LOG("Start backing up, batteryCap = %{public}d, temp = %{public}d(%{public}d)",
500         batteryCapacity, temp, tempLevel);
501 
502     // Backing up photo albums
503     AlbumBackup();
504 
505     // Backing up photos
506     PhotoBackupBatch();
507 }
508 
AlbumBackup()509 void MediaLibraryMetaRecovery::AlbumBackup()
510 {
511     vector<shared_ptr<PhotoAlbum>> photoAlbumVector;
512     MediaLibraryAssetOperations::QueryTotalAlbum(photoAlbumVector);
513     int photoAlbumCount = photoAlbumVector.size();
514     if (photoAlbumCount <= 0) {
515         MEDIA_INFO_LOG("AlbumBackup: no photo albums need to backup");
516         return;
517     }
518 
519     MEDIA_INFO_LOG("AlbumBackup: album count = %{public}d", photoAlbumCount);
520     if (E_OK != WritePhotoAlbumToFile(META_RECOVERY_ALBUM_PATH, photoAlbumVector)) {
521         MEDIA_ERR_LOG("AlbumBackup: WritePhotoAlbumToFile failed");
522     }
523 }
524 
PhotoBackupBatch()525 void MediaLibraryMetaRecovery::PhotoBackupBatch()
526 {
527     int32_t photoTotalCount = 0;
528     int32_t photoProcessedCount = 0;
529     int32_t photoSuccessedCount = 0;
530     vector<shared_ptr<FileAsset>> photoVector;
531     do {
532         if (recoveryState_.load() != MediaLibraryMetaRecoveryState::STATE_BACKING_UP) {
533             MEDIA_INFO_LOG("Photo backing up process is interrupted");
534             break;
535         }
536 
537         photoVector.clear();
538         MediaLibraryAssetOperations::QueryTotalPhoto(photoVector, QUERY_BATCH_SIZE);
539         if (photoVector.size() > 0) {
540             photoTotalCount += photoVector.size();
541             PhotoBackup(photoVector, photoProcessedCount, photoSuccessedCount);
542         }
543     } while (photoVector.size() == QUERY_BATCH_SIZE);
544     MEDIA_INFO_LOG("Photo backup end, result = %{public}d/%{public}d/%{public}d",
545         photoSuccessedCount, photoProcessedCount, photoTotalCount);
546     backupSuccCnt_ += photoSuccessedCount;
547 }
548 
PhotoBackup(const vector<shared_ptr<FileAsset>> & photoVector,int32_t & processCount,int32_t & successCount)549 void MediaLibraryMetaRecovery::PhotoBackup(const vector<shared_ptr<FileAsset>> &photoVector,
550                                            int32_t &processCount,
551                                            int32_t &successCount)
552 {
553     for (auto &asset : photoVector) {
554         // Check interrupt request
555         if (recoveryState_.load() != MediaLibraryMetaRecoveryState::STATE_BACKING_UP) {
556             MEDIA_INFO_LOG("Photo backing up process is interrupted");
557             break;
558         }
559 
560         processCount++;
561 
562         if (!asset) {
563             MEDIA_ERR_LOG("Photo asset pointer is null");
564             continue;
565         }
566 
567         if (E_OK != WriteSingleMetaData(*asset)) {
568             MEDIA_ERR_LOG("WriteSingleMetaData failed");
569             continue;
570         }
571 
572         successCount++;
573     }
574 }
575 
ScanMetaDir(const string & path,int32_t bucket_id)576 int32_t MediaLibraryMetaRecovery::ScanMetaDir(const string &path, int32_t bucket_id)
577 {
578     int err = E_OK;
579     DIR *dirPath = nullptr;
580     struct dirent *ent = nullptr;
581     size_t len = path.length();
582     struct stat statInfo;
583 
584     if (len >= FILENAME_MAX - 1) {
585         return ERR_INCORRECT_PATH;
586     }
587 
588     auto fName = (char *)calloc(FILENAME_MAX, sizeof(char));
589     if (fName == nullptr) {
590         return ERR_MEM_ALLOC_FAIL;
591     }
592 
593     if (strcpy_s(fName, FILENAME_MAX, path.c_str()) != ERR_SUCCESS) {
594         FREE_MEMORY_AND_SET_NULL(fName);
595         return ERR_MEM_ALLOC_FAIL;
596     }
597     fName[len++] = '/';
598     if ((dirPath = opendir(path.c_str())) == nullptr) {
599         MEDIA_ERR_LOG("Failed to opendir %{private}s, errno %{private}d", path.c_str(), errno);
600         FREE_MEMORY_AND_SET_NULL(fName);
601         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, -errno},
602             {KEY_OPT_FILE, path}, {KEY_OPT_TYPE, OptType::SCAN}};
603         PostEventUtils::GetInstance().PostErrorProcess(ErrType::FILE_OPT_ERR, map);
604         return ERR_NOT_ACCESSIBLE;
605     }
606 
607     int32_t recoverySuccessCnt = 0;
608     while ((ent = readdir(dirPath)) != nullptr) {
609         if (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) {
610             continue;
611         }
612 
613         if (strncpy_s(fName + len, FILENAME_MAX - len, ent->d_name, FILENAME_MAX - len)) {
614             continue;
615         }
616 
617         if (lstat(fName, &statInfo) == -1) {
618             continue;
619         }
620 
621         string currentPath = fName;
622         if (S_ISDIR(statInfo.st_mode)) {
623             int32_t cur_bucket = atoi(ent->d_name);
624             MEDIA_INFO_LOG("currentPath=%{public}s, path=%{public}s, cur_bucket %{public}d recovery start",
625                            DfxUtils::GetSafePath(currentPath).c_str(), DfxUtils::GetSafePath(path).c_str(), cur_bucket);
626 
627             // Recovery after interrupt, skip bucket which scanned.
628             if (metaStatus.find(cur_bucket) != metaStatus.end()) {
629                 MEDIA_INFO_LOG("skip bucket id=%{public}d", cur_bucket);
630                 continue;
631             }
632             (void)ScanMetaDir(currentPath, cur_bucket);
633             RefreshAlbumCount();
634             continue;
635         }
636 
637         MEDIA_DEBUG_LOG("currentPath=%{public}s, path=%{public}s",
638             DfxUtils::GetSafePath(currentPath).c_str(), DfxUtils::GetSafePath(path).c_str());
639 
640         FileAsset fileAsset;
641         if (ReadMetadataFromFile(currentPath, fileAsset) != E_OK) {
642             MEDIA_ERR_LOG("ScanMetaDir: ReadMetadataFrom file failed");
643             continue;
644         }
645 
646         // Insert fileAsset to DB
647         if (InsertMetadataInDbRetry(fileAsset) == E_OK) {
648             recoverySuccessCnt++;
649         }
650     }
651 
652     closedir(dirPath);
653     FREE_MEMORY_AND_SET_NULL(fName);
654 
655     if (bucket_id != -1) {
656         err = WriteMetaStatusToFile(to_string(bucket_id), recoverySuccessCnt);
657         if (err != E_OK) {
658             MEDIA_ERR_LOG("write meta status failed");
659         }
660         MEDIA_INFO_LOG("cur_bucket %{public}d recovery end", bucket_id);
661     }
662 
663     return err;
664 }
665 
WriteJsonFile(const std::string & filePath,const nlohmann::json & j)666 bool MediaLibraryMetaRecovery::WriteJsonFile(const std::string &filePath, const nlohmann::json &j)
667 {
668     const string parentDir = MediaFileUtils::GetParentPath(filePath);
669     if (!MediaFileUtils::CreateDirectory(parentDir)) {
670         MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
671         return false;
672     }
673 
674     std::ofstream outFile(filePath, std::ofstream::out | std::ofstream::trunc);
675     if (!outFile.is_open()) {
676         MEDIA_ERR_LOG("open filePath: %{private}s failed", filePath.c_str());
677         return false;
678     }
679     std::string jsonString = j.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
680     outFile << jsonString << std::endl;
681     outFile.close();
682     return true;
683 }
684 
ReadJsonFile(const std::string & filePath,nlohmann::json & j)685 bool MediaLibraryMetaRecovery::ReadJsonFile(const std::string &filePath, nlohmann::json &j)
686 {
687     std::ifstream inFile(filePath);
688     if (!inFile.is_open()) {
689         MEDIA_ERR_LOG("open filePath: %{private}s failed", filePath.c_str());
690         return false;
691     }
692     std::string buffer = std::string((istreambuf_iterator<char>(inFile)), istreambuf_iterator<char>());
693     j = json::parse(buffer, nullptr, false);
694     inFile.close();
695     return !j.is_discarded();
696 }
697 
WriteMetadataToFile(const string & filePath,const FileAsset & fileAsset)698 int32_t MediaLibraryMetaRecovery::WriteMetadataToFile(const string &filePath, const FileAsset &fileAsset)
699 {
700     json jsonMetadata;
701     AddMetadataToJson(jsonMetadata, fileAsset);
702     if (!WriteJsonFile(filePath, jsonMetadata)) {
703         MEDIA_ERR_LOG("WriteJsonFile failed");
704         return E_FILE_OPER_FAIL;
705     }
706     return E_OK;
707 }
708 
AddMetadataToJson(nlohmann::json & j,const FileAsset & fileAsset)709 void MediaLibraryMetaRecovery::AddMetadataToJson(nlohmann::json &j, const FileAsset &fileAsset)
710 {
711     std::unordered_map<std::string, ResultSetDataType> columnInfoMap = QueryRecoveryPhotosTableColumnInfo();
712     if (columnInfoMap.empty()) {
713         MEDIA_ERR_LOG("QueryRecoveryPhotosTableColumnInfo failed");
714         return;
715     }
716 
717     for (const auto &[key, type] : columnInfoMap) {
718         if (type == TYPE_STRING) {
719             string value = fileAsset.GetStrMember(key);
720             MEDIA_DEBUG_LOG("Writejson string: %{private}s: %{private}s", key.c_str(), value.c_str());
721             j[key] = json::string_t(value);
722         } else if (type == TYPE_INT32) {
723             int32_t value = fileAsset.GetInt32Member(key);
724             MEDIA_DEBUG_LOG("Writejson int32_t: %{private}s: %{public}d", key.c_str(), value);
725             j[key] = json::number_integer_t(value);
726         } else if (type == TYPE_INT64) {
727             int64_t value = fileAsset.GetInt64Member(key);
728             j[key] = json::number_integer_t(value);
729         } else if (type == TYPE_DOUBLE) {
730             double value = fileAsset.GetDoubleMember(key);
731             MEDIA_DEBUG_LOG("Writejson double: %{private}s: %{public}f", key.c_str(), value);
732             j[key] = json::number_float_t(value);
733         } else {
734             MEDIA_ERR_LOG("WriteFile: error type: %{public}d", type);
735         }
736     }
737 }
738 
GetMetadataFromJson(const nlohmann::json & j,FileAsset & fileAsset)739 bool MediaLibraryMetaRecovery::GetMetadataFromJson(const nlohmann::json &j, FileAsset &fileAsset)
740 {
741     std::unordered_map<std::string, ResultSetDataType> columnInfoMap = QueryRecoveryPhotosTableColumnInfo();
742     if (columnInfoMap.empty()) {
743         MEDIA_ERR_LOG("QueryRecoveryPhotosTableColumnInfo failed");
744         return false;
745     }
746 
747     bool ret = true;
748     for (const auto &[name, type] : columnInfoMap) {
749         if (type == TYPE_STRING) {
750             optional<string> value = GetStringFromJson(j, name);
751             if (value.has_value()) {
752                 fileAsset.SetMemberValue(name, value.value());
753             } else {
754                 ret = false;
755             }
756         } else if (type == TYPE_INT32) {
757             optional<int64_t> value = GetNumberFromJson(j, name);
758             if (value.has_value()) {
759                 fileAsset.SetMemberValue(name, (int32_t)value.value());
760             } else {
761                 ret = false;
762             }
763         } else if (type == TYPE_INT64) {
764             optional<int64_t> value = GetNumberFromJson(j, name);
765             if (value.has_value()) {
766                 fileAsset.SetMemberValue(name, (int64_t)value.value());
767             } else {
768                 ret = false;
769             }
770         } else if (type == TYPE_DOUBLE) {
771             optional<double> value = GetDoubleFromJson(j, name);
772             if (value.has_value()) {
773                 fileAsset.SetMemberValue(name, (double)value.value());
774             } else {
775                 ret = false;
776             }
777         } else {
778             MEDIA_ERR_LOG("ReadFile: error %{public}d", type);
779         }
780     }
781 
782     return ret;
783 }
784 
ReadMetadataFromFile(const string & filePath,FileAsset & fileAsset)785 int32_t MediaLibraryMetaRecovery::ReadMetadataFromFile(const string &filePath, FileAsset &fileAsset)
786 {
787     int ret = E_OK;
788     json jsonMetadata;
789     if (!ReadJsonFile(filePath, jsonMetadata)) {
790         MEDIA_ERR_LOG("ReadJsonFile failed");
791         return E_FILE_OPER_FAIL;
792     }
793 
794     if (!GetMetadataFromJson(jsonMetadata, fileAsset)) {
795         MEDIA_ERR_LOG("GetMetadataFromJson not all right");
796     }
797 
798     // Meida file path
799     string mediaFilePath = filePath;
800     size_t pos = mediaFilePath.find(META_RECOVERY_META_RELATIVE_PATH);
801     if (pos != string::npos) {
802         mediaFilePath.replace(pos, META_RECOVERY_META_RELATIVE_PATH.length(), META_RECOVERY_PHOTO_RELATIVE_PATH);
803     }
804     if (MediaFileUtils::EndsWith(mediaFilePath, META_RECOVERY_META_FILE_SUFFIX)) {
805         mediaFilePath.erase(mediaFilePath.length() - META_RECOVERY_META_FILE_SUFFIX.length());
806     }
807     fileAsset.SetFilePath(mediaFilePath);
808 
809     struct stat statInfo = { 0 };
810     if (stat(mediaFilePath.c_str(), &statInfo) != 0) {
811         MEDIA_ERR_LOG("ReadMetadataFromFile: stat syscall err %{public}d", errno);
812         ret = E_SYSCALL;
813         if (errno == ENOENT) {
814             remove(filePath.c_str());
815         }
816     }
817 
818     return ret;
819 }
820 
AddPhotoAlbumToJson(nlohmann::json & j,const PhotoAlbum & photoAlbum)821 void MediaLibraryMetaRecovery::AddPhotoAlbumToJson(nlohmann::json &j, const PhotoAlbum &photoAlbum)
822 {
823     j = json {
824         {PhotoAlbumColumns::ALBUM_ID, json::number_integer_t(photoAlbum.GetAlbumId())},
825         {PhotoAlbumColumns::ALBUM_TYPE, json::number_integer_t(photoAlbum.GetPhotoAlbumType())},
826         {PhotoAlbumColumns::ALBUM_SUBTYPE, json::number_integer_t(photoAlbum.GetPhotoAlbumSubType())},
827         {PhotoAlbumColumns::ALBUM_NAME, json::string_t(photoAlbum.GetAlbumName())},
828         {PhotoAlbumColumns::ALBUM_DATE_MODIFIED, json::number_integer_t(photoAlbum.GetDateModified())},
829         {PhotoAlbumColumns::CONTAINS_HIDDEN, json::number_integer_t(photoAlbum.GetContainsHidden())},
830         {PhotoAlbumColumns::ALBUM_ORDER, json::number_integer_t(photoAlbum.GetOrder())},
831         {PhotoAlbumColumns::ALBUM_BUNDLE_NAME, json::string_t(photoAlbum.GetBundleName())},
832         {PhotoAlbumColumns::ALBUM_LOCAL_LANGUAGE, json::string_t(photoAlbum.GetLocalLanguage())},
833         {PhotoAlbumColumns::ALBUM_DATE_ADDED, json::number_integer_t(photoAlbum.GetDateAdded())},
834         {PhotoAlbumColumns::ALBUM_IS_LOCAL, json::number_integer_t(photoAlbum.GetIsLocal())},
835         {PhotoAlbumColumns::ALBUM_LPATH, json::string_t(photoAlbum.GetLPath())},
836         {PhotoAlbumColumns::ALBUM_PRIORITY, json::number_integer_t(photoAlbum.GetPriority())}
837     };
838 }
839 
GetPhotoAlbumFromJson(const nlohmann::json & j,PhotoAlbum & photoAlbum)840 bool MediaLibraryMetaRecovery::GetPhotoAlbumFromJson(const nlohmann::json &j, PhotoAlbum &photoAlbum)
841 {
842     bool ret = true;
843     optional<int64_t> albumId = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_ID);
844     if (albumId.has_value()) {
845         photoAlbum.SetAlbumId((int32_t)albumId.value());
846     } else {
847         ret = false;
848     }
849 
850     optional<int64_t> albumType = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_TYPE);
851     if (albumType.has_value()) {
852         int32_t type = (int32_t)albumType.value();
853         photoAlbum.SetPhotoAlbumType(static_cast<PhotoAlbumType>(type));
854     } else {
855         ret = false;
856     }
857 
858     optional<int64_t> albumSubType = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_SUBTYPE);
859     if (albumSubType.has_value()) {
860         int32_t type = (int32_t)albumSubType.value();
861         photoAlbum.SetPhotoAlbumSubType(static_cast<PhotoAlbumSubType>(type));
862     } else {
863         ret = false;
864     }
865 
866     optional<string> albumName = GetStringFromJson(j, PhotoAlbumColumns::ALBUM_NAME);
867     if (albumName.has_value()) {
868         photoAlbum.SetAlbumName(albumName.value());
869     } else {
870         ret = false;
871     }
872 
873     optional<int64_t> dateModified = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_DATE_MODIFIED);
874     if (dateModified.has_value()) {
875         photoAlbum.SetDateModified(dateModified.value());
876     } else {
877         ret = false;
878     }
879 
880     optional<int64_t> containsHidden = GetNumberFromJson(j, PhotoAlbumColumns::CONTAINS_HIDDEN);
881     if (containsHidden.has_value()) {
882         photoAlbum.SetContainsHidden((int32_t)containsHidden.value());
883     } else {
884         ret = false;
885     }
886 
887     optional<int64_t> order = GetNumberFromJson(j, PhotoAlbumColumns::ALBUM_ORDER);
888     if (order.has_value()) {
889         photoAlbum.SetOrder((int32_t)order.value());
890     } else {
891         ret = false;
892     }
893 
894     return (ret && GetPhotoAlbumFromJsonPart1(j, photoAlbum));
895     // !! Do not add upgrade code here !!
896 }
897 
WritePhotoAlbumToFile(const string & filePath,const vector<shared_ptr<PhotoAlbum>> & vecPhotoAlbum)898 int32_t MediaLibraryMetaRecovery::WritePhotoAlbumToFile(const string &filePath,
899                                                         const vector<shared_ptr<PhotoAlbum>> &vecPhotoAlbum)
900 {
901     MEDIA_DEBUG_LOG("WritePhotoAlbumToFile start\n");
902 
903     const string parentDir = MediaFileUtils::GetParentPath(filePath);
904     if (!MediaFileUtils::CreateDirectory(parentDir)) {
905         MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
906         return false;
907     }
908 
909     json jsonArray = json::array();
910     for (auto &album : vecPhotoAlbum) {
911         if (album == nullptr) {
912             MEDIA_ERR_LOG("album == nullptr");
913             continue;
914         }
915 
916         json jsonPhotoAlbumItem;
917         OHOS::Media::PhotoAlbum &photoAlbumRef = *album.get();
918         AddPhotoAlbumToJson(jsonPhotoAlbumItem, photoAlbumRef);
919 
920         jsonArray.push_back(jsonPhotoAlbumItem);
921     }
922 
923     if (!WriteJsonFile(filePath, jsonArray)) {
924         MEDIA_ERR_LOG("WriteJsonFile failed");
925         return E_FILE_OPER_FAIL;
926     }
927 
928     MEDIA_DEBUG_LOG("WritePhotoAlbumToFile end\n");
929     return E_OK;
930 }
931 
ReadPhotoAlbumFromFile(const string & filePath,vector<shared_ptr<PhotoAlbum>> & photoAlbumVector)932 int32_t MediaLibraryMetaRecovery::ReadPhotoAlbumFromFile(const string &filePath,
933                                                          vector<shared_ptr<PhotoAlbum>> &photoAlbumVector)
934 {
935     json jsonArray;
936     if (!ReadJsonFile(filePath, jsonArray)) {
937         MEDIA_ERR_LOG("ReadJsonFile failed");
938         return E_FILE_OPER_FAIL;
939     }
940     if (!jsonArray.is_array()) {
941         MEDIA_ERR_LOG("json not is array");
942         return E_ERR;
943     }
944 
945     int ret = E_OK;
946     for (const json &j : jsonArray) {
947         PhotoAlbum photoAlbum;
948         if (!GetPhotoAlbumFromJson(j, photoAlbum)) {
949             MEDIA_WARN_LOG("GetPhotoAlbumFromJson failed");
950             ret = E_ERR;
951         }
952         if (photoAlbum.GetPhotoAlbumSubType() != 1 && photoAlbum.GetLPath() == "") {
953             continue;
954         }
955         photoAlbumVector.emplace_back(make_shared<PhotoAlbum>(photoAlbum));
956     }
957 
958     return ret;
959 }
960 
WriteMetaStatusToFile(const string & keyPath,const int32_t status)961 int32_t MediaLibraryMetaRecovery::WriteMetaStatusToFile(const string &keyPath, const int32_t status)
962 {
963     json j;
964     if (!ReadJsonFile(META_STATUS_PATH, j)) {
965         MEDIA_WARN_LOG("ReadFile META_STATUS_PATH failed, will write new META_STATUS_PATH file");
966         j = json::object();
967     }
968 
969     j[keyPath] = json::number_integer_t(status);
970 
971     if (!WriteJsonFile(META_STATUS_PATH, j)) {
972         MEDIA_ERR_LOG("WriteJsonFile failed");
973         return E_FILE_OPER_FAIL;
974     }
975 
976     return E_OK;
977 }
978 
ReadMetaStatusFromFile(set<int32_t> & status)979 int32_t MediaLibraryMetaRecovery::ReadMetaStatusFromFile(set<int32_t> &status)
980 {
981     json j;
982     if (!ReadJsonFile(META_STATUS_PATH, j)) {
983         MEDIA_ERR_LOG("ReadFile META_STATUS_PATH failed");
984         return E_FILE_OPER_FAIL;
985     }
986 
987     for (const auto& [key, value] : j.items()) {
988         if (!value.is_number_integer()) {
989             MEDIA_ERR_LOG("key: %{public}s not is number", key.c_str());
990             continue;
991         }
992         // Read bucket_id which finish recovery
993         int32_t val = atoi(key.c_str());
994         MEDIA_INFO_LOG("finish recovery bucket_id: %{public}s", key.c_str());
995         status.insert(val);
996     }
997 
998     return E_OK;
999 }
1000 
ReadMetaRecoveryCountFromFile()1001 int32_t MediaLibraryMetaRecovery::ReadMetaRecoveryCountFromFile()
1002 {
1003     json j;
1004     int32_t recoverySuccessCnt = 0;
1005 
1006     if (!ReadJsonFile(META_STATUS_PATH, j)) {
1007         MEDIA_ERR_LOG("ReadFile META_STATUS_PATH failed");
1008         return E_FILE_OPER_FAIL;
1009     }
1010 
1011     for (const auto& [key, value] : j.items()) {
1012         if (!value.is_number_integer()) {
1013             MEDIA_ERR_LOG("key: %{public}s not is number", key.c_str());
1014             continue;
1015         }
1016         int32_t val = value.get<int32_t>();
1017         recoverySuccessCnt += val;
1018         MEDIA_INFO_LOG("finish recovery bucket_id: %{public}s, recovery success count=%{public}d", key.c_str(), val);
1019     }
1020 
1021     return recoverySuccessCnt;
1022 }
1023 
UpdatePhotoOwnerAlbumId(NativeRdb::ValuesBucket & values)1024 bool MediaLibraryMetaRecovery::UpdatePhotoOwnerAlbumId(NativeRdb::ValuesBucket &values)
1025 {
1026     NativeRdb::ValueObject valueObject;
1027     if (!values.GetObject(PhotoColumn::PHOTO_OWNER_ALBUM_ID, valueObject)) {
1028         return false;
1029     }
1030 
1031     int32_t oldOwnerAlbumId = 0;
1032     valueObject.GetInt(oldOwnerAlbumId);
1033     if (oldAlbumIdToLpath.find(oldOwnerAlbumId) == oldAlbumIdToLpath.end()) {
1034         return false;
1035     }
1036 
1037     const std::string &lpath = oldAlbumIdToLpath[oldOwnerAlbumId];
1038     if (lpathToNewAlbumId.end() == lpathToNewAlbumId.find(lpath)) {
1039         return false;
1040     }
1041 
1042     int32_t newOwnerAlbumId = lpathToNewAlbumId[lpath];
1043     if (newOwnerAlbumId == oldOwnerAlbumId) {
1044         return false;
1045     }
1046 
1047     MEDIA_DEBUG_LOG("convert album %{public}d to %{public}d", oldOwnerAlbumId, newOwnerAlbumId);
1048     values.Delete(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
1049     values.PutInt(PhotoColumn::PHOTO_OWNER_ALBUM_ID, newOwnerAlbumId);
1050 
1051     return true;
1052 }
1053 
InsertMetadataInDbRetry(const FileAsset & fileAsset)1054 int32_t MediaLibraryMetaRecovery::InsertMetadataInDbRetry(const FileAsset &fileAsset)
1055 {
1056     int32_t retry_cnt = 0;
1057     do {
1058         if (InsertMetadataInDb(fileAsset) == E_OK) {
1059             break;
1060         }
1061 
1062         retry_cnt++;
1063         MEDIA_ERR_LOG("InsertMetadataInDb failed, retry_cnt = %{public}d", retry_cnt);
1064         this_thread::sleep_for(chrono::milliseconds(META_RETRY_INTERVAL));
1065     } while (retry_cnt < META_RETRY_MAX_COUNTS);
1066 
1067     if (retry_cnt >= META_RETRY_MAX_COUNTS) {
1068         MEDIA_ERR_LOG("InsertMetadataInDb finally failed, retry_cnt = %{public}d", retry_cnt);
1069         VariantMap map = {{KEY_ERR_FILE, __FILE__}, {KEY_ERR_LINE, __LINE__}, {KEY_ERR_CODE, E_DB_FAIL},
1070             {KEY_OPT_TYPE, OptType::CREATE}};
1071         PostEventUtils::GetInstance().PostErrorProcess(ErrType::RECOVERY_ERR, map);
1072         return ERR_FAIL;
1073     }
1074 
1075     return E_OK;
1076 }
1077 
InsertMetadataInDb(const FileAsset & fileAsset)1078 int32_t MediaLibraryMetaRecovery::InsertMetadataInDb(const FileAsset &fileAsset)
1079 {
1080     std::string filePath = fileAsset.GetFilePath();
1081     MEDIA_DEBUG_LOG("InsertMetadataInDb: photo filepath = %{public}s", DfxUtils::GetSafePath(filePath).c_str());
1082     if (MediaLibraryAssetOperations::CheckExist(filePath) == E_OK) {
1083         MEDIA_DEBUG_LOG("InsertMetadataInDb: insert: photo is exist in db, ignore");
1084         return E_OK;
1085     }
1086 
1087     std::unordered_map<std::string, ResultSetDataType> columnInfoMap = QueryRecoveryPhotosTableColumnInfo();
1088     if (columnInfoMap.empty()) {
1089         MEDIA_ERR_LOG("QueryRecoveryPhotosTableColumnInfo failed");
1090         return E_ERR;
1091     }
1092 
1093     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1094     if (rdbStore == nullptr) {
1095         MEDIA_ERR_LOG("GetRdbStore failed, return nullptr");
1096         return E_HAS_DB_ERROR;
1097     }
1098 
1099     NativeRdb::ValuesBucket valuesBucket;
1100     SetValuesFromFileAsset(fileAsset, valuesBucket, columnInfoMap);
1101 
1102     // set meta flags uptodate, to avoid backup db into meta again
1103     if (UpdatePhotoOwnerAlbumId(valuesBucket)) {
1104         valuesBucket.PutInt(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_DIRTY));
1105     } else {
1106         valuesBucket.PutInt(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_UPTODATE));
1107     }
1108 
1109     int64_t outRowId = -1;
1110     int32_t errCode = rdbStore->Insert(outRowId, PhotoColumn::PHOTOS_TABLE, valuesBucket);
1111     if (errCode != NativeRdb::E_OK) {
1112         MEDIA_ERR_LOG("Insert photo failed, errCode = %{public}d", errCode);
1113         return errCode;
1114     }
1115 
1116     return E_OK;
1117 }
1118 
InsertMetadataInDb(const std::vector<shared_ptr<PhotoAlbum>> & vecPhotoAlbum)1119 int32_t MediaLibraryMetaRecovery::InsertMetadataInDb(const std::vector<shared_ptr<PhotoAlbum>> &vecPhotoAlbum)
1120 {
1121     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1122     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "GetRdbStore failed, return nullptr)");
1123 
1124     for (auto iter : vecPhotoAlbum) {
1125         MEDIA_INFO_LOG("InsertMetadataInDb: album name = %{private}s", iter->GetAlbumName().c_str());
1126         NativeRdb::RdbPredicates predicates(PhotoAlbumColumns::TABLE);
1127         vector<string> columns = {PhotoAlbumColumns::ALBUM_ID,
1128             PhotoAlbumColumns::ALBUM_LPATH};
1129         predicates.IsNotNull(PhotoAlbumColumns::ALBUM_LPATH)->And()->EqualTo(PhotoAlbumColumns::ALBUM_LPATH,
1130                              iter->GetLPath());
1131         auto resultSet = MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
1132         if (resultSet == nullptr) {
1133             MEDIA_ERR_LOG("resultSet == nullptr)");
1134             continue;
1135         }
1136         if (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1137             MEDIA_ERR_LOG("skip duplicate lpath %{public}s", iter->GetLPath().c_str());
1138             continue;
1139         }
1140         std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
1141         int32_t errCode = NativeRdb::E_OK;
1142         std::function<int(void)> func = [&]()->int {
1143             // Insert album item
1144             NativeRdb::ValuesBucket valuesBucket;
1145             SetValuesFromPhotoAlbum(iter, valuesBucket);
1146             int64_t outRowId = -1;
1147             errCode = trans->Insert(outRowId, PhotoAlbumColumns::TABLE, valuesBucket);
1148             if (errCode != NativeRdb::E_OK) {
1149                 MEDIA_ERR_LOG("InsertMetadataInDb: insert album failed, errCode = %{public}d", errCode);
1150                 return errCode;
1151             }
1152 
1153             // Update album order inserted just now
1154             int32_t changedRows = -1;
1155             NativeRdb::RdbPredicates predicatesOrder(PhotoAlbumColumns::TABLE);
1156             predicatesOrder.And()->EqualTo(PhotoAlbumColumns::ALBUM_ID, outRowId)
1157                                  ->And()
1158                                  ->NotEqualTo(PhotoAlbumColumns::ALBUM_ORDER, iter->GetOrder());
1159             valuesBucket.Clear();
1160             valuesBucket.PutInt(PhotoAlbumColumns::ALBUM_ORDER, iter->GetOrder());
1161             errCode = trans->Update(changedRows, valuesBucket, predicatesOrder);
1162             if (errCode != E_OK) {
1163                 MEDIA_ERR_LOG("Update album order failed, err = %{public}d", errCode);
1164                 return E_HAS_DB_ERROR;
1165             }
1166             if (changedRows > 0) {
1167                 MEDIA_INFO_LOG("Update album order");
1168             }
1169             return errCode;
1170         };
1171         errCode = trans->RetryTrans(func);
1172         if (errCode != E_OK) {
1173             MEDIA_ERR_LOG("InsertMetadataInDb: trans retry fail!, ret:%{public}d", errCode);
1174             return errCode;
1175         }
1176     }
1177 
1178     return E_OK;
1179 }
1180 
UpdateMetadataFlagInDb(const int32_t fieldId,const MetadataFlags & flag)1181 int32_t MediaLibraryMetaRecovery::UpdateMetadataFlagInDb(const int32_t fieldId, const MetadataFlags &flag)
1182 {
1183     int32_t errCode = E_OK;
1184 
1185     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1186     if (!rdbStore) {
1187         MEDIA_ERR_LOG("GetRdbStore failed");
1188         return E_HAS_DB_ERROR;
1189     }
1190 
1191     NativeRdb::RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
1192     predicates.EqualTo(MediaColumn::MEDIA_ID, fieldId);
1193 
1194     NativeRdb::ValuesBucket values;
1195     values.PutInt(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(flag));
1196 
1197     int32_t changedRows = -1;
1198     errCode = rdbStore->Update(changedRows, values, predicates);
1199     if (errCode != E_OK) {
1200         MEDIA_ERR_LOG("Database update failed, err = %{public}d", errCode);
1201         return E_HAS_DB_ERROR;
1202     }
1203     return E_OK;
1204 }
1205 
SetRdbRebuiltStatus(bool status)1206 int32_t MediaLibraryMetaRecovery::SetRdbRebuiltStatus(bool status)
1207 {
1208     rdbRebuilt_ = status;
1209     reBuiltCount_++;
1210     return E_OK;
1211 }
1212 
StartAsyncRecovery()1213 int32_t MediaLibraryMetaRecovery::StartAsyncRecovery()
1214 {
1215     StatisticRestore();
1216 
1217     MediaLibraryMetaRecoveryState oldState = recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_RECOVERING);
1218     if (oldState == MediaLibraryMetaRecoveryState::STATE_RECOVERING) {
1219         MEDIA_INFO_LOG("recovery process is already running");
1220         return E_OK;
1221     }
1222 
1223     if (oldState == MediaLibraryMetaRecoveryState::STATE_NONE) {
1224         bool hasStatusFile = bool(access(META_STATUS_PATH.c_str(), F_OK) == E_OK);
1225         MEDIA_INFO_LOG("rebuild status %{public}d, has status file %{public}d", rdbRebuilt_, hasStatusFile);
1226         if (!hasStatusFile && !rdbRebuilt_) {
1227             MEDIA_INFO_LOG("StartAsyncRecovery: no need to recovery");
1228             recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_NONE);
1229             return E_OK;
1230         }
1231         oldState = hasStatusFile ? MediaLibraryMetaRecoveryState::STATE_RECOVERING_ABORT :
1232                                     MediaLibraryMetaRecoveryState::STATE_NONE;
1233     }
1234 
1235     if (oldState == MediaLibraryMetaRecoveryState::STATE_RECOVERING_ABORT) {
1236         ReadMetaStatusFromFile(metaStatus);
1237     } else {
1238         // Create status.json if not exist
1239         const string parentDir = MediaFileUtils::GetParentPath(META_STATUS_PATH);
1240         if (MediaFileUtils::CreateDirectory(parentDir)) {
1241             MediaFileUtils::CreateFile(META_STATUS_PATH);
1242         } else {
1243             MEDIA_ERR_LOG("CreateDirectory failed, dir = %{public}s", DfxUtils::GetSafePath(parentDir).c_str());
1244         }
1245     }
1246 
1247     std::thread([this]() {
1248         MEDIA_INFO_LOG("Start recovery");
1249         int64_t recoveryStartTime = MediaFileUtils::UTCTimeMilliSeconds();
1250         this->DoDataBaseRecovery();
1251         int64_t recoveryTotalTime = MediaFileUtils::UTCTimeMilliSeconds() - recoveryStartTime;
1252         bool isStatusFileExist = bool(access(META_STATUS_PATH.c_str(), F_OK) == E_OK);
1253         if (isStatusFileExist) {
1254             recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_RECOVERING_ABORT);
1255         } else {
1256             recoveryState_.exchange(MediaLibraryMetaRecoveryState::STATE_NONE);
1257         }
1258         recoveryCostTime_ += recoveryTotalTime;
1259         RecoveryStatistic();
1260     }).detach();
1261 
1262     return E_OK;
1263 }
1264 
DeleteMetaDataByPath(const string & filePath)1265 int32_t MediaLibraryMetaRecovery::DeleteMetaDataByPath(const string &filePath)
1266 {
1267     string metaFilePath;
1268     if (PhotoFileUtils::GetMetaPathFromOrignalPath(filePath, metaFilePath) != E_OK) {
1269         MEDIA_ERR_LOG("DeleteMetaDataByPath: invalid photo filePath, %{public}s",
1270             DfxUtils::GetSafePath(filePath).c_str());
1271         return E_INVALID_PATH;
1272     }
1273 
1274     if (remove(metaFilePath.c_str()) != 0 && errno != ENOENT) {
1275         MEDIA_ERR_LOG("remove metafile failed %{public}d, path %s", errno, DfxUtils::GetSafePath(metaFilePath).c_str());
1276     }
1277 
1278     MEDIA_INFO_LOG("DeleteMetaDataByPath: metafile removed successful, %{public}s",
1279         DfxUtils::GetSafePath(metaFilePath).c_str());
1280     return E_OK;
1281 }
1282 
StopCloudSync()1283 void MediaLibraryMetaRecovery::StopCloudSync()
1284 {
1285     MEDIA_INFO_LOG("Begin StopCloudSync");
1286     FileManagement::CloudSync::CloudSyncManager::GetInstance().StopSync(BUNDLE_NAME, true);
1287 }
1288 
RestartCloudSync()1289 void MediaLibraryMetaRecovery::RestartCloudSync()
1290 {
1291     MEDIA_INFO_LOG("Begin reset cloud cursor");
1292     static uint32_t baseUserRange = 200000; // uid base offset
1293     uid_t uid = getuid() / baseUserRange;
1294     FileManagement::CloudSync::CloudSyncManager::GetInstance().ResetCursor();
1295 
1296     int32_t ret = FileManagement::CloudSync::CloudSyncManager::GetInstance().StartSync(BUNDLE_NAME);
1297     if (ret != 0) {
1298         MEDIA_ERR_LOG("StartCloudSync fail, errcode=%{public}d", ret);
1299     }
1300     MEDIA_INFO_LOG("End StartCloudSync");
1301 }
1302 
GetDataType(const std::string & name)1303 ResultSetDataType MediaLibraryMetaRecovery::GetDataType(const std::string &name)
1304 {
1305     auto it = FILEASSET_MEMBER_MAP.find(name);
1306     if (it == FILEASSET_MEMBER_MAP.end()) {
1307         MEDIA_ERR_LOG("FILEASSET_MEMBER_MAP not find name: %{public}s", name.c_str());
1308         return TYPE_NULL;
1309     }
1310 
1311     switch (it->second) {
1312         case MEMBER_TYPE_INT32: {
1313             return TYPE_INT32;
1314             break;
1315         }
1316         case MEMBER_TYPE_INT64: {
1317             return TYPE_INT64;
1318             break;
1319         }
1320         case MEMBER_TYPE_STRING: {
1321             return TYPE_STRING;
1322             break;
1323         }
1324         case MEMBER_TYPE_DOUBLE: {
1325             return TYPE_DOUBLE;
1326             break;
1327         }
1328         default: {
1329             return TYPE_NULL;
1330             break;
1331         }
1332     }
1333 }
1334 
QueryRecoveryPhotosTableColumnInfo()1335 std::unordered_map<std::string, ResultSetDataType> MediaLibraryMetaRecovery::QueryRecoveryPhotosTableColumnInfo()
1336 {
1337     MEDIA_DEBUG_LOG("QueryRecoveryPhotosTableColumnInfo");
1338     std::unordered_map<std::string, ResultSetDataType> columnInfoMap;
1339     std::vector<std::string> columnInfo = MediaLibraryAssetOperations::QueryPhotosTableColumnInfo();
1340     if (columnInfo.empty()) {
1341         MEDIA_ERR_LOG("GetPhotosTableColumnInfo failed");
1342         return columnInfoMap;
1343     }
1344 
1345     for (const std::string &name : columnInfo) {
1346         if (EXCLUDED_COLUMNS.count(name) > 0) {
1347             continue;
1348         }
1349         ResultSetDataType type = GetDataType(name);
1350         columnInfoMap.emplace(name, type);
1351         MEDIA_DEBUG_LOG("photos table name: %{public}s, type: %{public}d", name.c_str(), type);
1352     }
1353 
1354     return columnInfoMap;
1355 }
1356 
ResetAllMetaDirty()1357 int32_t MediaLibraryMetaRecovery::ResetAllMetaDirty()
1358 {
1359     const std::string RESET_ALL_META_DIRTY_SQL =
1360         " UPDATE " + PhotoColumn::PHOTOS_TABLE + " SET " + PhotoColumn::PHOTO_METADATA_FLAGS +
1361         " = 0 " + " WHERE " + PhotoColumn::PHOTO_METADATA_FLAGS + " == 2; END;";
1362 
1363     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1364     if (rdbStore == nullptr) {
1365         return E_HAS_DB_ERROR;
1366     }
1367 
1368     int32_t err = rdbStore->ExecuteSql(RESET_ALL_META_DIRTY_SQL);
1369     if (err != NativeRdb::E_OK) {
1370         MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s", RESET_ALL_META_DIRTY_SQL.c_str());
1371     }
1372     return err;
1373 }
1374 
QueryInt(const NativeRdb::AbsRdbPredicates & predicates,const std::vector<std::string> & columns,const std::string & queryColumn,int32_t & value)1375 static int32_t QueryInt(const NativeRdb::AbsRdbPredicates &predicates,
1376     const std::vector<std::string> &columns, const std::string &queryColumn, int32_t &value)
1377 {
1378     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(predicates, columns);
1379     if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1380         return E_DB_FAIL;
1381     }
1382     value = GetInt32Val(queryColumn, resultSet);
1383     return E_OK;
1384 }
1385 
QueryAllPhoto(bool backup)1386 static int32_t QueryAllPhoto(bool backup)
1387 {
1388     NativeRdb::RdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
1389     predicates.And()->BeginWrap()->EqualTo(PhotoColumn::PHOTO_POSITION, "1")->Or()
1390         ->EqualTo(PhotoColumn::PHOTO_POSITION, "3")->EndWrap();
1391 
1392     if (backup) {
1393         predicates.BeginWrap()
1394                   ->EqualTo(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_NEW))
1395                   ->Or()
1396                   ->EqualTo(PhotoColumn::PHOTO_METADATA_FLAGS, static_cast<int>(MetadataFlags::TYPE_DIRTY))
1397                   ->Or()
1398                   ->IsNull(PhotoColumn::PHOTO_METADATA_FLAGS)
1399                   ->EndWrap();
1400     }
1401 
1402     std::vector<std::string> columns = { "count(1) AS count" };
1403     std::string queryColumn = "count";
1404     int32_t count;
1405     int32_t errCode = QueryInt(predicates, columns, queryColumn, count);
1406     if (errCode != E_OK) {
1407         MEDIA_ERR_LOG("query local image fail: %{public}d", errCode);
1408     }
1409     return count;
1410 }
1411 
StatisticSave()1412 void MediaLibraryMetaRecovery::StatisticSave()
1413 {
1414     int32_t errCode;
1415     shared_ptr<NativePreferences::Preferences> prefs =
1416         NativePreferences::PreferencesHelper::GetPreferences(RDB_CONFIG, errCode);
1417     if (!prefs) {
1418         MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
1419         return;
1420     }
1421     prefs->PutLong(BACKUP_PHOTO_COUNT, backupSuccCnt_);
1422     prefs->PutLong(BACKUP_COST_TIME, backupCostTime_);
1423     prefs->PutLong(REBUILT_COUNT, reBuiltCount_);
1424     prefs->PutLong(RECOVERY_BACKUP_TOTAL_COUNT, recoveryTotalBackupCnt_);
1425     prefs->PutLong(RECOVERY_SUCC_PHOTO_COUNT, recoverySuccCnt_);
1426     prefs->PutLong(RECOVERY_COST_TIME, recoveryCostTime_);
1427     prefs->FlushSync();
1428 }
1429 
StatisticRestore()1430 void MediaLibraryMetaRecovery::StatisticRestore()
1431 {
1432     int32_t errCode;
1433     shared_ptr<NativePreferences::Preferences> prefs =
1434         NativePreferences::PreferencesHelper::GetPreferences(RDB_CONFIG, errCode);
1435     if (!prefs) {
1436         MEDIA_ERR_LOG("get preferences error: %{public}d", errCode);
1437         return;
1438     }
1439     backupSuccCnt_ = prefs->GetLong(BACKUP_PHOTO_COUNT, 0);
1440     backupCostTime_ = prefs->GetLong(BACKUP_COST_TIME, 0);
1441     reBuiltCount_ += prefs->GetLong(REBUILT_COUNT, 0);  // reBuiltCount_ will be set before Restore
1442     recoveryTotalBackupCnt_ = prefs->GetLong(RECOVERY_BACKUP_TOTAL_COUNT, 0);
1443     recoverySuccCnt_ = prefs->GetLong(RECOVERY_SUCC_PHOTO_COUNT, 0);
1444     recoveryCostTime_ = prefs->GetLong(RECOVERY_COST_TIME, 0);
1445 }
1446 
StatisticReset()1447 void MediaLibraryMetaRecovery::StatisticReset()
1448 {
1449     backupSuccCnt_ = 0;
1450     reBuiltCount_ = 0;
1451     backupCostTime_ = 0;
1452     recoverySuccCnt_ = 0;
1453     recoveryCostTime_ = 0;
1454     recoveryTotalBackupCnt_ = 0;
1455     StatisticSave();
1456 }
1457 
RecoveryStatistic()1458 void MediaLibraryMetaRecovery::RecoveryStatistic()
1459 {
1460     static constexpr char MEDIA_LIBRARY[] = "MEDIALIBRARY";
1461     int64_t totalPhotoCount = QueryAllPhoto(false);
1462     int64_t totalbackupCount = GetTotalBackupFileCount();
1463     int ret = HiSysEventWrite(
1464         MEDIA_LIBRARY,
1465         "MEDIALIB_META_RECOVERY_INFO",
1466         HiviewDFX::HiSysEvent::EventType::STATISTIC,
1467         "TOTAL_PHOTO_COUNT", totalPhotoCount,
1468         "TOTAL_BACKUP_COUNT", totalbackupCount,
1469         "BACKUP_PHOTO_COUNT", backupSuccCnt_,
1470         "BACKUP_COST_TIME", backupCostTime_,
1471         "REBUILT_COUNT", reBuiltCount_,
1472         "RECOVERY_BACKUP_TOTAL_COUNT", recoveryTotalBackupCnt_,
1473         "RECOVERY_SUCC_PHOTO_COUNT", recoverySuccCnt_,
1474         "RECOVERY_COST_TIME", recoveryCostTime_);
1475     if (ret != 0) {
1476         MEDIA_ERR_LOG("RecoveryStatistic error:%{public}d", ret);
1477     }
1478     StatisticReset();
1479 }
1480 } // namespace Media
1481 } // namespace OHOS
1482