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