1 /*
2 * Copyright (C) 2023-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define MLOG_TAG "MediaLibraryBaseRestore"
17
18 #include "base_restore.h"
19
20 #include <sstream>
21
22 #include "application_context.h"
23 #include "backup_database_utils.h"
24 #include "backup_dfx_utils.h"
25 #include "backup_file_utils.h"
26 #include "backup_log_utils.h"
27 #include "directory_ex.h"
28 #include "extension_context.h"
29 #include "media_column.h"
30 #include "media_log.h"
31 #include "media_file_utils.h"
32 #include "media_scanner_manager.h"
33 #include "medialibrary_asset_operations.h"
34 #include "medialibrary_data_manager.h"
35 #include "medialibrary_object_utils.h"
36 #include "medialibrary_rdb_utils.h"
37 #include "medialibrary_type_const.h"
38 #include "medialibrary_errno.h"
39 #include "metadata.h"
40 #include "moving_photo_file_utils.h"
41 #include "parameters.h"
42 #include "photo_album_column.h"
43 #include "result_set_utils.h"
44 #include "userfilemgr_uri.h"
45 #include "medialibrary_notify.h"
46 #include "upgrade_restore_task_report.h"
47 #include "medialibrary_rdb_transaction.h"
48 #include "database_report.h"
49
50 namespace OHOS {
51 namespace Media {
52 const std::string DATABASE_PATH = "/data/storage/el2/database/rdb/media_library.db";
53 const std::string SINGLE_DIR_NAME = "A";
54 const std::string CLONE_FLAG = "multimedia.medialibrary.cloneFlag";
55
StartRestore(const std::string & backupRetoreDir,const std::string & upgradePath)56 void BaseRestore::StartRestore(const std::string &backupRetoreDir, const std::string &upgradePath)
57 {
58 backupRestoreDir_ = backupRetoreDir;
59 int32_t errorCode = Init(backupRetoreDir, upgradePath, true);
60 if (errorCode == E_OK) {
61 RestorePhoto();
62 RestoreAudio();
63 MEDIA_INFO_LOG("migrate database number: %{public}lld, file number: %{public}lld (%{public}lld + "
64 "%{public}lld), duplicate number: %{public}lld + %{public}lld, audio database number:%{public}lld, "
65 "audio file number:%{public}lld, duplicate audio number: %{public}lld, map number: %{public}lld",
66 (long long)migrateDatabaseNumber_, (long long)migrateFileNumber_,
67 (long long)(migrateFileNumber_ - migrateVideoFileNumber_), (long long)migrateVideoFileNumber_,
68 (long long)migratePhotoDuplicateNumber_, (long long)migrateVideoDuplicateNumber_,
69 (long long)migrateAudioDatabaseNumber_, (long long)migrateAudioFileNumber_,
70 (long long)migrateAudioDuplicateNumber_, (long long) migrateDatabaseMapNumber_);
71 UpdateDatabase();
72 } else {
73 if (errorCode != EXTERNAL_DB_NOT_EXIST) {
74 SetErrorCode(RestoreError::INIT_FAILED);
75 }
76 ErrorInfo errorInfo(RestoreError::INIT_FAILED, 0, errorCode);
77 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
78 }
79 HandleRestData();
80 }
81
Init(void)82 int32_t BaseRestore::Init(void)
83 {
84 if (mediaLibraryRdb_ != nullptr) {
85 return E_OK;
86 }
87 auto context = AbilityRuntime::Context::GetApplicationContext();
88 if (context == nullptr) {
89 MEDIA_ERR_LOG("Failed to get context");
90 return E_FAIL;
91 }
92 int32_t err = BackupDatabaseUtils::InitDb(mediaLibraryRdb_, MEDIA_DATA_ABILITY_DB_NAME, DATABASE_PATH, BUNDLE_NAME,
93 true, context->GetArea());
94 if (err != E_OK) {
95 MEDIA_ERR_LOG("medialibrary rdb fail, err = %{public}d", err);
96 return E_FAIL;
97 }
98 int32_t sceneCode = 0;
99 int32_t errCode = MediaLibraryDataManager::GetInstance()->InitMediaLibraryMgr(context, nullptr, sceneCode);
100 if (errCode != E_OK) {
101 MEDIA_ERR_LOG("When restore, InitMediaLibraryMgr fail, errcode = %{public}d", errCode);
102 return errCode;
103 }
104 migrateDatabaseNumber_ = 0;
105 migrateFileNumber_ = 0;
106 migrateVideoFileNumber_ = 0;
107 migrateAudioDatabaseNumber_ = 0;
108 migrateAudioFileNumber_ = 0;
109 imageNumber_ = BackupDatabaseUtils::QueryUniqueNumber(mediaLibraryRdb_, IMAGE_ASSET_TYPE);
110 videoNumber_ = BackupDatabaseUtils::QueryUniqueNumber(mediaLibraryRdb_, VIDEO_ASSET_TYPE);
111 audioNumber_ = BackupDatabaseUtils::QueryUniqueNumber(mediaLibraryRdb_, AUDIO_ASSET_TYPE);
112 MEDIA_INFO_LOG("imageNumber: %{public}d", (int)imageNumber_);
113 MEDIA_INFO_LOG("videoNumber: %{public}d", (int)videoNumber_);
114 MEDIA_INFO_LOG("audioNumber: %{public}d", (int)audioNumber_);
115 return E_OK;
116 }
117
ConvertPathToRealPath(const std::string & srcPath,const std::string & prefix,std::string & newPath,std::string & relativePath)118 bool BaseRestore::ConvertPathToRealPath(const std::string &srcPath, const std::string &prefix,
119 std::string &newPath, std::string &relativePath)
120 {
121 size_t pos = 0;
122 int32_t count = 0;
123 constexpr int32_t prefixLevel = 4;
124 for (size_t i = 0; i < srcPath.length(); i++) {
125 if (srcPath[i] == '/') {
126 count++;
127 if (count == prefixLevel) {
128 pos = i;
129 break;
130 }
131 }
132 }
133 if (count < prefixLevel) {
134 return false;
135 }
136 relativePath = srcPath.substr(pos);
137 if (!dualDirName_.empty() && relativePath.find(dualDirName_) != string::npos) {
138 std::size_t posStart = relativePath.find_first_of("/");
139 std::size_t posEnd = relativePath.find_first_of("/", posStart + 1);
140 if (posEnd != string::npos) {
141 string temp = relativePath.substr(posStart + 1, posEnd - posStart -1);
142 if (temp == dualDirName_) {
143 relativePath.replace(relativePath.find(dualDirName_), dualDirName_.length(), SINGLE_DIR_NAME);
144 }
145 }
146 }
147 std::string extraPrefix = BackupFileUtils::GetExtraPrefixForRealPath(sceneCode_, srcPath);
148 newPath = prefix + extraPrefix + relativePath;
149 return true;
150 }
151
QuerySql(const string & sql,const vector<string> & selectionArgs) const152 shared_ptr<NativeRdb::ResultSet> BaseRestore::QuerySql(const string &sql, const vector<string> &selectionArgs) const
153 {
154 if (mediaLibraryRdb_ == nullptr) {
155 MEDIA_ERR_LOG("Pointer rdb_ is nullptr. Maybe it didn't init successfully.");
156 return nullptr;
157 }
158
159 return mediaLibraryRdb_->QuerySql(sql, selectionArgs);
160 }
161
MoveFile(const std::string & srcFile,const std::string & dstFile) const162 int32_t BaseRestore::MoveFile(const std::string &srcFile, const std::string &dstFile) const
163 {
164 int32_t errCode = BackupFileUtils::MoveFile(srcFile, dstFile, sceneCode_);
165 if (errCode == E_SUCCESS) {
166 return E_OK;
167 }
168 if (this->CopyFile(srcFile, dstFile) != E_OK) {
169 return E_FAIL;
170 }
171 (void)MediaFileUtils::DeleteFile(srcFile);
172 return E_OK;
173 }
174
CopyFile(const std::string & srcFile,const std::string & dstFile) const175 int32_t BaseRestore::CopyFile(const std::string &srcFile, const std::string &dstFile) const
176 {
177 if (!MediaFileUtils::CopyFileUtil(srcFile, dstFile)) {
178 MEDIA_ERR_LOG("CopyFile failed, src: %{public}s, dst: %{public}s, errMsg: %{public}s",
179 BackupFileUtils::GarbleFilePath(srcFile, sceneCode_).c_str(),
180 BackupFileUtils::GarbleFilePath(srcFile, DEFAULT_RESTORE_ID).c_str(), strerror(errno));
181 return E_FAIL;
182 }
183 return E_OK;
184 }
185
IsFileValid(FileInfo & fileInfo,const int32_t sceneCode)186 int32_t BaseRestore::IsFileValid(FileInfo &fileInfo, const int32_t sceneCode)
187 {
188 int32_t errCode = BackupFileUtils::IsFileValid(fileInfo.filePath, DUAL_FRAME_CLONE_RESTORE_ID,
189 fileInfo.relativePath, hasLowQualityImage_);
190 if (errCode != E_OK) {
191 MEDIA_ERR_LOG("File is not valid: %{public}s, errno=%{public}d.",
192 BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode).c_str(), errno);
193 return errCode;
194 }
195
196 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
197 if (!MediaFileUtils::IsFileValid(fileInfo.movingPhotoVideoPath)) {
198 MEDIA_ERR_LOG("Moving photo video is not valid: %{public}s, errno=%{public}d.",
199 BackupFileUtils::GarbleFilePath(fileInfo.movingPhotoVideoPath, sceneCode).c_str(), errno);
200 return E_FAIL;
201 }
202
203 if (!MediaFileUtils::IsFileValid(fileInfo.extraDataPath)) {
204 MEDIA_WARN_LOG("Media extra data is not valid: %{public}s, errno=%{public}d.",
205 BackupFileUtils::GarbleFilePath(fileInfo.extraDataPath, sceneCode).c_str(), errno);
206 return E_FAIL;
207 }
208 }
209 return E_OK;
210 }
211
RemoveDuplicateDualCloneFiles(const FileInfo & fileInfo)212 static void RemoveDuplicateDualCloneFiles(const FileInfo &fileInfo)
213 {
214 (void)MediaFileUtils::DeleteFile(fileInfo.filePath);
215 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
216 (void)MediaFileUtils::DeleteFile(fileInfo.movingPhotoVideoPath);
217 (void)MediaFileUtils::DeleteFile(fileInfo.extraDataPath);
218 }
219 }
220
GetInsertValues(const int32_t sceneCode,std::vector<FileInfo> & fileInfos,int32_t sourceType)221 vector<NativeRdb::ValuesBucket> BaseRestore::GetInsertValues(const int32_t sceneCode, std::vector<FileInfo> &fileInfos,
222 int32_t sourceType)
223 {
224 vector<NativeRdb::ValuesBucket> values;
225 for (size_t i = 0; i < fileInfos.size(); i++) {
226 int32_t errCode = IsFileValid(fileInfos[i], sceneCode);
227 if (errCode != E_OK) {
228 fileInfos[i].needMove = false;
229 std::string fileDbCheckInfo = CheckInvalidFile(fileInfos[i], errCode);
230 ErrorInfo errorInfo(RestoreError::FILE_INVALID, 1, std::to_string(errCode),
231 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i], { fileDbCheckInfo }));
232 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
233 continue;
234 }
235 std::string cloudPath;
236 int32_t uniqueId = GetUniqueId(fileInfos[i].fileType);
237 errCode = BackupFileUtils::CreateAssetPathById(uniqueId, fileInfos[i].fileType,
238 MediaFileUtils::GetExtensionFromPath(fileInfos[i].displayName), cloudPath);
239 if (errCode != E_OK) {
240 fileInfos[i].needMove = false;
241 ErrorInfo errorInfo(RestoreError::CREATE_PATH_FAILED, 1, std::to_string(errCode),
242 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i]));
243 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
244 continue;
245 }
246 fileInfos[i].cloudPath = cloudPath;
247 NativeRdb::ValuesBucket value = GetInsertValue(fileInfos[i], cloudPath, sourceType);
248 SetValueFromMetaData(fileInfos[i], value);
249 if ((sceneCode == DUAL_FRAME_CLONE_RESTORE_ID || sceneCode == OTHERS_PHONE_CLONE_RESTORE ||
250 sceneCode == LITE_PHONE_CLONE_RESTORE || sceneCode == I_PHONE_CLONE_RESTORE) &&
251 this->HasSameFileForDualClone(fileInfos[i])) {
252 fileInfos[i].needMove = false;
253 RemoveDuplicateDualCloneFiles(fileInfos[i]);
254 MEDIA_WARN_LOG("File %{public}s already exists.",
255 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str());
256 UpdateDuplicateNumber(fileInfos[i].fileType);
257 continue;
258 }
259 if (fileInfos[i].isNew) {
260 values.emplace_back(value);
261 }
262 }
263 return values;
264 }
265
InsertDateTaken(std::unique_ptr<Metadata> & metadata,FileInfo & fileInfo,NativeRdb::ValuesBucket & value)266 static void InsertDateTaken(std::unique_ptr<Metadata> &metadata, FileInfo &fileInfo, NativeRdb::ValuesBucket &value)
267 {
268 int64_t dateTaken = metadata->GetDateTaken();
269 if (dateTaken != 0) {
270 value.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
271 fileInfo.dateTaken = dateTaken;
272 return;
273 }
274
275 int64_t dateAdded = metadata->GetFileDateAdded();
276 if (dateAdded == 0) {
277 int64_t dateModified = metadata->GetFileDateModified();
278 if (dateModified == 0) {
279 dateTaken = MediaFileUtils::UTCTimeMilliSeconds();
280 } else {
281 dateTaken = dateModified;
282 }
283 } else {
284 dateTaken = dateAdded;
285 }
286 value.PutLong(MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
287 fileInfo.dateTaken = dateTaken;
288 }
289
InsertDateAdded(std::unique_ptr<Metadata> & metadata,NativeRdb::ValuesBucket & value)290 static void InsertDateAdded(std::unique_ptr<Metadata> &metadata, NativeRdb::ValuesBucket &value)
291 {
292 int64_t dateAdded = metadata->GetFileDateAdded();
293 if (dateAdded != 0) {
294 value.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
295 return;
296 }
297
298 int64_t dateTaken = metadata->GetDateTaken();
299 if (dateTaken == 0) {
300 int64_t dateModified = metadata->GetFileDateModified();
301 if (dateModified == 0) {
302 dateAdded = MediaFileUtils::UTCTimeMilliSeconds();
303 } else {
304 dateAdded = dateModified;
305 }
306 } else {
307 dateAdded = dateTaken;
308 }
309 value.PutLong(MediaColumn::MEDIA_DATE_ADDED, dateAdded);
310 }
311
InsertOrientation(std::unique_ptr<Metadata> & metadata,NativeRdb::ValuesBucket & value,FileInfo & fileInfo,int32_t sceneCode)312 static void InsertOrientation(std::unique_ptr<Metadata> &metadata, NativeRdb::ValuesBucket &value,
313 FileInfo &fileInfo, int32_t sceneCode)
314 {
315 bool hasOrientation = value.HasColumn(PhotoColumn::PHOTO_ORIENTATION);
316 if (hasOrientation && fileInfo.fileType != MEDIA_TYPE_VIDEO) {
317 return; // image use orientation in rdb
318 }
319 if (hasOrientation) {
320 value.Delete(PhotoColumn::PHOTO_ORIENTATION);
321 }
322 value.PutInt(PhotoColumn::PHOTO_ORIENTATION, metadata->GetOrientation()); // video use orientation in metadata
323 if (sceneCode == OTHERS_PHONE_CLONE_RESTORE || sceneCode == I_PHONE_CLONE_RESTORE ||
324 sceneCode == LITE_PHONE_CLONE_RESTORE) {
325 fileInfo.orientation = metadata->GetOrientation();
326 }
327 }
328
SetCoverPosition(const FileInfo & fileInfo,const unique_ptr<Metadata> & imageMetaData,NativeRdb::ValuesBucket & value)329 static void SetCoverPosition(const FileInfo &fileInfo,
330 const unique_ptr<Metadata> &imageMetaData, NativeRdb::ValuesBucket &value)
331 {
332 uint64_t coverPosition = 0;
333 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
334 uint32_t version = 0;
335 uint32_t frameIndex = 0;
336 bool hasCinemagraphInfo = false;
337 string absExtraDataPath;
338 if (!PathToRealPath(fileInfo.extraDataPath, absExtraDataPath)) {
339 MEDIA_ERR_LOG("file is not real path: %{private}s, errno: %{public}d",
340 fileInfo.extraDataPath.c_str(), errno);
341 value.PutLong(PhotoColumn::PHOTO_COVER_POSITION, static_cast<int64_t>(coverPosition));
342 return;
343 }
344 UniqueFd extraDataFd(open(absExtraDataPath.c_str(), O_RDONLY));
345 (void)MovingPhotoFileUtils::GetVersionAndFrameNum(extraDataFd.Get(), version, frameIndex, hasCinemagraphInfo);
346 (void)MovingPhotoFileUtils::GetCoverPosition(fileInfo.movingPhotoVideoPath,
347 frameIndex, coverPosition, Scene::AV_META_SCENE_CLONE);
348 }
349 value.PutLong(PhotoColumn::PHOTO_COVER_POSITION, static_cast<int64_t>(coverPosition));
350 }
351
SetValueFromMetaData(FileInfo & fileInfo,NativeRdb::ValuesBucket & value)352 void BaseRestore::SetValueFromMetaData(FileInfo &fileInfo, NativeRdb::ValuesBucket &value)
353 {
354 std::unique_ptr<Metadata> data = make_unique<Metadata>();
355 data->SetFilePath(fileInfo.filePath);
356 data->SetFileMediaType(fileInfo.fileType);
357 data->SetFileDateModified(fileInfo.dateModified);
358 data->SetFileName(fileInfo.displayName);
359 BackupFileUtils::FillMetadata(data);
360 MediaType mediaType = data->GetFileMediaType();
361
362 value.PutString(MediaColumn::MEDIA_FILE_PATH, data->GetFilePath());
363 value.PutString(MediaColumn::MEDIA_MIME_TYPE, data->GetFileMimeType());
364 value.PutInt(MediaColumn::MEDIA_TYPE, mediaType);
365 value.PutString(MediaColumn::MEDIA_TITLE, data->GetFileTitle());
366 if (fileInfo.fileSize != 0) {
367 value.PutLong(MediaColumn::MEDIA_SIZE, fileInfo.fileSize);
368 } else {
369 MEDIA_WARN_LOG("DB file size is zero!");
370 value.PutLong(MediaColumn::MEDIA_SIZE, data->GetFileSize());
371 fileInfo.fileSize = data->GetFileSize();
372 }
373 value.PutLong(MediaColumn::MEDIA_DATE_MODIFIED, data->GetFileDateModified());
374 value.PutInt(MediaColumn::MEDIA_DURATION, data->GetFileDuration());
375 InsertDateTaken(data, fileInfo, value);
376 value.PutLong(MediaColumn::MEDIA_TIME_PENDING, 0);
377 value.PutInt(PhotoColumn::PHOTO_HEIGHT, data->GetFileHeight());
378 value.PutInt(PhotoColumn::PHOTO_WIDTH, data->GetFileWidth());
379 value.PutDouble(PhotoColumn::PHOTO_LONGITUDE, data->GetLongitude());
380 value.PutDouble(PhotoColumn::PHOTO_LATITUDE, data->GetLatitude());
381 value.PutString(PhotoColumn::PHOTO_ALL_EXIF, data->GetAllExif());
382 value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE, data->GetShootingMode());
383 value.PutString(PhotoColumn::PHOTO_SHOOTING_MODE_TAG, data->GetShootingModeTag());
384 value.PutLong(PhotoColumn::PHOTO_LAST_VISIT_TIME, data->GetLastVisitTime());
385 value.PutString(PhotoColumn::PHOTO_FRONT_CAMERA, data->GetFrontCamera());
386 value.PutInt(PhotoColumn::PHOTO_DYNAMIC_RANGE_TYPE, data->GetDynamicRangeType());
387 InsertDateAdded(data, value);
388 InsertOrientation(data, value, fileInfo, sceneCode_);
389 int64_t dateAdded = 0;
390 NativeRdb::ValueObject valueObject;
391 if (value.GetObject(MediaColumn::MEDIA_DATE_ADDED, valueObject)) {
392 valueObject.GetLong(dateAdded);
393 }
394 fileInfo.dateAdded = dateAdded;
395 value.PutString(PhotoColumn::PHOTO_DATE_YEAR,
396 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_YEAR_FORMAT, fileInfo.dateTaken));
397 value.PutString(PhotoColumn::PHOTO_DATE_MONTH,
398 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_MONTH_FORMAT, fileInfo.dateTaken));
399 value.PutString(PhotoColumn::PHOTO_DATE_DAY,
400 MediaFileUtils::StrCreateTimeByMilliseconds(PhotoColumn::PHOTO_DATE_DAY_FORMAT, fileInfo.dateTaken));
401 SetCoverPosition(fileInfo, data, value);
402 }
403
CreateDir(std::string & dir)404 void BaseRestore::CreateDir(std::string &dir)
405 {
406 if (!MediaFileUtils::IsFileExists(dir)) {
407 MediaFileUtils::CreateDirectory(dir);
408 }
409 }
410
RecursiveCreateDir(std::string & relativePath,std::string & suffix)411 void BaseRestore::RecursiveCreateDir(std::string &relativePath, std::string &suffix)
412 {
413 CreateDir(relativePath);
414 size_t pos = suffix.find('/');
415 if (pos == std::string::npos) {
416 return;
417 }
418 std::string prefix = suffix.substr(0, pos + 1);
419 std::string suffixTmp = suffix.erase(0, prefix.length());
420 prefix = relativePath + prefix;
421 RecursiveCreateDir(prefix, suffixTmp);
422 }
423
InsertAudio(int32_t sceneCode,std::vector<FileInfo> & fileInfos)424 void BaseRestore::InsertAudio(int32_t sceneCode, std::vector<FileInfo> &fileInfos)
425 {
426 if (fileInfos.empty()) {
427 MEDIA_ERR_LOG("fileInfos are empty");
428 return;
429 }
430 int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
431 int32_t fileMoveCount = 0;
432 for (size_t i = 0; i < fileInfos.size(); i++) {
433 if (!MediaFileUtils::IsFileExists(fileInfos[i].filePath)) {
434 MEDIA_ERR_LOG("File is not exist: filePath: %{public}s, size: %{public}lld",
435 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str(),
436 (long long)fileInfos[i].fileSize);
437 continue;
438 }
439 string relativePath0 = RESTORE_MUSIC_LOCAL_DIR;
440 string relativePath1 = fileInfos[i].relativePath;
441 if (relativePath1[0] == '/') {
442 relativePath1.erase(0, 1);
443 }
444 string dstPath = RESTORE_MUSIC_LOCAL_DIR + relativePath1;
445 RecursiveCreateDir(relativePath0, relativePath1);
446 if (MediaFileUtils::IsFileExists(dstPath)) {
447 MEDIA_INFO_LOG("dstPath %{public}s already exists.",
448 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str());
449 UpdateDuplicateNumber(fileInfos[i].fileType);
450 continue;
451 }
452 int32_t moveErrCode = BackupFileUtils::MoveFile(fileInfos[i].filePath, dstPath, sceneCode);
453 if (moveErrCode != E_SUCCESS) {
454 MEDIA_ERR_LOG("MoveFile failed, filePath: %{public}s, errCode: %{public}d, errno: %{public}d",
455 BackupFileUtils::GarbleFilePath(fileInfos[i].filePath, sceneCode).c_str(), moveErrCode, errno);
456 UpdateFailedFiles(fileInfos[i].fileType, fileInfos[i], RestoreError::MOVE_FAILED);
457 continue;
458 }
459 BackupFileUtils::ModifyFile(dstPath, fileInfos[i].dateModified / MSEC_TO_SEC);
460 fileMoveCount++;
461 }
462 migrateAudioFileNumber_ += fileMoveCount;
463 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
464 MEDIA_INFO_LOG("move %{public}ld file cost %{public}ld.", (long)fileMoveCount, (long)(end - startMove));
465 }
466
MoveExtraData(const FileInfo & fileInfo,int32_t sceneCode)467 static bool MoveExtraData(const FileInfo &fileInfo, int32_t sceneCode)
468 {
469 string localExtraDataDir = BackupFileUtils::GetReplacedPathByPrefixType(
470 PrefixType::CLOUD, PrefixType::LOCAL, MovingPhotoFileUtils::GetMovingPhotoExtraDataDir(fileInfo.cloudPath));
471 if (localExtraDataDir.empty()) {
472 MEDIA_WARN_LOG("Failed to get local extra data dir");
473 return false;
474 }
475 if (!MediaFileUtils::IsFileExists(localExtraDataDir) && !MediaFileUtils::CreateDirectory(localExtraDataDir)) {
476 MEDIA_WARN_LOG("Failed to create local extra data dir, errno:%{public}d", errno);
477 return false;
478 }
479
480 string localExtraDataPath = BackupFileUtils::GetReplacedPathByPrefixType(
481 PrefixType::CLOUD, PrefixType::LOCAL, MovingPhotoFileUtils::GetMovingPhotoExtraDataPath(fileInfo.cloudPath));
482 if (localExtraDataPath.empty()) {
483 MEDIA_WARN_LOG("Failed to get local extra data path");
484 return false;
485 }
486 int32_t errCode = BackupFileUtils::MoveFile(fileInfo.extraDataPath, localExtraDataPath, sceneCode);
487 if (errCode != E_OK) {
488 MEDIA_WARN_LOG("MoveFile failed, src:%{public}s, dest:%{public}s, err:%{public}d, errno:%{public}d",
489 BackupFileUtils::GarbleFilePath(fileInfo.extraDataPath, sceneCode).c_str(),
490 BackupFileUtils::GarbleFilePath(localExtraDataPath, sceneCode).c_str(), errCode, errno);
491 return false;
492 }
493 return true;
494 }
495
MoveAndModifyFile(const FileInfo & fileInfo,int32_t sceneCode)496 static bool MoveAndModifyFile(const FileInfo &fileInfo, int32_t sceneCode)
497 {
498 string tmpPath = fileInfo.cloudPath;
499 string localPath = tmpPath.replace(0, RESTORE_CLOUD_DIR.length(), RESTORE_LOCAL_DIR);
500 int32_t errCode = BackupFileUtils::MoveFile(fileInfo.filePath, localPath, sceneCode);
501 if (errCode != E_OK) {
502 MEDIA_ERR_LOG("MoveFile failed, src:%{public}s, dest:%{public}s, err:%{public}d, errno:%{public}d",
503 BackupFileUtils::GarbleFilePath(fileInfo.filePath, sceneCode).c_str(),
504 BackupFileUtils::GarbleFilePath(localPath, sceneCode).c_str(), errCode, errno);
505 return false;
506 }
507 BackupFileUtils::ModifyFile(localPath, fileInfo.dateModified / MSEC_TO_SEC);
508
509 if (BackupFileUtils::IsLivePhoto(fileInfo)) {
510 string tmpVideoPath = MovingPhotoFileUtils::GetMovingPhotoVideoPath(fileInfo.cloudPath);
511 string localVideoPath = tmpVideoPath.replace(0, RESTORE_CLOUD_DIR.length(), RESTORE_LOCAL_DIR);
512 errCode = BackupFileUtils::MoveFile(fileInfo.movingPhotoVideoPath, localVideoPath, sceneCode);
513 if (errCode != E_OK) {
514 MEDIA_ERR_LOG(
515 "MoveFile failed for mov video, src:%{public}s, dest:%{public}s, err:%{public}d, errno:%{public}d",
516 BackupFileUtils::GarbleFilePath(fileInfo.movingPhotoVideoPath, sceneCode).c_str(),
517 BackupFileUtils::GarbleFilePath(localVideoPath, sceneCode).c_str(), errCode, errno);
518 (void)MediaFileUtils::DeleteFile(localPath);
519 return false;
520 }
521 BackupFileUtils::ModifyFile(localVideoPath, fileInfo.dateModified / MSEC_TO_SEC);
522 return MoveExtraData(fileInfo, sceneCode);
523 }
524 return true;
525 }
526
MoveMigrateFile(std::vector<FileInfo> & fileInfos,int32_t & fileMoveCount,int32_t & videoFileMoveCount,int32_t sceneCode)527 void BaseRestore::MoveMigrateFile(std::vector<FileInfo> &fileInfos, int32_t &fileMoveCount, int32_t &videoFileMoveCount,
528 int32_t sceneCode)
529 {
530 vector<std::string> moveFailedData;
531 for (size_t i = 0; i < fileInfos.size(); i++) {
532 if (!fileInfos[i].needMove) {
533 continue;
534 }
535 if (IsFileValid(fileInfos[i], sceneCode) != E_OK) {
536 continue;
537 }
538 if (!MoveAndModifyFile(fileInfos[i], sceneCode)) {
539 fileInfos[i].updateMap.clear();
540 UpdateFailedFiles(fileInfos[i].fileType, fileInfos[i], RestoreError::MOVE_FAILED);
541 ErrorInfo errorInfo(RestoreError::MOVE_FAILED, 1, strerror(errno),
542 BackupLogUtils::FileInfoToString(sceneCode, fileInfos[i]));
543 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
544 moveFailedData.push_back(fileInfos[i].cloudPath);
545 continue;
546 }
547 fileMoveCount++;
548 videoFileMoveCount += fileInfos[i].fileType == MediaType::MEDIA_TYPE_VIDEO;
549 }
550 DeleteMoveFailedData(moveFailedData);
551 migrateFileNumber_ += fileMoveCount;
552 migrateVideoFileNumber_ += videoFileMoveCount;
553 }
554
InsertPhoto(int32_t sceneCode,std::vector<FileInfo> & fileInfos,int32_t sourceType)555 int BaseRestore::InsertPhoto(int32_t sceneCode, std::vector<FileInfo> &fileInfos, int32_t sourceType)
556 {
557 MEDIA_INFO_LOG("Start insert %{public}zu photos", fileInfos.size());
558 if (mediaLibraryRdb_ == nullptr) {
559 MEDIA_ERR_LOG("mediaLibraryRdb_ is null");
560 return E_OK;
561 }
562 if (fileInfos.empty()) {
563 MEDIA_ERR_LOG("fileInfos are empty");
564 return E_OK;
565 }
566 int64_t startGenerate = MediaFileUtils::UTCTimeMilliSeconds();
567 vector<NativeRdb::ValuesBucket> values = GetInsertValues(sceneCode, fileInfos, sourceType);
568 int64_t startInsert = MediaFileUtils::UTCTimeMilliSeconds();
569 int64_t rowNum = 0;
570 int32_t errCode = BatchInsertWithRetry(PhotoColumn::PHOTOS_TABLE, values, rowNum);
571 if (errCode != E_OK) {
572 if (needReportFailed_) {
573 UpdateFailedFiles(fileInfos, RestoreError::INSERT_FAILED);
574 ErrorInfo errorInfo(RestoreError::INSERT_FAILED, static_cast<int32_t>(fileInfos.size()), errCode);
575 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
576 }
577 return errCode;
578 }
579
580 int64_t startInsertRelated = MediaFileUtils::UTCTimeMilliSeconds();
581 InsertPhotoRelated(fileInfos, sourceType);
582
583 int64_t startMove = MediaFileUtils::UTCTimeMilliSeconds();
584 migrateDatabaseNumber_ += rowNum;
585 int32_t fileMoveCount = 0;
586 int32_t videoFileMoveCount = 0;
587 MoveMigrateFile(fileInfos, fileMoveCount, videoFileMoveCount, sceneCode);
588 this->tabOldPhotosRestore_.Restore(this->mediaLibraryRdb_, fileInfos);
589 int64_t startUpdate = MediaFileUtils::UTCTimeMilliSeconds();
590 UpdatePhotosByFileInfoMap(mediaLibraryRdb_, fileInfos);
591 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
592 MEDIA_INFO_LOG("generate values cost %{public}ld, insert %{public}ld assets cost %{public}ld, insert photo related"
593 " cost %{public}ld, and move %{public}ld files (%{public}ld + %{public}ld) cost %{public}ld. update cost"
594 " %{public}ld.",
595 (long)(startInsert - startGenerate), (long)rowNum, (long)(startInsertRelated - startInsert),
596 (long)(startMove - startInsertRelated), (long)fileMoveCount, (long)(fileMoveCount - videoFileMoveCount),
597 (long)videoFileMoveCount, (long)(startUpdate - startMove), long(end - startUpdate));
598 return E_OK;
599 }
600
DeleteMoveFailedData(std::vector<std::string> & moveFailedData)601 void BaseRestore::DeleteMoveFailedData(std::vector<std::string> &moveFailedData)
602 {
603 if (moveFailedData.empty()) {
604 MEDIA_INFO_LOG("No move failed");
605 return;
606 }
607 MEDIA_INFO_LOG("%{public}d file move failed", static_cast<int>(moveFailedData.size()));
608 NativeRdb::AbsRdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
609 predicates.In(MediaColumn::MEDIA_FILE_PATH, moveFailedData);
610 int32_t changedRows = 0;
611 int deleteRes = BackupDatabaseUtils::Delete(predicates, changedRows, mediaLibraryRdb_);
612 MEDIA_INFO_LOG("changeRows:%{public}d, deleteRes:%{public}d", changedRows, deleteRes);
613 }
614
BatchInsertWithRetry(const std::string & tableName,std::vector<NativeRdb::ValuesBucket> & values,int64_t & rowNum)615 int32_t BaseRestore::BatchInsertWithRetry(const std::string &tableName, std::vector<NativeRdb::ValuesBucket> &values,
616 int64_t &rowNum)
617 {
618 if (values.empty()) {
619 return 0;
620 }
621
622 int32_t errCode = E_ERR;
623 TransactionOperations trans{ __func__ };
624 trans.SetBackupRdbStore(mediaLibraryRdb_);
625 std::function<int(void)> func = [&]()->int {
626 errCode = trans.BatchInsert(rowNum, tableName, values);
627 if (errCode != E_OK) {
628 MEDIA_ERR_LOG("InsertSql failed, errCode: %{public}d, rowNum: %{public}ld.", errCode, (long)rowNum);
629 }
630 return errCode;
631 };
632 errCode = trans.RetryTrans(func, true);
633 if (errCode != E_OK) {
634 MEDIA_ERR_LOG("BatchInsertWithRetry: tans finish fail!, ret:%{public}d", errCode);
635 }
636 return errCode;
637 }
638
MoveDirectory(const std::string & srcDir,const std::string & dstDir,bool deleteOriginalFile) const639 int32_t BaseRestore::MoveDirectory(const std::string &srcDir, const std::string &dstDir, bool deleteOriginalFile) const
640 {
641 if (!MediaFileUtils::CreateDirectory(dstDir)) {
642 MEDIA_ERR_LOG("Create dstDir %{public}s failed",
643 BackupFileUtils::GarbleFilePath(dstDir, DEFAULT_RESTORE_ID).c_str());
644 return E_FAIL;
645 }
646 if (!MediaFileUtils::IsFileExists(srcDir)) {
647 MEDIA_WARN_LOG("%{public}s doesn't exist, skip.", srcDir.c_str());
648 return E_OK;
649 }
650 for (const auto &dirEntry : std::filesystem::directory_iterator{ srcDir }) {
651 std::string srcFilePath = dirEntry.path();
652 std::string tmpFilePath = srcFilePath;
653 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
654 int32_t opRet = E_FAIL;
655 if (deleteOriginalFile) {
656 opRet = this->MoveFile(srcFilePath, dstFilePath);
657 } else {
658 opRet = this->CopyFile(srcFilePath, dstFilePath);
659 }
660 if (opRet != E_OK) {
661 MEDIA_ERR_LOG("Move file from %{public}s to %{public}s failed, deleteOriginalFile=%{public}d",
662 BackupFileUtils::GarbleFilePath(srcFilePath, sceneCode_).c_str(),
663 BackupFileUtils::GarbleFilePath(dstFilePath, DEFAULT_RESTORE_ID).c_str(),
664 deleteOriginalFile);
665 return E_FAIL;
666 }
667 }
668 return E_OK;
669 }
670
IsSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName,FileInfo & fileInfo)671 bool BaseRestore::IsSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName,
672 FileInfo &fileInfo)
673 {
674 string srcPath = fileInfo.filePath;
675 string dstPath = BackupFileUtils::GetFullPathByPrefixType(PrefixType::LOCAL, fileInfo.relativePath);
676 struct stat srcStatInfo {};
677 struct stat dstStatInfo {};
678
679 if (access(dstPath.c_str(), F_OK)) {
680 return false;
681 }
682 if (stat(srcPath.c_str(), &srcStatInfo) != 0) {
683 MEDIA_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", srcPath.c_str(), errno);
684 return false;
685 }
686 if (stat(dstPath.c_str(), &dstStatInfo) != 0) {
687 MEDIA_ERR_LOG("Failed to get file %{private}s StatInfo, err=%{public}d", dstPath.c_str(), errno);
688 return false;
689 }
690 if ((srcStatInfo.st_size != dstStatInfo.st_size || srcStatInfo.st_mtime != dstStatInfo.st_mtime) &&
691 !HasSameAudioFile(rdbStore, tableName, fileInfo)) { /* file size & last modify time */
692 MEDIA_INFO_LOG("Size (%{public}lld -> %{public}lld) or mtime (%{public}lld -> %{public}lld) differs",
693 (long long)srcStatInfo.st_size, (long long)dstStatInfo.st_size, (long long)srcStatInfo.st_mtime,
694 (long long)dstStatInfo.st_mtime);
695 return false;
696 }
697 fileInfo.isNew = false;
698 return true;
699 }
700
HasSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> & rdbStore,const std::string & tableName,FileInfo & fileInfo)701 bool BaseRestore::HasSameAudioFile(const std::shared_ptr<NativeRdb::RdbStore> &rdbStore, const std::string &tableName,
702 FileInfo &fileInfo)
703 {
704 string querySql = "SELECT " + MediaColumn::MEDIA_ID + ", " + MediaColumn::MEDIA_FILE_PATH + " FROM " +
705 tableName + " WHERE " + MediaColumn::MEDIA_NAME + " = '" + fileInfo.displayName + "' AND " +
706 MediaColumn::MEDIA_SIZE + " = " + to_string(fileInfo.fileSize) + " AND " +
707 MediaColumn::MEDIA_DATE_MODIFIED + " = " + to_string(fileInfo.dateModified);
708 querySql += " LIMIT 1";
709 auto resultSet = BackupDatabaseUtils::GetQueryResultSet(rdbStore, querySql);
710 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
711 return false;
712 }
713 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
714 string cloudPath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
715 if (fileId <= 0 || cloudPath.empty()) {
716 return false;
717 }
718 fileInfo.fileIdNew = fileId;
719 fileInfo.cloudPath = cloudPath;
720 return true;
721 }
722
InsertPhotoMap(std::vector<FileInfo> & fileInfos,int64_t & mapRowNum)723 void BaseRestore::InsertPhotoMap(std::vector<FileInfo> &fileInfos, int64_t &mapRowNum)
724 {
725 BatchInsertMap(fileInfos, mapRowNum);
726 migrateDatabaseMapNumber_ += mapRowNum;
727 }
728
BatchQueryPhoto(vector<FileInfo> & fileInfos,bool isFull,const NeedQueryMap & needQueryMap)729 void BaseRestore::BatchQueryPhoto(vector<FileInfo> &fileInfos, bool isFull, const NeedQueryMap &needQueryMap)
730 {
731 string querySql = "SELECT " + MediaColumn::MEDIA_ID + " , " + MediaColumn::MEDIA_FILE_PATH + " FROM " +
732 PhotoColumn::PHOTOS_TABLE + " WHERE ";
733 bool firstSql = false;
734 std::vector<std::string> cloudPathArgs;
735 for (auto &fileInfo : fileInfos) {
736 if (!isFull && !NeedQuery(fileInfo, needQueryMap)) {
737 continue;
738 }
739 if (firstSql) {
740 querySql += " OR ";
741 } else {
742 firstSql = true;
743 }
744 querySql += MediaColumn::MEDIA_FILE_PATH + " = ? ";
745 cloudPathArgs.push_back(fileInfo.cloudPath);
746 }
747 auto result = BackupDatabaseUtils::GetQueryResultSet(mediaLibraryRdb_, querySql, cloudPathArgs);
748 if (result == nullptr) {
749 MEDIA_ERR_LOG("Query resultSql is null.");
750 return;
751 }
752 while (result->GoToNextRow() == NativeRdb::E_OK) {
753 int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, result);
754 std::string path = GetStringVal(MediaColumn::MEDIA_FILE_PATH, result);
755 auto pathMatch = [path {path}](const auto &fileInfo) {
756 return fileInfo.cloudPath == path;
757 };
758 auto it = std::find_if(fileInfos.begin(), fileInfos.end(), pathMatch);
759 if (it != fileInfos.end() && fileId > 0) {
760 it->fileIdNew = fileId;
761 }
762 }
763 }
764
BatchInsertMap(const vector<FileInfo> & fileInfos,int64_t & totalRowNum)765 void BaseRestore::BatchInsertMap(const vector<FileInfo> &fileInfos, int64_t &totalRowNum)
766 {
767 vector<NativeRdb::ValuesBucket> values;
768 for (const auto &fileInfo : fileInfos) {
769 if (!fileInfo.packageName.empty()) {
770 // add for trigger insert_photo_insert_source_album
771 continue;
772 }
773 if (fileInfo.cloudPath.empty() || fileInfo.mediaAlbumId <= 0 || fileInfo.fileIdNew <= 0) {
774 MEDIA_ERR_LOG("AlbumMap error file name = %{public}s.", fileInfo.displayName.c_str());
775 continue;
776 }
777 NativeRdb::ValuesBucket value;
778 value.PutInt(PhotoMap::ASSET_ID, fileInfo.fileIdNew);
779 value.PutInt(PhotoMap::ALBUM_ID, fileInfo.mediaAlbumId);
780 values.emplace_back(value);
781 }
782 int64_t rowNum = 0;
783 int32_t errCode = BatchInsertWithRetry(PhotoMap::TABLE, values, rowNum);
784 if (errCode != E_OK) {
785 MEDIA_ERR_LOG("Batch insert map failed, errCode: %{public}d", errCode);
786 }
787 totalRowNum += rowNum;
788 }
789
StartRestoreEx(const std::string & backupRetoreDir,const std::string & upgradePath,std::string & restoreExInfo)790 void BaseRestore::StartRestoreEx(const std::string &backupRetoreDir, const std::string &upgradePath,
791 std::string &restoreExInfo)
792 {
793 UpgradeRestoreTaskReport()
794 .SetSceneCode(this->sceneCode_)
795 .SetTaskId(this->taskId_)
796 .ReportProgress("start", std::to_string(MediaFileUtils::UTCTimeSeconds()));
797 StartRestore(backupRetoreDir, upgradePath);
798 DatabaseReport()
799 .SetSceneCode(this->sceneCode_)
800 .SetTaskId(this->taskId_)
801 .ReportMedia(this->mediaLibraryRdb_, DatabaseReport::PERIOD_AFTER);
802 restoreExInfo = GetRestoreExInfo();
803 UpgradeRestoreTaskReport()
804 .SetSceneCode(this->sceneCode_)
805 .SetTaskId(this->taskId_)
806 .ReportTask(restoreExInfo)
807 .ReportTotal(std::to_string(errorCode_), GetRestoreTotalInfo())
808 .ReportTimeCost()
809 .ReportProgress("end", std::to_string(MediaFileUtils::UTCTimeSeconds()));
810 }
811
GetRestoreExInfo()812 std::string BaseRestore::GetRestoreExInfo()
813 {
814 nlohmann::json restoreExInfoJson;
815 restoreExInfoJson[STAT_KEY_RESULT_INFO] = { GetErrorInfoJson(), GetCountInfoJson(STAT_TYPES) };
816 return restoreExInfoJson.dump();
817 }
818
GetErrorInfoJson()819 nlohmann::json BaseRestore::GetErrorInfoJson()
820 {
821 int32_t errorCode = errorCode_ == RestoreError::SUCCESS ? STAT_DEFAULT_ERROR_CODE_SUCCESS :
822 STAT_DEFAULT_ERROR_CODE_FAILED;
823 nlohmann::json errorInfoJson = {
824 { STAT_KEY_TYPE, STAT_VALUE_ERROR_INFO },
825 { STAT_KEY_ERROR_CODE, std::to_string(errorCode) },
826 { STAT_KEY_ERROR_INFO, errorInfo_ }
827 };
828 return errorInfoJson;
829 }
830
GetCountInfoJson(const std::vector<std::string> & countInfoTypes)831 nlohmann::json BaseRestore::GetCountInfoJson(const std::vector<std::string> &countInfoTypes)
832 {
833 nlohmann::json countInfoJson;
834 countInfoJson[STAT_KEY_TYPE] = STAT_VALUE_COUNT_INFO;
835 size_t limit = MAX_FAILED_FILES_LIMIT;
836 for (const auto &type : countInfoTypes) {
837 SubCountInfo subCountInfo = GetSubCountInfo(type);
838 MEDIA_INFO_LOG("SubCountInfo %{public}s success: %{public}lld, duplicate: %{public}lld, failed: %{public}zu",
839 type.c_str(), (long long)subCountInfo.successCount, (long long)subCountInfo.duplicateCount,
840 subCountInfo.failedFiles.size());
841 countInfoJson[STAT_KEY_INFOS].push_back(GetSubCountInfoJson(type, subCountInfo, limit));
842 }
843 return countInfoJson;
844 }
845
GetSubCountInfo(const std::string & type)846 SubCountInfo BaseRestore::GetSubCountInfo(const std::string &type)
847 {
848 std::unordered_map<std::string, FailedFileInfo> failedFiles = GetFailedFiles(type);
849 if (type == STAT_TYPE_PHOTO) {
850 return SubCountInfo(migrateFileNumber_ - migrateVideoFileNumber_, migratePhotoDuplicateNumber_, failedFiles);
851 }
852 if (type == STAT_TYPE_VIDEO) {
853 return SubCountInfo(migrateVideoFileNumber_, migrateVideoDuplicateNumber_, failedFiles);
854 }
855 return SubCountInfo(migrateAudioFileNumber_, migrateAudioDuplicateNumber_, failedFiles);
856 }
857
GetFailedFiles(const std::string & type)858 std::unordered_map<std::string, FailedFileInfo> BaseRestore::GetFailedFiles(const std::string &type)
859 {
860 std::lock_guard<mutex> lock(failedFilesMutex_);
861 std::unordered_map<std::string, FailedFileInfo> failedFiles;
862 auto iter = failedFilesMap_.find(type);
863 if (iter != failedFilesMap_.end()) {
864 return iter->second;
865 }
866 return failedFiles;
867 }
868
GetSubCountInfoJson(const std::string & type,const SubCountInfo & subCountInfo,size_t & limit)869 nlohmann::json BaseRestore::GetSubCountInfoJson(const std::string &type, const SubCountInfo &subCountInfo,
870 size_t &limit)
871 {
872 nlohmann::json subCountInfoJson;
873 subCountInfoJson[STAT_KEY_BACKUP_INFO] = type;
874 subCountInfoJson[STAT_KEY_SUCCESS_COUNT] = subCountInfo.successCount;
875 subCountInfoJson[STAT_KEY_DUPLICATE_COUNT] = subCountInfo.duplicateCount;
876 subCountInfoJson[STAT_KEY_FAILED_COUNT] = subCountInfo.failedFiles.size();
877 // update currentLimit = min(limit, failedFiles.size())
878 size_t currentLimit = limit <= subCountInfo.failedFiles.size() ? limit : subCountInfo.failedFiles.size();
879 std::string detailsPath;
880 std::vector<std::string> failedFilesList;
881 if (sceneCode_ == UPGRADE_RESTORE_ID) {
882 detailsPath = BackupFileUtils::GetDetailsPath(DEFAULT_RESTORE_ID, type, subCountInfo.failedFiles, currentLimit);
883 subCountInfoJson[STAT_KEY_DETAILS] = detailsPath;
884 } else {
885 failedFilesList = BackupFileUtils::GetFailedFilesList(DEFAULT_RESTORE_ID, subCountInfo.failedFiles,
886 currentLimit);
887 subCountInfoJson[STAT_KEY_DETAILS] = failedFilesList;
888 }
889 MEDIA_INFO_LOG("Get %{public}s details size: %{public}zu", type.c_str(), currentLimit);
890 limit -= currentLimit; // update total limit
891 return subCountInfoJson;
892 }
893
GetBackupInfo()894 std::string BaseRestore::GetBackupInfo()
895 {
896 return "";
897 }
898
SetErrorCode(int32_t errorCode)899 void BaseRestore::SetErrorCode(int32_t errorCode)
900 {
901 errorCode_ = errorCode;
902 errorInfo_ = BackupLogUtils::RestoreErrorToString(errorCode);
903 }
904
UpdateFailedFileByFileType(int32_t fileType,const FileInfo & fileInfo,int32_t errorCode)905 void BaseRestore::UpdateFailedFileByFileType(int32_t fileType, const FileInfo &fileInfo, int32_t errorCode)
906 {
907 std::lock_guard<mutex> lock(failedFilesMutex_);
908 FailedFileInfo failedFileInfo(sceneCode_, fileInfo, errorCode);
909 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) {
910 failedFilesMap_[STAT_TYPE_PHOTO].emplace(fileInfo.oldPath, failedFileInfo);
911 return;
912 }
913 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO)) {
914 failedFilesMap_[STAT_TYPE_VIDEO].emplace(fileInfo.oldPath, failedFileInfo);
915 return;
916 }
917 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_AUDIO)) {
918 failedFilesMap_[STAT_TYPE_AUDIO].emplace(fileInfo.oldPath, failedFileInfo);
919 return;
920 }
921 MEDIA_ERR_LOG("Unsupported file type: %{public}d", fileType);
922 }
923
UpdateFailedFiles(int32_t fileType,const FileInfo & fileInfo,int32_t errorCode)924 void BaseRestore::UpdateFailedFiles(int32_t fileType, const FileInfo &fileInfo, int32_t errorCode)
925 {
926 SetErrorCode(errorCode);
927 UpdateFailedFileByFileType(fileType, fileInfo, errorCode);
928 }
929
UpdateFailedFiles(const std::vector<FileInfo> & fileInfos,int32_t errorCode)930 void BaseRestore::UpdateFailedFiles(const std::vector<FileInfo> &fileInfos, int32_t errorCode)
931 {
932 SetErrorCode(errorCode);
933 for (const auto &fileInfo : fileInfos) {
934 UpdateFailedFileByFileType(fileInfo.fileType, fileInfo, errorCode);
935 }
936 }
937
UpdateDuplicateNumber(int32_t fileType)938 void BaseRestore::UpdateDuplicateNumber(int32_t fileType)
939 {
940 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE)) {
941 migratePhotoDuplicateNumber_++;
942 return;
943 }
944 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_VIDEO)) {
945 migrateVideoDuplicateNumber_++;
946 return;
947 }
948 if (fileType == static_cast<int32_t>(MediaType::MEDIA_TYPE_AUDIO)) {
949 migrateAudioDuplicateNumber_++;
950 return;
951 }
952 MEDIA_ERR_LOG("Unsupported file type: %{public}d", fileType);
953 }
954
SetParameterForClone()955 void BaseRestore::SetParameterForClone()
956 {
957 auto currentTime = to_string(MediaFileUtils::UTCTimeSeconds());
958 MEDIA_INFO_LOG("SetParameterForClone currentTime:%{public}s", currentTime.c_str());
959 bool retFlag = system::SetParameter(CLONE_FLAG, currentTime);
960 if (!retFlag) {
961 MEDIA_ERR_LOG("Failed to set parameter cloneFlag, retFlag:%{public}d", retFlag);
962 }
963 }
964
StopParameterForClone(int32_t sceneCode)965 void BaseRestore::StopParameterForClone(int32_t sceneCode)
966 {
967 bool retFlag = system::SetParameter(CLONE_FLAG, "0");
968 if (!retFlag) {
969 MEDIA_ERR_LOG("Failed to set parameter cloneFlag, retFlag:%{public}d", retFlag);
970 }
971 }
972
InsertPhotoRelated(std::vector<FileInfo> & fileInfos,int32_t sourceType)973 void BaseRestore::InsertPhotoRelated(std::vector<FileInfo> &fileInfos, int32_t sourceType)
974 {
975 if (sourceType != SourceType::GALLERY) {
976 return;
977 }
978 NeedQueryMap needQueryMap;
979 if (!NeedBatchQueryPhoto(fileInfos, needQueryMap)) {
980 MEDIA_INFO_LOG("There is no need to batch query photo");
981 return;
982 }
983 int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
984 BatchQueryPhoto(fileInfos, false, needQueryMap);
985 int64_t startInsertMap = MediaFileUtils::UTCTimeMilliSeconds();
986 int64_t mapRowNum = 0;
987 InsertPhotoMap(fileInfos, mapRowNum);
988 int64_t startInsertPortrait = MediaFileUtils::UTCTimeMilliSeconds();
989 int64_t faceRowNum = 0;
990 int64_t portraitMapRowNum = 0;
991 int64_t portraitPhotoNum = 0;
992 InsertFaceAnalysisData(fileInfos, needQueryMap, faceRowNum, portraitMapRowNum, portraitPhotoNum);
993 int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
994 MEDIA_INFO_LOG("query cost %{public}ld, insert %{public}ld maps cost %{public}ld, insert face analysis data of "
995 "%{public}ld photos (%{public}ld faces + %{public}ld maps) cost %{public}ld",
996 (long)(startInsertMap - startQuery), (long)mapRowNum, (long)(startInsertPortrait - startInsertMap),
997 (long)portraitPhotoNum, (long)faceRowNum, (long)portraitMapRowNum, (long)(end - startInsertPortrait));
998 }
999
NeedBatchQueryPhoto(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)1000 bool BaseRestore::NeedBatchQueryPhoto(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
1001 {
1002 return NeedBatchQueryPhotoForPhotoMap(fileInfos, needQueryMap) ||
1003 NeedBatchQueryPhotoForPortrait(fileInfos, needQueryMap);
1004 }
1005
NeedBatchQueryPhotoForPhotoMap(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)1006 bool BaseRestore::NeedBatchQueryPhotoForPhotoMap(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
1007 {
1008 std::unordered_set<std::string> needQuerySet;
1009 for (const auto &fileInfo : fileInfos) {
1010 if (!fileInfo.packageName.empty()) {
1011 continue;
1012 }
1013 if (fileInfo.cloudPath.empty() || fileInfo.mediaAlbumId <= 0) {
1014 MEDIA_ERR_LOG("Album error file name = %{public}s.", fileInfo.displayName.c_str());
1015 continue;
1016 }
1017 needQuerySet.insert(fileInfo.cloudPath);
1018 }
1019 if (needQuerySet.empty()) {
1020 return false;
1021 }
1022 needQueryMap[PhotoRelatedType::PHOTO_MAP] = needQuerySet;
1023 return true;
1024 }
1025
NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> & fileInfos,NeedQueryMap & needQueryMap)1026 bool BaseRestore::NeedBatchQueryPhotoForPortrait(const std::vector<FileInfo> &fileInfos, NeedQueryMap &needQueryMap)
1027 {
1028 return false;
1029 }
1030
NeedQuery(const FileInfo & fileInfo,const NeedQueryMap & needQueryMap)1031 bool BaseRestore::NeedQuery(const FileInfo &fileInfo, const NeedQueryMap &needQueryMap)
1032 {
1033 for (auto iter = needQueryMap.begin(); iter != needQueryMap.end(); ++iter) {
1034 if (NeedQueryByPhotoRelatedType(fileInfo, iter->first, iter->second)) {
1035 return true;
1036 }
1037 }
1038 return false;
1039 }
1040
NeedQueryByPhotoRelatedType(const FileInfo & fileInfo,PhotoRelatedType photoRelatedType,const std::unordered_set<std::string> & needQuerySet)1041 bool BaseRestore::NeedQueryByPhotoRelatedType(const FileInfo &fileInfo, PhotoRelatedType photoRelatedType,
1042 const std::unordered_set<std::string> &needQuerySet)
1043 {
1044 std::string searchPath;
1045 switch (photoRelatedType) {
1046 case PhotoRelatedType::PHOTO_MAP: {
1047 searchPath = fileInfo.cloudPath;
1048 break;
1049 }
1050 case PhotoRelatedType::PORTRAIT: {
1051 searchPath = fileInfo.hashCode;
1052 break;
1053 }
1054 default:
1055 MEDIA_ERR_LOG("Unsupported photo related type: %{public}d", static_cast<int32_t>(photoRelatedType));
1056 }
1057 return !searchPath.empty() && needQuerySet.count(searchPath) > 0;
1058 }
1059
InsertFaceAnalysisData(const std::vector<FileInfo> & fileInfos,const NeedQueryMap & needQueryMap,int64_t & faceRowNum,int64_t & mapRowNum,int64_t & photoNum)1060 void BaseRestore::InsertFaceAnalysisData(const std::vector<FileInfo> &fileInfos, const NeedQueryMap &needQueryMap,
1061 int64_t &faceRowNum, int64_t &mapRowNum, int64_t &photoNum)
1062 {
1063 return;
1064 }
1065
ReportPortraitStat(int32_t sceneCode)1066 void BaseRestore::ReportPortraitStat(int32_t sceneCode)
1067 {
1068 MEDIA_INFO_LOG("PortraitStat: album %{public}zu, photo %{public}lld, face %{public}lld, cost %{public}lld",
1069 portraitAlbumIdMap_.size(), (long long)migratePortraitPhotoNumber_, (long long)migratePortraitFaceNumber_,
1070 (long long)migratePortraitTotalTimeCost_);
1071 BackupDfxUtils::PostPortraitStat(static_cast<uint32_t>(portraitAlbumIdMap_.size()), migratePortraitPhotoNumber_,
1072 migratePortraitFaceNumber_, migratePortraitTotalTimeCost_);
1073 }
1074
GetUniqueId(int32_t fileType)1075 int32_t BaseRestore::GetUniqueId(int32_t fileType)
1076 {
1077 int32_t uniqueId = -1;
1078 switch (fileType) {
1079 case MediaType::MEDIA_TYPE_IMAGE: {
1080 lock_guard<mutex> lock(imageMutex_);
1081 uniqueId = static_cast<int32_t>(imageNumber_);
1082 imageNumber_++;
1083 break;
1084 }
1085 case MediaType::MEDIA_TYPE_VIDEO: {
1086 lock_guard<mutex> lock(videoMutex_);
1087 uniqueId = static_cast<int32_t>(videoNumber_);
1088 videoNumber_++;
1089 break;
1090 }
1091 case MediaType::MEDIA_TYPE_AUDIO: {
1092 lock_guard<mutex> lock(audioMutex_);
1093 uniqueId = static_cast<int32_t>(audioNumber_);
1094 audioNumber_++;
1095 break;
1096 }
1097 default:
1098 MEDIA_ERR_LOG("Unsupported file type: %{public}d", fileType);
1099 }
1100 return uniqueId;
1101 }
1102
GetProgressInfo()1103 std::string BaseRestore::GetProgressInfo()
1104 {
1105 nlohmann::json progressInfoJson;
1106 for (const auto &type : STAT_PROGRESS_TYPES) {
1107 SubProcessInfo subProcessInfo = GetSubProcessInfo(type);
1108 progressInfoJson[STAT_KEY_PROGRESS_INFO].push_back(GetSubProcessInfoJson(type, subProcessInfo));
1109 }
1110 std::string progressInfo = progressInfoJson.dump();
1111 UpgradeRestoreTaskReport()
1112 .SetSceneCode(this->sceneCode_)
1113 .SetTaskId(this->taskId_)
1114 .ReportProgress("onProcess", progressInfo, ongoingTotalNumber_.load())
1115 .ReportTimeout(ongoingTotalNumber_.load());
1116 return progressInfo;
1117 }
1118
GetSubProcessInfo(const std::string & type)1119 SubProcessInfo BaseRestore::GetSubProcessInfo(const std::string &type)
1120 {
1121 uint64_t success = 0;
1122 uint64_t duplicate = 0;
1123 uint64_t failed = 0;
1124 uint64_t total = 0;
1125 if (type == STAT_TYPE_PHOTO_VIDEO) {
1126 success = migrateFileNumber_;
1127 duplicate = migratePhotoDuplicateNumber_ + migrateVideoDuplicateNumber_;
1128 failed = static_cast<uint64_t>(GetFailedFiles(STAT_TYPE_PHOTO).size() + GetFailedFiles(STAT_TYPE_VIDEO).size());
1129 total = totalNumber_;
1130 } else if (type == STAT_TYPE_AUDIO) {
1131 success = migrateAudioFileNumber_;
1132 duplicate = migrateAudioDuplicateNumber_;
1133 failed = static_cast<uint64_t>(GetFailedFiles(type).size());
1134 total = audioTotalNumber_;
1135 } else if (type == STAT_TYPE_UPDATE) {
1136 UpdateProcessedNumber(updateProcessStatus_, updateProcessedNumber_, updateTotalNumber_);
1137 success = updateProcessedNumber_;
1138 total = updateTotalNumber_;
1139 } else if (type == STAT_TYPE_OTHER) {
1140 UpdateProcessedNumber(otherProcessStatus_, otherProcessedNumber_, otherTotalNumber_);
1141 success = otherProcessedNumber_;
1142 total = otherTotalNumber_;
1143 } else {
1144 ongoingTotalNumber_++;
1145 success = ongoingTotalNumber_;
1146 total = ongoingTotalNumber_; // make sure progressInfo changes as process goes on
1147 }
1148 uint64_t processed = success + duplicate + failed;
1149 return SubProcessInfo(processed, total);
1150 }
1151
UpdateProcessedNumber(const std::atomic<int32_t> & processStatus,std::atomic<uint64_t> & processedNumber,const std::atomic<uint64_t> & totalNumber)1152 void BaseRestore::UpdateProcessedNumber(const std::atomic<int32_t> &processStatus,
1153 std::atomic<uint64_t> &processedNumber, const std::atomic<uint64_t> &totalNumber)
1154 {
1155 if (processStatus == ProcessStatus::STOP) {
1156 processedNumber = totalNumber.load();
1157 return;
1158 }
1159 processedNumber += processedNumber < totalNumber ? 1 : 0;
1160 }
1161
GetSubProcessInfoJson(const std::string & type,const SubProcessInfo & subProcessInfo)1162 nlohmann::json BaseRestore::GetSubProcessInfoJson(const std::string &type, const SubProcessInfo &subProcessInfo)
1163 {
1164 nlohmann::json subProcessInfoJson;
1165 subProcessInfoJson[STAT_KEY_NAME] = type;
1166 subProcessInfoJson[STAT_KEY_PROCESSED] = subProcessInfo.processed;
1167 subProcessInfoJson[STAT_KEY_TOTAL] = subProcessInfo.total;
1168 subProcessInfoJson[STAT_KEY_IS_PERCENTAGE] = false;
1169 return subProcessInfoJson;
1170 }
1171
UpdateDatabase()1172 void BaseRestore::UpdateDatabase()
1173 {
1174 updateProcessStatus_ = ProcessStatus::START;
1175 GetUpdateTotalCount();
1176 MEDIA_INFO_LOG("Start update all albums");
1177 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1178 MediaLibraryRdbUtils::UpdateAllAlbums(rdbStore);
1179 MEDIA_INFO_LOG("Start update unique number");
1180 BackupDatabaseUtils::UpdateUniqueNumber(mediaLibraryRdb_, imageNumber_, IMAGE_ASSET_TYPE);
1181 BackupDatabaseUtils::UpdateUniqueNumber(mediaLibraryRdb_, videoNumber_, VIDEO_ASSET_TYPE);
1182 BackupDatabaseUtils::UpdateUniqueNumber(mediaLibraryRdb_, audioNumber_, AUDIO_ASSET_TYPE);
1183 MEDIA_INFO_LOG("Start notify");
1184 NotifyAlbum();
1185 updateProcessStatus_ = ProcessStatus::STOP;
1186 }
1187
NotifyAlbum()1188 void BaseRestore::NotifyAlbum()
1189 {
1190 auto watch = MediaLibraryNotify::GetInstance();
1191 if (watch == nullptr) {
1192 MEDIA_ERR_LOG("Can not get MediaLibraryNotify Instance");
1193 return;
1194 }
1195 watch->Notify(PhotoColumn::DEFAULT_PHOTO_URI, NotifyType::NOTIFY_ADD);
1196 watch->Notify(PhotoAlbumColumns::ALBUM_URI_PREFIX, NotifyType::NOTIFY_ADD);
1197 }
1198
GetUpdateTotalCount()1199 void BaseRestore::GetUpdateTotalCount()
1200 {
1201 GetUpdateAllAlbumsCount();
1202 GetUpdateUniqueNumberCount();
1203 }
1204
GetUpdateAllAlbumsCount()1205 void BaseRestore::GetUpdateAllAlbumsCount()
1206 {
1207 const std::vector<std::string> ALBUM_TABLE_LIST = { "PhotoAlbum", "AnalysisAlbum" };
1208 int32_t albumTotalCount = 0;
1209 for (const auto &tableName : ALBUM_TABLE_LIST) {
1210 std::string querySql = "SELECT count(1) as count FROM " + tableName;
1211 albumTotalCount += BackupDatabaseUtils::QueryInt(mediaLibraryRdb_, querySql, CUSTOM_COUNT);
1212 }
1213 updateTotalNumber_ += static_cast<uint64_t>(albumTotalCount);
1214 MEDIA_INFO_LOG("onProcess Update updateTotalNumber_: %{public}lld", (long long)updateTotalNumber_);
1215 }
1216
GetUpdateUniqueNumberCount()1217 void BaseRestore::GetUpdateUniqueNumberCount()
1218 {
1219 updateTotalNumber_ += UNIQUE_NUMBER_NUM;
1220 MEDIA_INFO_LOG("onProcess Update updateTotalNumber_: %{public}lld", (long long)updateTotalNumber_);
1221 }
1222
RestoreThumbnail()1223 void BaseRestore::RestoreThumbnail()
1224 {
1225 // restore thumbnail for date fronted 500 photos
1226 MEDIA_INFO_LOG("Start RestoreThumbnail");
1227 otherProcessStatus_ = ProcessStatus::START;
1228 otherTotalNumber_ += THUMBNAIL_NUM;
1229 MEDIA_INFO_LOG("onProcess Update otherTotalNumber_: %{public}lld", (long long)otherTotalNumber_);
1230 BackupFileUtils::GenerateThumbnailsAfterRestore();
1231 otherProcessStatus_ = ProcessStatus::STOP;
1232 }
1233
StartBackup()1234 void BaseRestore::StartBackup()
1235 {}
1236
CheckInvalidFile(const FileInfo & fileInfo,int32_t errCode)1237 std::string BaseRestore::CheckInvalidFile(const FileInfo &fileInfo, int32_t errCode)
1238 {
1239 return "";
1240 }
1241
GetRestoreTotalInfo()1242 std::string BaseRestore::GetRestoreTotalInfo()
1243 {
1244 std::stringstream restoreTotalInfo;
1245 uint64_t success = migrateFileNumber_;
1246 uint64_t duplicate = migratePhotoDuplicateNumber_ + migrateVideoDuplicateNumber_;
1247 uint64_t failed = static_cast<uint64_t>(GetFailedFiles(STAT_TYPE_PHOTO).size() +
1248 GetFailedFiles(STAT_TYPE_VIDEO).size());
1249 uint64_t error = totalNumber_ - success - duplicate - failed;
1250 restoreTotalInfo << failed;
1251 restoreTotalInfo << ";" << error;
1252 restoreTotalInfo << ";" << GetNoNeedMigrateCount();
1253 return restoreTotalInfo.str();
1254 }
1255
GetNoNeedMigrateCount()1256 int32_t BaseRestore::GetNoNeedMigrateCount()
1257 {
1258 return 0;
1259 }
1260
UpdatePhotosByFileInfoMap(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,const std::vector<FileInfo> & fileInfos)1261 void BaseRestore::UpdatePhotosByFileInfoMap(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb,
1262 const std::vector<FileInfo>& fileInfos)
1263 {
1264 for (const FileInfo &fileInfo : fileInfos) {
1265 auto &updateMap = fileInfo.updateMap;
1266 if (fileInfo.fileIdNew <= 0 || fileInfo.isNew || updateMap.empty()) {
1267 continue;
1268 }
1269 int32_t changeRows = 0;
1270 std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
1271 make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
1272 predicates->SetWhereClause("file_id=?");
1273 predicates->SetWhereArgs({ to_string(fileInfo.fileIdNew) });
1274 NativeRdb::ValuesBucket updatePostBucket;
1275 for (auto it = updateMap.begin(); it != updateMap.end(); it++) {
1276 updatePostBucket.Put(it->first, it->second);
1277 }
1278 BackupDatabaseUtils::Update(mediaLibraryRdb, changeRows, updatePostBucket, predicates);
1279 if (changeRows <= 0) {
1280 MEDIA_ERR_LOG("update failed, fileId: %{public}d", fileInfo.fileIdNew);
1281 ErrorInfo errorInfo(RestoreError::UPDATE_PHOTOS_FAILED, 1, "",
1282 BackupLogUtils::FileInfoToString(this->sceneCode_, fileInfo));
1283 UpgradeRestoreTaskReport().SetSceneCode(this->sceneCode_).SetTaskId(this->taskId_).ReportError(errorInfo);
1284 }
1285 }
1286 }
1287 } // namespace Media
1288 } // namespace OHOS
1289