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 #include "photos_clone.h"
16
17 #include <uuid.h>
18 #include <numeric>
19
20 #include "rdb_store.h"
21 #include "result_set_utils.h"
22 #include "photo_album_dao.h"
23 #include "backup_const.h"
24 #include "media_log.h"
25 #include "album_plugin_config.h"
26 #include "userfile_manager_types.h"
27
28 namespace OHOS::Media {
ToString(const FileInfo & fileInfo)29 std::string PhotosClone::ToString(const FileInfo &fileInfo)
30 {
31 return "FileInfo[ fileId: " + std::to_string(fileInfo.fileIdOld) + ", displayName: " + fileInfo.displayName +
32 ", bundleName: " + fileInfo.bundleName + ", lPath: " + fileInfo.lPath +
33 ", size: " + std::to_string(fileInfo.fileSize) + ", fileType: " + std::to_string(fileInfo.fileType) + " ]";
34 }
35
ToLower(const std::string & str)36 std::string PhotosClone::ToLower(const std::string &str)
37 {
38 std::string lowerStr;
39 std::transform(
40 str.begin(), str.end(), std::back_inserter(lowerStr), [](unsigned char c) { return std::tolower(c); });
41 return lowerStr;
42 }
43
44 /**
45 * @brief Get Row Count of Photos in Album.
46 */
GetPhotosRowCountInPhotoMap()47 int32_t PhotosClone::GetPhotosRowCountInPhotoMap()
48 {
49 std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_IN_PHOTO_MAP;
50 if (this->mediaLibraryOriginalRdb_ == nullptr) {
51 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
52 return 0;
53 }
54 auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
55 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
56 return 0;
57 }
58 return GetInt32Val("count", resultSet);
59 }
60
61 /**
62 * @brief Get Row Count of Photos not in Album.
63 */
GetPhotosRowCountNotInPhotoMap()64 int32_t PhotosClone::GetPhotosRowCountNotInPhotoMap()
65 {
66 std::string querySql = this->SQL_PHOTOS_TABLE_COUNT_NOT_IN_PHOTO_MAP;
67 if (this->mediaLibraryOriginalRdb_ == nullptr) {
68 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
69 return 0;
70 }
71 auto resultSet = this->mediaLibraryOriginalRdb_->QuerySql(querySql);
72 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
73 return 0;
74 }
75 return GetInt32Val("count", resultSet);
76 }
77
78 /**
79 * @brief Query the Photos Info, which is in PhotoAlbum, from the Original MediaLibrary Database.
80 */
GetPhotosInPhotoMap(int32_t offset,int32_t pageSize)81 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetPhotosInPhotoMap(int32_t offset, int32_t pageSize)
82 {
83 std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
84 if (this->mediaLibraryOriginalRdb_ == nullptr) {
85 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
86 return nullptr;
87 }
88 return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_PHOTOS_TABLE_QUERY_IN_PHOTO_MAP, bindArgs);
89 }
90
91 /**
92 * @brief Query the Photos Info, which is not in PhotoAlbum, from the Original MediaLibrary Database.
93 */
GetPhotosNotInPhotoMap(int32_t offset,int32_t pageSize)94 std::shared_ptr<NativeRdb::ResultSet> PhotosClone::GetPhotosNotInPhotoMap(int32_t offset, int32_t pageSize)
95 {
96 std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
97 if (this->mediaLibraryOriginalRdb_ == nullptr) {
98 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
99 return nullptr;
100 }
101 return this->mediaLibraryOriginalRdb_->QuerySql(this->SQL_PHOTOS_TABLE_QUERY_NOT_IN_PHOTO_MAP, bindArgs);
102 }
103 /**
104 * @note If the lPath is empty, return '/Pictures/其它' string.
105 * If the lPath is '/Pictures/ScreenShots', return '/Pictures/ScreenShots' string.
106 * Otherwise, return the lPath of the FileInfo.
107 */
FindAlbumInfo(const FileInfo & fileInfo)108 PhotoAlbumDao::PhotoAlbumRowData PhotosClone::FindAlbumInfo(const FileInfo &fileInfo)
109 {
110 PhotoAlbumDao::PhotoAlbumRowData albumInfo;
111 if (fileInfo.lPath.empty()) {
112 MEDIA_ERR_LOG("Media_Restore: lPath is empty, Object: %{public}s", this->ToString(fileInfo).c_str());
113 return albumInfo;
114 }
115 if (this->ToLower(fileInfo.lPath) == this->ToLower(AlbumPlugin::LPATH_SCREEN_SHOTS) &&
116 fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
117 albumInfo = this->photoAlbumDao_.BuildAlbumInfoOfRecorders();
118 albumInfo = this->photoAlbumDao_.GetOrCreatePhotoAlbum(albumInfo);
119 MEDIA_INFO_LOG(
120 "Media_Restore: screenshots redirect to screenrecords, Object: %{public}s, albumInfo: %{public}s",
121 this->ToString(fileInfo).c_str(),
122 this->photoAlbumDao_.ToString(albumInfo).c_str());
123 return albumInfo;
124 }
125 albumInfo = this->photoAlbumDao_.GetPhotoAlbum(fileInfo.lPath);
126 if (albumInfo.lPath.empty()) {
127 MEDIA_ERR_LOG("Media_Restore: albumInfo is empty, albumInfo: %{public}s, Object: %{public}s",
128 this->photoAlbumDao_.ToString(albumInfo).c_str(),
129 this->ToString(fileInfo).c_str());
130 }
131 return albumInfo;
132 }
133
134 /**
135 * @brief Find the lPath of the PhotoAlbum related to Photos from target database.
136 */
FindlPath(const FileInfo & fileInfo)137 std::string PhotosClone::FindlPath(const FileInfo &fileInfo)
138 {
139 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
140 return albumInfo.lPath;
141 }
142
143 /**
144 * @brief Find the albumId of the PhotoAlbum related to Photos from target database.
145 */
FindAlbumId(const FileInfo & fileInfo)146 int32_t PhotosClone::FindAlbumId(const FileInfo &fileInfo)
147 {
148 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
149 return albumInfo.albumId;
150 }
151
152 /**
153 * @brief Find the packageName of the PhotoAlbum related to Photos from target database.
154 */
FindPackageName(const FileInfo & fileInfo)155 std::string PhotosClone::FindPackageName(const FileInfo &fileInfo)
156 {
157 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
158 // Only provide the package name of the SOURCE album.
159 if (albumInfo.albumType != static_cast<int32_t>(PhotoAlbumType::SOURCE) ||
160 albumInfo.albumSubType != static_cast<int32_t>(PhotoAlbumSubType::SOURCE_GENERIC)) {
161 return "";
162 }
163 return albumInfo.albumName;
164 }
165
166 /**
167 * @brief Find the bundleName of the PhotoAlbum related to Photos from target database.
168 */
FindBundleName(const FileInfo & fileInfo)169 std::string PhotosClone::FindBundleName(const FileInfo &fileInfo)
170 {
171 PhotoAlbumDao::PhotoAlbumRowData albumInfo = this->FindAlbumInfo(fileInfo);
172 // Only provide the bundle name of the SOURCE album.
173 if (albumInfo.albumType != static_cast<int32_t>(PhotoAlbumType::SOURCE) ||
174 albumInfo.albumSubType != static_cast<int32_t>(PhotoAlbumSubType::SOURCE_GENERIC)) {
175 return "";
176 }
177 return albumInfo.bundleName;
178 }
179
FindDuplicateBurstKey()180 std::vector<PhotosDao::PhotosRowData> PhotosClone::FindDuplicateBurstKey()
181 {
182 std::vector<PhotosDao::PhotosRowData> result;
183 std::string querySql = this->SQL_PHOTOS_TABLE_BURST_KEY_DUPLICATE_QUERY;
184 int rowCount = 0;
185 int offset = 0;
186 int pageSize = 200;
187 do {
188 std::vector<NativeRdb::ValueObject> bindArgs = {offset, pageSize};
189 if (this->mediaLibraryOriginalRdb_ == nullptr) {
190 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
191 break;
192 }
193 auto resultSet = this->mediaLibraryTargetRdb_->QuerySql(querySql, bindArgs);
194 if (resultSet == nullptr) {
195 MEDIA_ERR_LOG("Query resultSql is null.");
196 break;
197 }
198 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
199 PhotosDao::PhotosRowData info;
200 info.burstKey = GetStringVal("burst_key", resultSet);
201 info.ownerAlbumId = GetInt32Val("owner_album_id", resultSet);
202 result.emplace_back(info);
203 }
204 // Check if there are more rows to fetch.
205 resultSet->GetRowCount(rowCount);
206 offset += pageSize;
207 } while (rowCount > 0);
208 return result;
209 }
210
FindPhotoQuality(const FileInfo & fileInfo)211 int32_t PhotosClone::FindPhotoQuality(const FileInfo &fileInfo)
212 {
213 if (fileInfo.photoQuality == 1 && fileInfo.fileType == MediaType::MEDIA_TYPE_VIDEO) {
214 return 0;
215 }
216 return fileInfo.photoQuality;
217 }
218
ToString(const std::vector<NativeRdb::ValueObject> & values)219 std::string PhotosClone::ToString(const std::vector<NativeRdb::ValueObject> &values)
220 {
221 std::vector<std::string> result;
222 for (auto &value : values) {
223 std::string str;
224 value.GetString(str);
225 result.emplace_back(str + ", ");
226 }
227 return std::accumulate(result.begin(), result.end(), std::string());
228 }
229
230 /**
231 * @brief generate a uuid
232 *
233 * @return std::string uuid with 32 characters
234 */
GenerateUuid()235 std::string PhotosClone::GenerateUuid()
236 {
237 uuid_t uuid;
238 uuid_generate(uuid);
239 char str[UUID_STR_LENGTH] = {};
240 uuid_unparse(uuid, str);
241 return str;
242 }
243
244 /**
245 * @brief Fix Duplicate burst_key in Photos, which is used in different PhotoAlbum.
246 */
FixDuplicateBurstKeyInDifferentAlbum(std::atomic<uint64_t> & totalNumber)247 int32_t PhotosClone::FixDuplicateBurstKeyInDifferentAlbum(std::atomic<uint64_t> &totalNumber)
248 {
249 std::vector<PhotosDao::PhotosRowData> duplicateBurstKeyList = this->FindDuplicateBurstKey();
250 totalNumber += static_cast<uint64_t>(duplicateBurstKeyList.size());
251 MEDIA_INFO_LOG("onProcess Update otherTotalNumber_: %{public}lld", (long long)totalNumber);
252 std::string executeSql = this->SQL_PHOTOS_TABLE_BURST_KEY_UPDATE;
253 for (auto &info : duplicateBurstKeyList) {
254 std::string burstKeyNew = this->GenerateUuid();
255 std::vector<NativeRdb::ValueObject> bindArgs = {burstKeyNew, info.ownerAlbumId, info.burstKey};
256 MEDIA_INFO_LOG("Media_Restore: executeSql = %{public}s, bindArgs=%{public}s",
257 executeSql.c_str(),
258 this->ToString(bindArgs).c_str());
259 if (this->mediaLibraryOriginalRdb_ == nullptr) {
260 MEDIA_ERR_LOG("Media_Restore: mediaLibraryOriginalRdb_ is null.");
261 break;
262 }
263 int32_t ret = this->mediaLibraryTargetRdb_->ExecuteSql(executeSql, bindArgs);
264 if (ret != NativeRdb::E_OK) {
265 MEDIA_ERR_LOG("Media_Restore: FixDuplicateBurstKeyInDifferentAlbum failed,"
266 " ret=%{public}d, sql=%{public}s, bindArgs=%{public}s",
267 ret,
268 executeSql.c_str(),
269 this->ToString(bindArgs).c_str());
270 }
271 }
272 return 0;
273 }
274 } // namespace OHOS::Media