• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "PhotosDataHandler"
16 
17 #include "photos_data_handler.h"
18 
19 #include <sstream>
20 
21 #include "backup_database_utils.h"
22 #include "backup_file_utils.h"
23 #include "ffrt.h"
24 #include "ffrt_inner.h"
25 #include "media_file_utils.h"
26 #include "upgrade_restore_task_report.h"
27 
28 namespace OHOS::Media {
OnStart(int32_t sceneCode,const std::string & taskId,std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)29 void PhotosDataHandler::OnStart(int32_t sceneCode, const std::string &taskId,
30     std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
31 {
32     SetSceneCode(sceneCode).SetTaskId(taskId).SetMediaLibraryRdb(mediaLibraryRdb);
33 }
34 
SetSceneCode(int32_t sceneCode)35 PhotosDataHandler &PhotosDataHandler::SetSceneCode(int32_t sceneCode)
36 {
37     sceneCode_ = sceneCode;
38     return *this;
39 }
40 
SetTaskId(const std::string & taskId)41 PhotosDataHandler &PhotosDataHandler::SetTaskId(const std::string &taskId)
42 {
43     taskId_ = taskId;
44     return *this;
45 }
46 
SetMediaLibraryRdb(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)47 PhotosDataHandler &PhotosDataHandler::SetMediaLibraryRdb(std::shared_ptr<NativeRdb::RdbStore> mediaLibraryRdb)
48 {
49     mediaLibraryRdb_ = mediaLibraryRdb;
50     photosDao_.SetMediaLibraryRdb(mediaLibraryRdb);
51     return *this;
52 }
53 
HandleDirtyFiles()54 void PhotosDataHandler::HandleDirtyFiles()
55 {
56     int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
57     int32_t totalNumber = photosDao_.GetDirtyFilesCount();
58     MEDIA_INFO_LOG("totalNumber = %{public}d", totalNumber);
59     CHECK_AND_RETURN(totalNumber > 0);
60     ffrt_set_cpu_worker_max_num(ffrt::qos_utility, MAX_THREAD_NUM);
61     int64_t startClean = MediaFileUtils::UTCTimeMilliSeconds();
62     for (int32_t offset = 0; offset < totalNumber; offset += QUERY_COUNT) {
63         ffrt::submit([this, offset]() { HandleDirtyFilesBatch(offset); }, { &offset }, {},
64             ffrt::task_attr().qos(static_cast<int32_t>(ffrt::qos_utility)));
65     }
66     ffrt::wait();
67     int64_t startSetVisible = MediaFileUtils::UTCTimeMilliSeconds();
68     int32_t setCount = PhotosDataHandler::SetVisibleFilesInDb();
69     int64_t startDelete = MediaFileUtils::UTCTimeMilliSeconds();
70     int32_t deleteCount = PhotosDataHandler::DeleteDirtyFilesInDb();
71     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
72     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
73         .Report("HANDLE_DIRTY_FILES", "",
74             "total dirty count: " + std::to_string(totalNumber) +
75             ", query total cost: " + std::to_string(startClean - startQuery) +
76             "; clean files count: " + std::to_string(dirtyFileCleanNumber_) +
77             ", clean files cost: " + std::to_string(startDelete - startClean) +
78             ", failed clean files count: " + std::to_string(failedDirtyFileCleanNumber_) +
79             "; set visible count: " + std::to_string(setCount) +
80             ", update in db cost: " + std::to_string(end - startSetVisible) +
81             "; clean db count: " + std::to_string(deleteCount) +
82             ", delete in db cost: " + std::to_string(end - startDelete));
83 }
84 
HandleDirtyFilesBatch(int32_t offset)85 void PhotosDataHandler::HandleDirtyFilesBatch(int32_t offset)
86 {
87     MEDIA_INFO_LOG("start clean dirty files offset: %{public}d", offset);
88     int64_t startQuery = MediaFileUtils::UTCTimeMilliSeconds();
89     std::vector<PhotosDao::PhotosRowData> dirtyFiles = photosDao_.GetDirtyFiles(offset);
90     int64_t startClean = MediaFileUtils::UTCTimeMilliSeconds();
91     dirtyFileCleanNumber_ += CleanDirtyFiles(dirtyFiles);
92     int64_t end = MediaFileUtils::UTCTimeMilliSeconds();
93     MEDIA_INFO_LOG("query %{public}zu dirty files cost %{public}" PRId64", clean cost %{public}" PRId64,
94         dirtyFiles.size(), startClean - startQuery, end - startClean);
95 }
96 
CleanDirtyFiles(const std::vector<PhotosDao::PhotosRowData> & dirtyFiles)97 int32_t PhotosDataHandler::CleanDirtyFiles(const std::vector<PhotosDao::PhotosRowData> &dirtyFiles)
98 {
99     int32_t count = 0;
100     CHECK_AND_RETURN_RET(!dirtyFiles.empty(), count);
101     for (const auto &dirtyFile : dirtyFiles) {
102         if (ShouldSetVisible(dirtyFile)) {
103             IsFileExist(dirtyFile) ? AddToSetVisibleFiles(dirtyFile) : AddToCleanFailedFiles(dirtyFile);
104             continue;
105         }
106         if (!DeleteDirtyFile(dirtyFile)) {
107             AddToCleanFailedFiles(dirtyFile);
108             continue;
109         }
110         count++;
111     }
112     return count;
113 }
114 
DeleteDirtyFile(const PhotosDao::PhotosRowData & dirtyFile)115 bool PhotosDataHandler::DeleteDirtyFile(const PhotosDao::PhotosRowData &dirtyFile)
116 {
117     // clean cloud path
118     bool deleteFileRet = MediaFileUtils::DeleteFileOrFolder(dirtyFile.data, true);
119     // clean thumbs folder
120     std::string thumbsFolder =
121         BackupFileUtils::GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::CLOUD_THUMB, dirtyFile.data);
122     bool deleteThumbsRet = MediaFileUtils::DeleteFileOrFolder(thumbsFolder, false);
123     if (!deleteFileRet || !deleteThumbsRet) {
124         MEDIA_ERR_LOG("Clean file failed, path: %{public}s, deleteFileRet: %{public}d, deleteThumbsRet: %{public}d,"
125             " errno: %{public}d", BackupFileUtils::GarbleFilePath(dirtyFile.data, DEFAULT_RESTORE_ID).c_str(),
126             static_cast<int32_t>(deleteFileRet), static_cast<int32_t>(deleteThumbsRet), errno);
127         return false;
128     }
129     return true;
130 }
131 
DeleteDirtyFilesInDb()132 int32_t PhotosDataHandler::DeleteDirtyFilesInDb()
133 {
134     // clean database
135     NativeRdb::AbsRdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
136     predicates.EqualTo(PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_BACKUP));
137     predicates.NotIn(MediaColumn::MEDIA_ID, cleanFailedFiles_);
138     int32_t changedRows = 0;
139     int32_t deleteDbRet = BackupDatabaseUtils::Delete(predicates, changedRows, mediaLibraryRdb_);
140     MEDIA_INFO_LOG("changedRows: %{public}d, deleteRet: %{public}d", changedRows, deleteDbRet);
141     return changedRows;
142 }
143 
SetVisibleFilesInDb()144 int32_t PhotosDataHandler::SetVisibleFilesInDb()
145 {
146     NativeRdb::ValuesBucket valuesBucket;
147     valuesBucket.PutInt(PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE));
148     std::unique_ptr<NativeRdb::AbsRdbPredicates> predicates =
149         std::make_unique<NativeRdb::AbsRdbPredicates>(PhotoColumn::PHOTOS_TABLE);
150     predicates->EqualTo(PhotoColumn::PHOTO_SYNC_STATUS, static_cast<int32_t>(SyncStatusType::TYPE_BACKUP));
151     predicates->In(MediaColumn::MEDIA_ID, setVisibleFiles_);
152 
153     int32_t changedRows = 0;
154     int32_t updateRet = BackupDatabaseUtils::Update(mediaLibraryRdb_, changedRows, valuesBucket, predicates);
155     MEDIA_INFO_LOG("changedRows: %{public}d, updateRet: %{public}d", changedRows, updateRet);
156     return changedRows;
157 }
158 
ShouldSetVisible(const PhotosDao::PhotosRowData & dirtyFile)159 bool PhotosDataHandler::ShouldSetVisible(const PhotosDao::PhotosRowData &dirtyFile)
160 {
161     return sceneCode_ == UPGRADE_RESTORE_ID && dirtyFile.position == static_cast<int32_t>(PhotoPositionType::LOCAL) &&
162         IsLocalFileExist(dirtyFile);
163 }
164 
AddToCleanFailedFiles(const PhotosDao::PhotosRowData & dirtyFile)165 void PhotosDataHandler::AddToCleanFailedFiles(const PhotosDao::PhotosRowData &dirtyFile)
166 {
167     std::lock_guard<mutex> lock(cleanFailedFilesMutex_);
168     cleanFailedFiles_.emplace_back(std::to_string(dirtyFile.fileId));
169     failedDirtyFileCleanNumber_++;
170 }
171 
AddToSetVisibleFiles(const PhotosDao::PhotosRowData & dirtyFile)172 void PhotosDataHandler::AddToSetVisibleFiles(const PhotosDao::PhotosRowData &dirtyFile)
173 {
174     std::lock_guard<mutex> lock(setVisibleFilesMutex_);
175     setVisibleFiles_.emplace_back(std::to_string(dirtyFile.fileId));
176 }
177 
IsLocalFileExist(const PhotosDao::PhotosRowData & dirtyFile)178 bool PhotosDataHandler::IsLocalFileExist(const PhotosDao::PhotosRowData &dirtyFile)
179 {
180     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::StartsWith(dirtyFile.data, RESTORE_FILES_CLOUD_DIR), false,
181         "Invalid prefix, path: %{public}s",
182         BackupFileUtils::GarbleFilePath(dirtyFile.data, DEFAULT_RESTORE_ID).c_str());
183     std::string localPath =
184         BackupFileUtils::GetReplacedPathByPrefixType(PrefixType::CLOUD, PrefixType::LOCAL, dirtyFile.data);
185     return MediaFileUtils::IsFileExists(localPath);
186 }
187 
IsFileExist(const PhotosDao::PhotosRowData & dirtyFile)188 bool PhotosDataHandler::IsFileExist(const PhotosDao::PhotosRowData &dirtyFile)
189 {
190     bool ret = dirtyFile.subtype != static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ?
191         BackupFileUtils::IsValidFile(dirtyFile.data) :
192         BackupFileUtils::IsValidFile(dirtyFile.data) && BackupFileUtils::IsMovingPhotoExist(dirtyFile.data);
193     CHECK_AND_EXECUTE(ret, ReportDirtyFile("FILE_NOT_EXIST", dirtyFile));
194     return ret;
195 }
196 
ReportDirtyFile(const std::string & errorCode,const PhotosDao::PhotosRowData & dirtyFile)197 void PhotosDataHandler::ReportDirtyFile(const std::string &errorCode, const PhotosDao::PhotosRowData &dirtyFile)
198 {
199     UpgradeRestoreTaskReport().SetSceneCode(sceneCode_).SetTaskId(taskId_)
200         .ReportInAudit("HANDLE_DIRTY_FILE", errorCode,
201             "Dirty file id: " + std::to_string(dirtyFile.fileId) +
202             ", subtype: " + std::to_string(dirtyFile.subtype) +
203             ", data: " + BackupFileUtils::GarbleFilePath(dirtyFile.data, DEFAULT_RESTORE_ID));
204 }
205 }  // namespace OHOS::Media
206