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
16 #include "medialibrary_album_fusion_utils.h"
17
18 #include <cerrno>
19 #include <functional>
20 #include <iomanip>
21 #include <sstream>
22 #include <string>
23 #include <unordered_map>
24
25 #include "dfx_reporter.h"
26 #include "medialibrary_type_const.h"
27 #include "medialibrary_formmap_operations.h"
28 #include "medialibrary_notify.h"
29 #include "medialibrary_rdbstore.h"
30 #include "metadata.h"
31 #include "media_file_utils.h"
32 #include "medialibrary_album_compatibility_fusion_sql.h"
33 #include "medialibrary_album_refresh.h"
34 #include "parameters.h"
35 #include "photo_file_operation.h"
36 #include "photo_asset_copy_operation.h"
37 #include "result_set_utils.h"
38 #include "thumbnail_service.h"
39 #include "userfile_manager_types.h"
40 #include "photo_source_path_operation.h"
41 #include "medialibrary_rdb_transaction.h"
42 #include "photo_album_lpath_operation.h"
43 #include "photo_album_update_date_modified_operation.h"
44 #include "photo_other_album_trans_operation.h"
45 #include "photo_album_copy_meta_data_operation.h"
46
47 namespace OHOS::Media {
48 using namespace std;
49 using namespace NativeRdb;
50
51 constexpr int32_t POSITION_LOCAL_FLAG = 1;
52 constexpr int32_t POSITION_CLOUD_FLAG = 2;
53 constexpr int32_t POSITION_BOTH_FLAG = 3;
54 constexpr int32_t CLOUD_COPY_DIRTY_FLAG = 7;
55 constexpr int32_t PHOTO_HIDDEN_FLAG = 1;
56
57 constexpr int32_t TIME_STAMP_OFFSET = 5;
58 const std::string ALBUM_FUSION_FLAG = "multimedia.medialibrary.cloneFlag";
59 const std::string ALBUM_FUSION_UPGRADE_STATUS_FLAG = "persist.multimedia.medialibrary.albumFusion.status";
60 const int32_t ALBUM_FUSION_UPGRADE_SUCCESS = 1;
61 const int32_t ALBUM_FUSION_UPGRADE_FAIL = 0;
62 const int32_t ALBUM_FUSION_BATCH_COUNT = 200;
63 const string SQL_GET_DUPLICATE_PHOTO = "SELECT p.file_id FROM Photos p "
64 "LEFT JOIN PhotoAlbum a ON p.owner_album_id = a.album_id "
65 "WHERE p.dirty = 7 AND a.album_id IS NULL LIMIT 500";
66
67 static unordered_map<string, ResultSetDataType> commonColumnTypeMap = {
68 {MediaColumn::MEDIA_SIZE, ResultSetDataType::TYPE_INT64},
69 {MediaColumn::MEDIA_TITLE, ResultSetDataType::TYPE_STRING},
70 {MediaColumn::MEDIA_NAME, ResultSetDataType::TYPE_STRING},
71 {MediaColumn::MEDIA_TYPE, ResultSetDataType::TYPE_INT32},
72 {MediaColumn::MEDIA_MIME_TYPE, ResultSetDataType::TYPE_STRING},
73 {MediaColumn::MEDIA_OWNER_PACKAGE, ResultSetDataType::TYPE_STRING},
74 {MediaColumn::MEDIA_OWNER_APPID, ResultSetDataType::TYPE_STRING},
75 {MediaColumn::MEDIA_PACKAGE_NAME, ResultSetDataType::TYPE_STRING},
76 {MediaColumn::MEDIA_DEVICE_NAME, ResultSetDataType::TYPE_STRING},
77 {MediaColumn::MEDIA_DATE_MODIFIED, ResultSetDataType::TYPE_INT64},
78 {MediaColumn::MEDIA_DATE_ADDED, ResultSetDataType::TYPE_INT64},
79 {MediaColumn::MEDIA_DATE_TAKEN, ResultSetDataType::TYPE_INT64},
80 {MediaColumn::MEDIA_DURATION, ResultSetDataType::TYPE_INT32},
81 {MediaColumn::MEDIA_IS_FAV, ResultSetDataType::TYPE_INT32},
82 {MediaColumn::MEDIA_DATE_TRASHED, ResultSetDataType::TYPE_INT64},
83 {MediaColumn::MEDIA_DATE_DELETED, ResultSetDataType::TYPE_INT64},
84 {MediaColumn::MEDIA_HIDDEN, ResultSetDataType::TYPE_INT32},
85 {MediaColumn::MEDIA_PARENT_ID, ResultSetDataType::TYPE_INT32},
86 {PhotoColumn::PHOTO_META_DATE_MODIFIED, ResultSetDataType::TYPE_INT64},
87 {PhotoColumn::PHOTO_ORIENTATION, ResultSetDataType::TYPE_INT32},
88 {PhotoColumn::PHOTO_LATITUDE, ResultSetDataType::TYPE_DOUBLE},
89 {PhotoColumn::PHOTO_LONGITUDE, ResultSetDataType::TYPE_DOUBLE},
90 {PhotoColumn::PHOTO_HEIGHT, ResultSetDataType::TYPE_INT32},
91 {PhotoColumn::PHOTO_WIDTH, ResultSetDataType::TYPE_INT32},
92 {PhotoColumn::PHOTO_EDIT_TIME, ResultSetDataType::TYPE_INT64},
93 {PhotoColumn::PHOTO_SUBTYPE, ResultSetDataType::TYPE_INT32},
94 {PhotoColumn::CAMERA_SHOT_KEY, ResultSetDataType::TYPE_STRING},
95 {PhotoColumn::PHOTO_USER_COMMENT, ResultSetDataType::TYPE_STRING},
96 {PhotoColumn::PHOTO_SHOOTING_MODE, ResultSetDataType::TYPE_STRING},
97 {PhotoColumn::PHOTO_SHOOTING_MODE_TAG, ResultSetDataType::TYPE_STRING},
98 {PhotoColumn::PHOTO_ALL_EXIF, ResultSetDataType::TYPE_STRING},
99 {PhotoColumn::PHOTO_DATE_YEAR, ResultSetDataType::TYPE_STRING},
100 {PhotoColumn::PHOTO_DATE_MONTH, ResultSetDataType::TYPE_STRING},
101 {PhotoColumn::PHOTO_DATE_DAY, ResultSetDataType::TYPE_STRING},
102 {PhotoColumn::PHOTO_HIDDEN_TIME, ResultSetDataType::TYPE_INT64},
103 {PhotoColumn::PHOTO_FIRST_VISIT_TIME, ResultSetDataType::TYPE_INT64},
104 {PhotoColumn::PHOTO_DEFERRED_PROC_TYPE, ResultSetDataType::TYPE_INT32},
105 {PhotoColumn::PHOTO_DYNAMIC_RANGE_TYPE, ResultSetDataType::TYPE_INT32},
106 {PhotoColumn::MOVING_PHOTO_EFFECT_MODE, ResultSetDataType::TYPE_INT32},
107 {PhotoColumn::PHOTO_FRONT_CAMERA, ResultSetDataType::TYPE_STRING},
108 {PhotoColumn::PHOTO_BURST_COVER_LEVEL, ResultSetDataType::TYPE_INT32},
109 {PhotoColumn::SUPPORTED_WATERMARK_TYPE, ResultSetDataType::TYPE_INT32},
110 {PhotoColumn::PHOTO_MEDIA_SUFFIX, ResultSetDataType::TYPE_STRING},
111 {PhotoColumn::PHOTO_IS_RECENT_SHOW, ResultSetDataType::TYPE_INT32}
112 };
113
114 static unordered_map<string, ResultSetDataType> thumbnailColumnTypeMap = {
115 {PhotoColumn::PHOTO_LCD_VISIT_TIME, ResultSetDataType::TYPE_INT64},
116 {PhotoColumn::PHOTO_THUMBNAIL_READY, ResultSetDataType::TYPE_INT64},
117 {PhotoColumn::PHOTO_LCD_SIZE, ResultSetDataType::TYPE_STRING},
118 {PhotoColumn::PHOTO_THUMB_SIZE, ResultSetDataType::TYPE_STRING},
119 };
120
121 static unordered_map<string, ResultSetDataType> albumColumnTypeMap = {
122 {PhotoAlbumColumns::ALBUM_TYPE, ResultSetDataType::TYPE_INT32},
123 {PhotoAlbumColumns::ALBUM_SUBTYPE, ResultSetDataType::TYPE_INT32},
124 {PhotoAlbumColumns::ALBUM_NAME, ResultSetDataType::TYPE_STRING},
125 {PhotoAlbumColumns::ALBUM_COVER_URI, ResultSetDataType::TYPE_STRING},
126 {PhotoAlbumColumns::ALBUM_COUNT, ResultSetDataType::TYPE_INT32},
127 {PhotoAlbumColumns::ALBUM_DATE_MODIFIED, ResultSetDataType::TYPE_INT64},
128 {PhotoAlbumColumns::CONTAINS_HIDDEN, ResultSetDataType::TYPE_INT32},
129 {PhotoAlbumColumns::HIDDEN_COUNT, ResultSetDataType::TYPE_INT32},
130 {PhotoAlbumColumns::HIDDEN_COVER, ResultSetDataType::TYPE_STRING},
131 {PhotoAlbumColumns::ALBUM_ORDER, ResultSetDataType::TYPE_INT32},
132 {PhotoAlbumColumns::ALBUM_IMAGE_COUNT, ResultSetDataType::TYPE_INT32},
133 {PhotoAlbumColumns::ALBUM_VIDEO_COUNT, ResultSetDataType::TYPE_INT32},
134 {PhotoAlbumColumns::ALBUM_BUNDLE_NAME, ResultSetDataType::TYPE_STRING},
135 {PhotoAlbumColumns::ALBUM_LOCAL_LANGUAGE, ResultSetDataType::TYPE_STRING},
136 {PhotoAlbumColumns::ALBUM_IS_LOCAL, ResultSetDataType::TYPE_INT32},
137 };
138
139 std::mutex MediaLibraryAlbumFusionUtils::cloudAlbumAndDataMutex_;
140 std::atomic<bool> MediaLibraryAlbumFusionUtils::isNeedRefreshAlbum = false;
141
RemoveMisAddedHiddenData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)142 int32_t MediaLibraryAlbumFusionUtils::RemoveMisAddedHiddenData(
143 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
144 {
145 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_0: Start remove misadded hidden data");
146 CHECK_AND_RETURN_RET_LOG(upgradeStore != nullptr, E_DB_FAIL, "fail to get rdbstore");
147 int64_t beginTime = MediaFileUtils::UTCTimeMilliSeconds();
148 int32_t err = upgradeStore->ExecuteSql(DROP_UNWANTED_ALBUM_RELATIONSHIP_FOR_HIDDEN_ALBUM_ASSET);
149 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
150 "Failed to drop unwanted album relationship for .hiddenAlbum! Failed to exec: %{public}s",
151 DROP_UNWANTED_ALBUM_RELATIONSHIP_FOR_HIDDEN_ALBUM_ASSET.c_str());
152 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_0: End remove misadded hidden data, cost %{public}ld",
153 (long)(MediaFileUtils::UTCTimeMilliSeconds() - beginTime));
154 return E_OK;
155 }
156
PrepareTempUpgradeTable(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,int32_t & matchedCount)157 static int32_t PrepareTempUpgradeTable(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore, int32_t &matchedCount)
158 {
159 int32_t err = upgradeStore->ExecuteSql(DROP_TEMP_UPGRADE_PHOTO_MAP_TABLE);
160 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
161 "Fatal error! Failed to exec: %{public}s", DROP_TEMP_UPGRADE_PHOTO_MAP_TABLE.c_str());
162 MEDIA_INFO_LOG("ALBUM_FUSE begin exec: %{public}s", CREATE_TEMP_UPGRADE_PHOTO_MAP_TABLE.c_str());
163 err = upgradeStore->ExecuteSql(CREATE_TEMP_UPGRADE_PHOTO_MAP_TABLE);
164
165 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
166 "Fatal error! Failed to exec: %{public}s", CREATE_TEMP_UPGRADE_PHOTO_MAP_TABLE.c_str());
167 auto resultSet = upgradeStore->QuerySql(QUERY_MATCHED_COUNT);
168 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
169 MEDIA_ERR_LOG("Query matched data fails");
170 return E_DB_FAIL;
171 }
172 resultSet->GetInt(0, matchedCount);
173 MEDIA_INFO_LOG("ALBUM_FUSE: There are %{public}d matched items", matchedCount);
174 err = upgradeStore->ExecuteSql(CREATE_UNIQUE_TEMP_UPGRADE_INDEX_ON_MAP_ASSET);
175 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
176 "Fatal error! Failed to exec: %{public}s", CREATE_UNIQUE_TEMP_UPGRADE_INDEX_ON_MAP_ASSET.c_str());
177 err = upgradeStore->ExecuteSql(CREATE_UNIQUE_TEMP_UPGRADE_INDEX_ON_PHOTO_MAP);
178 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
179 "Fatal error! Failed to exec: %{public}s", CREATE_UNIQUE_TEMP_UPGRADE_INDEX_ON_PHOTO_MAP.c_str());
180 return E_OK;
181 }
182
IfHandledDataCountMatched(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,int32_t & exceptCount)183 static int32_t IfHandledDataCountMatched(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
184 int32_t &exceptCount)
185 {
186 if (upgradeStore == nullptr) {
187 MEDIA_INFO_LOG("fail to get rdbstore");
188 return E_DB_FAIL;
189 }
190 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_1: Check if compensate matched data owner_album_id success");
191 int32_t updatedSuccessCount = 0;
192 auto resultSet = upgradeStore->QuerySql(QUERY_SUCCESS_MATCHED_COUNT);
193 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
194 MEDIA_ERR_LOG("Query matched data fails");
195 return E_DB_FAIL;
196 }
197 resultSet->GetInt(0, updatedSuccessCount);
198 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_1: There are %{public}d items update success", updatedSuccessCount);
199 if (updatedSuccessCount >= exceptCount) {
200 MEDIA_INFO_LOG("Handled count matches!");
201 return E_OK;
202 }
203 return E_DB_FAIL;
204 }
205
HandleMatchedDataFusion(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)206 int32_t MediaLibraryAlbumFusionUtils::HandleMatchedDataFusion(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
207 {
208 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_1: Start handle matched relationship");
209 if (upgradeStore == nullptr) {
210 MEDIA_INFO_LOG("fail to get rdbstore");
211 return E_DB_FAIL;
212 }
213 int64_t beginTime = MediaFileUtils::UTCTimeMilliSeconds();
214 int32_t matchedCount = 0;
215 int32_t err = PrepareTempUpgradeTable(upgradeStore, matchedCount);
216 if (err != E_OK) {
217 MEDIA_ERR_LOG("Prepare temp upgrade table fails");
218 return err;
219 }
220 MEDIA_INFO_LOG("ALBUM_FUSE: execute update!");
221 err = upgradeStore->ExecuteSql(UPDATE_ALBUM_ASSET_MAPPING_CONSISTENCY_DATA_SQL);
222 MEDIA_INFO_LOG("ALBUM_FUSE: execute finish!");
223 if (err != NativeRdb::E_OK) {
224 MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s",
225 UPDATE_ALBUM_ASSET_MAPPING_CONSISTENCY_DATA_SQL.c_str());
226 return err;
227 }
228
229 if (IfHandledDataCountMatched(upgradeStore, matchedCount) != E_OK) {
230 MEDIA_ERR_LOG("Handled count not match, may has other transaction!");
231 return E_HAS_DB_ERROR;
232 }
233 err = upgradeStore->ExecuteSql(DELETE_MATCHED_RELATIONSHIP_IN_PHOTOMAP_SQL);
234 if (err != NativeRdb::E_OK) {
235 MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s", DELETE_MATCHED_RELATIONSHIP_IN_PHOTOMAP_SQL.c_str());
236 return err;
237 }
238 err = upgradeStore->ExecuteSql(DROP_TEMP_UPGRADE_PHOTO_MAP_TABLE);
239 if (err != NativeRdb::E_OK) {
240 MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s", DROP_TEMP_UPGRADE_PHOTO_MAP_TABLE.c_str());
241 return err;
242 }
243 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_1: End handle matched relationship, cost %{public}ld",
244 (long)(MediaFileUtils::UTCTimeMilliSeconds() - beginTime));
245 return E_OK;
246 }
247
AddToMap(std::multimap<int32_t,vector<int32_t>> & targetMap,int key,int value)248 static inline void AddToMap(std::multimap<int32_t, vector<int32_t>> &targetMap, int key, int value)
249 {
250 auto it = targetMap.find(key);
251 if (it == targetMap.end()) {
252 std::vector<int32_t> valueVector = {value};
253 targetMap.insert(std::make_pair(key, valueVector));
254 } else {
255 it->second.push_back(value);
256 }
257 }
258
QueryNoMatchedMap(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,std::multimap<int32_t,vector<int32_t>> & notMathedMap,bool isUpgrade)259 int32_t MediaLibraryAlbumFusionUtils::QueryNoMatchedMap(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
260 std::multimap<int32_t, vector<int32_t>> ¬MathedMap, bool isUpgrade)
261 {
262 if (upgradeStore == nullptr) {
263 MEDIA_ERR_LOG("invalid rdbstore or nullptr map");
264 return E_INVALID_ARGUMENTS;
265 }
266 std::string queryNotMatchedDataSql = "";
267 if (isUpgrade) {
268 queryNotMatchedDataSql = QUERY_NOT_MATCHED_DATA_IN_PHOTOMAP_BY_PAGE;
269 } else {
270 queryNotMatchedDataSql = QUERY_NEW_NOT_MATCHED_DATA_IN_PHOTOMAP_BY_PAGE;
271 }
272 auto resultSet = upgradeStore->QuerySql(queryNotMatchedDataSql);
273 MEDIA_INFO_LOG("query sql is %{public}s", queryNotMatchedDataSql.c_str());
274 if (resultSet == nullptr) {
275 MEDIA_ERR_LOG("Query not matched data fails");
276 return E_DB_FAIL;
277 }
278 int32_t notMatchedCount = 0;
279 resultSet->GetRowCount(notMatchedCount);
280 if (notMatchedCount == 0) {
281 MEDIA_INFO_LOG("Already matched, no need to handle");
282 return E_OK;
283 }
284 MEDIA_INFO_LOG("There are %{public}d assets need to copy", notMatchedCount);
285 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
286 int colIndex = -1;
287 int32_t assetId = 0;
288 int32_t albumId = 0;
289 resultSet->GetColumnIndex(PhotoMap::ALBUM_ID, colIndex);
290 if (resultSet->GetInt(colIndex, albumId) != NativeRdb::E_OK) {
291 return E_HAS_DB_ERROR;
292 }
293 resultSet->GetColumnIndex(PhotoMap::ASSET_ID, colIndex);
294 if (resultSet->GetInt(colIndex, assetId) != NativeRdb::E_OK) {
295 return E_HAS_DB_ERROR;
296 }
297 AddToMap(notMathedMap, assetId, albumId);
298 }
299 return E_OK;
300 }
301
isLocalAsset(shared_ptr<NativeRdb::ResultSet> & resultSet)302 static bool isLocalAsset(shared_ptr<NativeRdb::ResultSet> &resultSet)
303 {
304 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
305 MEDIA_INFO_LOG("Query not matched data fails");
306 return E_DB_FAIL;
307 }
308 int colIndex = -1;
309 int32_t position = POSITION_CLOUD_FLAG;
310 resultSet->GetColumnIndex("position", colIndex);
311 if (resultSet->GetInt(colIndex, position) != NativeRdb::E_OK) {
312 return E_HAS_DB_ERROR;
313 }
314 return position != POSITION_CLOUD_FLAG;
315 }
316
buildTargetFilePath(std::string & targetPath,std::string displayName,int32_t mediaType)317 static inline void buildTargetFilePath(std::string &targetPath, std::string displayName, int32_t mediaType)
318 {
319 std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
320 std::function<int(void)> tryReuseDeleted = [&]()->int {
321 int32_t uniqueId = MediaLibraryAssetOperations::CreateAssetUniqueId(mediaType, trans);
322 return MediaLibraryAssetOperations::CreateAssetPathById(uniqueId, mediaType,
323 MediaFileUtils::GetExtensionFromPath(displayName), targetPath);
324 };
325 int ret = trans->RetryTrans(tryReuseDeleted);
326 if (ret != E_OK) {
327 MEDIA_ERR_LOG("Create targetPath failed, ret=%{public}d", ret);
328 }
329 }
330
getThumbnailPathFromOrignalPath(std::string srcPath)331 static std::string getThumbnailPathFromOrignalPath(std::string srcPath)
332 {
333 if (srcPath.empty()) {
334 MEDIA_ERR_LOG("source file invalid!");
335 return "";
336 }
337 std::string photoRelativePath = "/Photo/";
338 std::string thumbRelativePath = "/.thumbs/Photo/";
339 size_t pos = srcPath.find(photoRelativePath);
340 std::string thumbnailPath = "";
341 if (pos != string::npos) {
342 thumbnailPath = srcPath.replace(pos, photoRelativePath.length(), thumbRelativePath);
343 }
344 return thumbnailPath;
345 }
346
CopyDirectory(const std::string & srcDir,const std::string & dstDir)347 int32_t CopyDirectory(const std::string &srcDir, const std::string &dstDir)
348 {
349 if (!MediaFileUtils::CreateDirectory(dstDir)) {
350 MEDIA_ERR_LOG("Create dstDir %{public}s failed", dstDir.c_str());
351 return E_FAIL;
352 }
353 if (!MediaFileUtils::IsFileExists(srcDir)) {
354 MEDIA_WARN_LOG("%{public}s doesn't exist, skip.", srcDir.c_str());
355 return E_OK;
356 }
357 for (const auto &dirEntry : std::filesystem::directory_iterator{ srcDir }) {
358 std::string srcFilePath = dirEntry.path();
359 std::string tmpFilePath = srcFilePath;
360 std::string dstFilePath = tmpFilePath.replace(0, srcDir.length(), dstDir);
361 if (!MediaFileUtils::IsFileExists(srcFilePath) || !MediaFileUtils::IsFileValid(srcFilePath)) {
362 MEDIA_ERR_LOG("Copy file from %{public}s failed , because of thumbnail is invalid", srcFilePath.c_str());
363 }
364 if (!MediaFileUtils::CopyFileUtil(srcFilePath, dstFilePath)) {
365 MEDIA_ERR_LOG("Copy file from %{public}s to %{public}s failed",
366 srcFilePath.c_str(), dstFilePath.c_str());
367 return E_FAIL;
368 }
369 }
370 return E_OK;
371 }
372
CopyOriginThumbnail(const std::string & srcPath,std::string & targetPath)373 static int32_t CopyOriginThumbnail(const std::string &srcPath, std::string &targetPath)
374 {
375 if (srcPath.empty() || targetPath.empty()) {
376 MEDIA_ERR_LOG("source file or targetPath empty");
377 return E_INVALID_PATH;
378 }
379 std::string originalThumbnailDirPath = getThumbnailPathFromOrignalPath(srcPath);
380 std::string targetThumbnailDirPath = getThumbnailPathFromOrignalPath(targetPath);
381 if (!targetThumbnailDirPath.empty()) {
382 int32_t err = MediaFileUtils::CopyDirectory(originalThumbnailDirPath, targetThumbnailDirPath);
383 if (err != E_OK) {
384 MEDIA_ERR_LOG("copy thumbnail dir fail because of %{public}d, dir:%{public}s",
385 err, originalThumbnailDirPath.c_str());
386 }
387 }
388 return E_OK;
389 }
390
DeleteFile(const std::string & targetPath)391 static int32_t DeleteFile(const std::string &targetPath)
392 {
393 if (targetPath.empty()) {
394 MEDIA_ERR_LOG("targetPath empty");
395 return E_INVALID_PATH;
396 }
397 MediaFileUtils::DeleteFile(targetPath);
398 return E_OK;
399 }
400
DeleteThumbnail(const std::string & targetPath)401 static int32_t DeleteThumbnail(const std::string &targetPath)
402 {
403 if (targetPath.empty()) {
404 MEDIA_ERR_LOG("targetPath empty");
405 return E_INVALID_PATH;
406 }
407 std::string targetThumbnailDirPath = getThumbnailPathFromOrignalPath(targetPath);
408 MediaFileUtils::DeleteDir(targetThumbnailDirPath);
409 return E_OK;
410 }
411
GetIntValueFromResultSet(shared_ptr<ResultSet> resultSet,const string & column,int & value)412 static int32_t GetIntValueFromResultSet(shared_ptr<ResultSet> resultSet, const string &column, int &value)
413 {
414 if (resultSet == nullptr) {
415 return E_HAS_DB_ERROR;
416 }
417 int index = -1;
418 resultSet->GetColumnIndex(column, index);
419 if (index == -1) {
420 return E_HAS_DB_ERROR;
421 }
422 if (resultSet->GetInt(index, value) != NativeRdb::E_OK) {
423 return E_HAS_DB_ERROR;
424 }
425 return E_OK;
426 }
427
GetDoubleValueFromResultSet(shared_ptr<ResultSet> resultSet,const string & column,double & value)428 static int32_t GetDoubleValueFromResultSet(shared_ptr<ResultSet> resultSet, const string &column, double &value)
429 {
430 if (resultSet == nullptr) {
431 return E_HAS_DB_ERROR;
432 }
433 int index = -1;
434 resultSet->GetColumnIndex(column, index);
435 if (index == -1) {
436 return E_HAS_DB_ERROR;
437 }
438 if (resultSet->GetDouble(index, value) != NativeRdb::E_OK) {
439 return E_HAS_DB_ERROR;
440 }
441 return E_OK;
442 }
443
GetLongValueFromResultSet(shared_ptr<ResultSet> resultSet,const string & column,int64_t & value)444 static int64_t GetLongValueFromResultSet(shared_ptr<ResultSet> resultSet, const string &column, int64_t &value)
445 {
446 if (resultSet == nullptr) {
447 return E_HAS_DB_ERROR;
448 }
449 int index = -1;
450 resultSet->GetColumnIndex(column, index);
451 if (index == -1) {
452 return E_HAS_DB_ERROR;
453 }
454 if (resultSet->GetLong(index, value) != NativeRdb::E_OK) {
455 return E_HAS_DB_ERROR;
456 }
457 return E_OK;
458 }
459
GetStringValueFromResultSet(shared_ptr<ResultSet> resultSet,const string & column,string & value)460 static int32_t GetStringValueFromResultSet(shared_ptr<ResultSet> resultSet, const string &column, string &value)
461 {
462 if (resultSet == nullptr) {
463 return E_HAS_DB_ERROR;
464 }
465 int index = -1;
466 resultSet->GetColumnIndex(column, index);
467 if (index == -1) {
468 return E_HAS_DB_ERROR;
469 }
470 if (resultSet->GetString(index, value) != NativeRdb::E_OK) {
471 return E_HAS_DB_ERROR;
472 }
473 return E_OK;
474 }
475
ParsingAndFillValue(NativeRdb::ValuesBucket & values,const string & columnName,ResultSetDataType columnType,shared_ptr<NativeRdb::ResultSet> & resultSet)476 static void ParsingAndFillValue(NativeRdb::ValuesBucket &values, const string &columnName,
477 ResultSetDataType columnType, shared_ptr<NativeRdb::ResultSet> &resultSet)
478 {
479 switch (columnType) {
480 case ResultSetDataType::TYPE_INT32: {
481 int32_t intColumnValue;
482 GetIntValueFromResultSet(resultSet, columnName, intColumnValue);
483 values.PutInt(columnName, intColumnValue);
484 break;
485 }
486 case ResultSetDataType::TYPE_INT64: {
487 int64_t longColumnValue;
488 GetLongValueFromResultSet(resultSet, columnName, longColumnValue);
489 values.PutLong(columnName, longColumnValue);
490 break;
491 }
492 case ResultSetDataType::TYPE_DOUBLE: {
493 double doubleColumnValue;
494 GetDoubleValueFromResultSet(resultSet, columnName, doubleColumnValue);
495 values.PutDouble(columnName, doubleColumnValue);
496 break;
497 }
498 case ResultSetDataType::TYPE_STRING: {
499 std::string stringValue = "";
500 GetStringValueFromResultSet(resultSet, columnName, stringValue);
501 values.PutString(columnName, stringValue);
502 break;
503 }
504 default:
505 MEDIA_ERR_LOG("No such column type");
506 }
507 }
508
509 struct MediaAssetCopyInfo {
510 std::string targetPath;
511 bool isCopyThumbnail;
512 int32_t ownerAlbumId;
513 std::string displayName;
514 bool isCopyDateAdded;
MediaAssetCopyInfoOHOS::Media::MediaAssetCopyInfo515 MediaAssetCopyInfo(const std::string& targetPath, bool isCopyThumbnail, int32_t ownerAlbumId,
516 const std::string& displayName = "", bool isCopyDateAdded = true)
517 : targetPath(targetPath), isCopyThumbnail(isCopyThumbnail), ownerAlbumId(ownerAlbumId),
518 displayName(displayName), isCopyDateAdded(isCopyDateAdded) {}
519 };
520
HandleLowQualityAssetValuesBucket(shared_ptr<NativeRdb::ResultSet> & resultSet,NativeRdb::ValuesBucket & values)521 static void HandleLowQualityAssetValuesBucket(shared_ptr<NativeRdb::ResultSet>& resultSet,
522 NativeRdb::ValuesBucket& values)
523 {
524 int32_t dirty = -1;
525 GetIntValueFromResultSet(resultSet, PhotoColumn::PHOTO_DIRTY, dirty);
526 int32_t photoQuality = 0;
527 GetIntValueFromResultSet(resultSet, PhotoColumn::PHOTO_QUALITY, photoQuality);
528 if (photoQuality == static_cast<int32_t>(MultiStagesPhotoQuality::LOW)) {
529 photoQuality = static_cast<int32_t>(MultiStagesPhotoQuality::FULL);
530 dirty = static_cast<int32_t>(DirtyType::TYPE_NEW);
531 values.PutInt(PhotoColumn::PHOTO_DIRTY, dirty);
532 }
533 values.PutInt(PhotoColumn::PHOTO_QUALITY, photoQuality);
534 if (dirty == -1 && photoQuality != static_cast<int32_t>(MultiStagesPhotoQuality::LOW)) {
535 MEDIA_WARN_LOG("Status error, dirty is -1, cannot upload");
536 values.PutInt(PhotoColumn::PHOTO_DIRTY, -1);
537 }
538 }
539
BuildInsertValuesBucket(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,NativeRdb::ValuesBucket & values,shared_ptr<NativeRdb::ResultSet> & resultSet,const MediaAssetCopyInfo & copyInfo)540 static int32_t BuildInsertValuesBucket(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,
541 NativeRdb::ValuesBucket &values, shared_ptr<NativeRdb::ResultSet> &resultSet, const MediaAssetCopyInfo ©Info)
542 {
543 values.PutString(MediaColumn::MEDIA_FILE_PATH, copyInfo.targetPath);
544 PhotoAssetCopyOperation()
545 .SetTargetPhotoInfo(resultSet)
546 .SetTargetAlbumId(copyInfo.ownerAlbumId)
547 .SetDisplayName(copyInfo.displayName)
548 .CopyPhotoAsset(rdbStore, values);
549 for (auto it = commonColumnTypeMap.begin(); it != commonColumnTypeMap.end(); ++it) {
550 string columnName = it->first;
551 ResultSetDataType columnType = it->second;
552 ParsingAndFillValue(values, columnName, columnType, resultSet);
553 }
554 if (copyInfo.isCopyThumbnail) {
555 for (auto it = thumbnailColumnTypeMap.begin(); it != thumbnailColumnTypeMap.end(); ++it) {
556 string columnName = it->first;
557 ResultSetDataType columnType = it->second;
558 ParsingAndFillValue(values, columnName, columnType, resultSet);
559 }
560 // Indicate original file cloud_id for cloud copy
561 std::string cloudId = "";
562 GetStringValueFromResultSet(resultSet, PhotoColumn::PHOTO_CLOUD_ID, cloudId);
563 if (cloudId.empty()) {
564 // copy from copyed asset, may not synced, need copy from original asset
565 GetStringValueFromResultSet(resultSet, PhotoColumn::PHOTO_ORIGINAL_ASSET_CLOUD_ID, cloudId);
566 }
567 values.PutString(PhotoColumn::PHOTO_ORIGINAL_ASSET_CLOUD_ID, cloudId);
568 values.PutInt(PhotoColumn::PHOTO_POSITION, POSITION_CLOUD_FLAG);
569 values.PutInt(PhotoColumn::PHOTO_DIRTY, CLOUD_COPY_DIRTY_FLAG);
570 }
571 if (!copyInfo.isCopyDateAdded) {
572 values.Delete(MediaColumn::MEDIA_DATE_ADDED);
573 values.PutLong(MediaColumn::MEDIA_DATE_ADDED, MediaFileUtils::UTCTimeMilliSeconds());
574 }
575 HandleLowQualityAssetValuesBucket(resultSet, values);
576 return E_OK;
577 }
578
copyMetaData(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,int64_t & newAssetId,NativeRdb::ValuesBucket & values)579 static int32_t copyMetaData(const std::shared_ptr<MediaLibraryRdbStore> rdbStore, int64_t &newAssetId,
580 NativeRdb::ValuesBucket &values)
581 {
582 int32_t ret = rdbStore->Insert(newAssetId, PhotoColumn::PHOTOS_TABLE, values);
583 if (ret != NativeRdb::E_OK) {
584 MEDIA_ERR_LOG("upgradeStore->Insert failed, ret = %{public}d", ret);
585 return E_HAS_DB_ERROR;
586 }
587 MEDIA_DEBUG_LOG("Insert copy meta data success, rowId=%{public}" PRId64", ret=%{public}d", newAssetId, ret);
588 return ret;
589 }
590
GetSourceFilePath(std::string & srcPath,shared_ptr<NativeRdb::ResultSet> & resultSet)591 static int32_t GetSourceFilePath(std::string &srcPath, shared_ptr<NativeRdb::ResultSet> &resultSet)
592 {
593 int colIndex = -1;
594 resultSet->GetColumnIndex(MediaColumn::MEDIA_FILE_PATH, colIndex);
595 if (resultSet->GetString(colIndex, srcPath) != NativeRdb::E_OK) {
596 return E_HAS_DB_ERROR;
597 }
598 return E_OK;
599 }
600
UpdateRelationship(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,const int32_t & assetId,const int32_t & newAssetId,const int32_t & ownerAlbumId,bool isLocalAsset)601 static int32_t UpdateRelationship(const std::shared_ptr<MediaLibraryRdbStore> rdbStore, const int32_t &assetId,
602 const int32_t &newAssetId, const int32_t &ownerAlbumId, bool isLocalAsset)
603 {
604 const std::string UPDATE_ALBUM_ID_FOR_COPY_ASSET =
605 "UPDATE Photos SET owner_album_id = " + to_string(ownerAlbumId) + " WHERE file_id = " + to_string(newAssetId);
606 int32_t ret = rdbStore->ExecuteSql(UPDATE_ALBUM_ID_FOR_COPY_ASSET);
607 if (ret != NativeRdb::E_OK) {
608 MEDIA_ERR_LOG("UPDATE_ALBUM_ID_FOR_COPY_ASSET failed, ret = %{public}d", ret);
609 return E_HAS_DB_ERROR;
610 }
611 const std::string DROP_HANDLED_MAP_RELATIONSHIP =
612 "UPDATE PhotoMap SET dirty = '4' WHERE " + PhotoMap::ASSET_ID + " = '" + to_string(assetId) +
613 "' AND " + PhotoMap::ALBUM_ID + " = '" + to_string(ownerAlbumId) + "'";
614 ret = rdbStore->ExecuteSql(DROP_HANDLED_MAP_RELATIONSHIP);
615 if (ret != NativeRdb::E_OK) {
616 MEDIA_ERR_LOG("DROP_HANDLED_MAP_RELATIONSHIP failed, ret = %{public}d", ret);
617 return E_HAS_DB_ERROR;
618 }
619 if (!isLocalAsset) {
620 const std::string INDICATE_FILE_NEED_CLOUD_COPY =
621 "UPDATE Photos SET dirty = '7' WHERE " + PhotoMap::ASSET_ID + " = '" + to_string(newAssetId);
622 }
623 MEDIA_INFO_LOG("Update handled copy meta success, rowId = %{public}d, ", newAssetId);
624 return E_OK;
625 }
626
GenerateThumbnail(const int32_t & assetId,const std::string & targetPath,shared_ptr<NativeRdb::ResultSet> & resultSet,bool isSyncGenerateThumbnail)627 static int32_t GenerateThumbnail(const int32_t &assetId, const std::string &targetPath,
628 shared_ptr<NativeRdb::ResultSet> &resultSet, bool isSyncGenerateThumbnail)
629 {
630 if (ThumbnailService::GetInstance() == nullptr) {
631 return E_FAIL;
632 }
633 std::string displayName = "";
634 GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_NAME, displayName);
635 int64_t dateTaken = 0;
636 GetLongValueFromResultSet(resultSet, MediaColumn::MEDIA_DATE_TAKEN, dateTaken);
637 int64_t dateModified = 0;
638 GetLongValueFromResultSet(resultSet, MediaColumn::MEDIA_DATE_MODIFIED, dateModified);
639 std::string uri = PHOTO_URI_PREFIX + to_string(assetId) + MediaFileUtils::GetExtraUri(displayName, targetPath) +
640 "?api_version=10&date_modified=" + to_string(dateModified) + "&date_taken=" + to_string(dateTaken);
641 MEDIA_INFO_LOG("Begin generate thumbnail %{public}s, ", uri.c_str());
642 int32_t err = ThumbnailService::GetInstance()->CreateThumbnailFileScaned(uri, targetPath, isSyncGenerateThumbnail);
643 if (err != E_SUCCESS) {
644 MEDIA_ERR_LOG("ThumbnailService CreateThumbnailFileScaned failed : %{public}d", err);
645 }
646 MEDIA_INFO_LOG("Generate thumbnail %{public}s, success ", uri.c_str());
647 return err;
648 }
649
UpdateCoverInfoForAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & oldAssetId,const int32_t & ownerAlbumId,int64_t & newAssetId,const std::string & targetPath)650 static int32_t UpdateCoverInfoForAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
651 const int32_t &oldAssetId, const int32_t &ownerAlbumId, int64_t &newAssetId, const std::string &targetPath)
652 {
653 if (upgradeStore == nullptr) {
654 MEDIA_INFO_LOG("fail to get rdbstore");
655 return E_DB_FAIL;
656 }
657 const std::string QUERY_ALBUM_COVER_INFO =
658 "SELECT cover_uri FROM PhotoAlbum WHERE album_id = " + to_string(ownerAlbumId) +
659 " AND cover_uri like 'file://media/Photo/" + to_string(oldAssetId) + "%'";
660 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_ALBUM_COVER_INFO);
661 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
662 MEDIA_INFO_LOG("No need to update cover_uri");
663 return E_OK;
664 }
665 string newCoverUri = MediaLibraryFormMapOperations::GetUriByFileId(newAssetId, targetPath);
666 MEDIA_INFO_LOG("New cover uri is %{public}s", targetPath.c_str());
667 const std::string UPDATE_ALBUM_COVER_URI =
668 "UPDATE PhotoAlbum SET cover_uri = '" + newCoverUri +"' WHERE album_id = " + to_string(ownerAlbumId);
669 int32_t ret = upgradeStore->ExecuteSql(UPDATE_ALBUM_COVER_URI);
670 CHECK_AND_RETURN_RET_LOG(ret == NativeRdb::E_OK, E_HAS_DB_ERROR,
671 "update cover uri failed, ret = %{public}d, target album is %{public}d", ret, ownerAlbumId);
672 return E_OK;
673 }
674
CopyLocalFile(shared_ptr<NativeRdb::ResultSet> & resultSet,const int32_t & ownerAlbumId,const std::string displayName,std::string & targetPath,const int32_t & assetId)675 static int32_t CopyLocalFile(shared_ptr<NativeRdb::ResultSet> &resultSet, const int32_t &ownerAlbumId,
676 const std::string displayName, std::string &targetPath, const int32_t &assetId)
677 {
678 MEDIA_INFO_LOG("begin copy local file, fileId:%{public}d, and target album:%{public}d", assetId, ownerAlbumId);
679 std::string srcPath = "";
680 GetSourceFilePath(srcPath, resultSet);
681
682 int32_t mediaType;
683 GetIntValueFromResultSet(resultSet, MediaColumn::MEDIA_TYPE, mediaType);
684 buildTargetFilePath(targetPath, displayName, mediaType);
685 if (targetPath.empty()) {
686 MEDIA_ERR_LOG("Build target path fail, origin file is %{public}s", srcPath.c_str());
687 return E_INVALID_PATH;
688 }
689 MEDIA_INFO_LOG("begin copy local file, scrPath is %{public}s, and target path is %{public}s",
690 srcPath.c_str(), targetPath.c_str());
691 // Copy photo files, supporting copy moving photo's video and extraData folder.
692 int32_t err = PhotoFileOperation().CopyPhoto(resultSet, targetPath);
693 if (err != E_OK) {
694 MEDIA_ERR_LOG("CopyPhoto failed, srcPath = %{public}s, targetPath = %{public}s, ret = %{public}d",
695 srcPath.c_str(), targetPath.c_str(), err);
696 return err;
697 }
698 return E_OK;
699 }
700
CopyMateData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,shared_ptr<NativeRdb::ResultSet> & resultSet,int64_t & newAssetId,std::string & targetPath,const MediaAssetCopyInfo & copyInfo)701 static int32_t CopyMateData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore, shared_ptr<NativeRdb::ResultSet>
702 &resultSet, int64_t &newAssetId, std::string &targetPath, const MediaAssetCopyInfo ©Info)
703 {
704 NativeRdb::ValuesBucket values;
705 int32_t err = BuildInsertValuesBucket(upgradeStore, values, resultSet, copyInfo);
706 if (err != E_OK) {
707 MEDIA_ERR_LOG("Insert meta data fail and delete migrated file %{public}s ", targetPath.c_str());
708 DeleteFile(targetPath);
709 return err;
710 }
711 err = copyMetaData(upgradeStore, newAssetId, values);
712 if (err != E_OK) {
713 MEDIA_ERR_LOG("Insert meta data fail and delete migrated file err %{public}d ", err);
714 // If insert fails, delete the moved file to avoid wasted space
715 DeleteFile(targetPath);
716 return err;
717 }
718 return E_OK;
719 }
720
CopyLocalSingleFile(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & ownerAlbumId,shared_ptr<NativeRdb::ResultSet> & resultSet,int64_t & newAssetId,std::string displayName)721 int32_t MediaLibraryAlbumFusionUtils::CopyLocalSingleFile(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
722 const int32_t &ownerAlbumId, shared_ptr<NativeRdb::ResultSet> &resultSet, int64_t &newAssetId,
723 std::string displayName)
724 {
725 if (upgradeStore == nullptr) {
726 MEDIA_INFO_LOG("fail to get rdbstore");
727 return E_DB_FAIL;
728 }
729
730 int32_t assetId;
731 GetIntValueFromResultSet(resultSet, MediaColumn::MEDIA_ID, assetId);
732 GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_NAME, displayName);
733 std::string targetPath = "";
734 int32_t err = CopyLocalFile(resultSet, ownerAlbumId, displayName, targetPath, assetId);
735 if (err != E_OK) {
736 MEDIA_INFO_LOG("Failed to copy local file.");
737 return E_ERR;
738 }
739
740 MediaAssetCopyInfo copyInfo(targetPath, false, ownerAlbumId, displayName);
741 err = CopyMateData(upgradeStore, resultSet, newAssetId, targetPath, copyInfo);
742 if (err != E_OK) {
743 MEDIA_INFO_LOG("Failed to copy local file.");
744 return E_ERR;
745 }
746
747 err = UpdateRelationship(upgradeStore, assetId, newAssetId, ownerAlbumId, true);
748 if (err != E_OK) {
749 MEDIA_ERR_LOG("UpdateRelationship fail, assetId: %{public}d, newAssetId: %{public}lld,"
750 "ownerAlbumId: %{public}d, ret = %{public}d", assetId, (long long)newAssetId, ownerAlbumId, err);
751 return E_OK;
752 }
753
754 err = PhotoFileOperation().CopyThumbnail(resultSet, targetPath, newAssetId);
755 if (err != E_OK && GenerateThumbnail(newAssetId, targetPath, resultSet, false) != E_SUCCESS) {
756 MediaLibraryRdbUtils::UpdateThumbnailRelatedDataToDefault(upgradeStore, newAssetId);
757 MEDIA_ERR_LOG("Copy thumbnail failed, targetPath = %{public}s, ret = %{public}d, newAssetId = %{public}" PRId64,
758 targetPath.c_str(), err, newAssetId);
759 return err;
760 }
761 UpdateCoverInfoForAlbum(upgradeStore, assetId, ownerAlbumId, newAssetId, targetPath);
762 return E_OK;
763 }
764
CopyLocalSingleFileSync(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & ownerAlbumId,shared_ptr<NativeRdb::ResultSet> & resultSet,int64_t & newAssetId,const std::string displayName)765 static int32_t CopyLocalSingleFileSync(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore, const int32_t
766 &ownerAlbumId, shared_ptr<NativeRdb::ResultSet> &resultSet, int64_t &newAssetId, const std::string displayName)
767 {
768 if (upgradeStore == nullptr) {
769 MEDIA_INFO_LOG("fail to get rdbstore");
770 return E_DB_FAIL;
771 }
772
773 int32_t assetId;
774 GetIntValueFromResultSet(resultSet, MediaColumn::MEDIA_ID, assetId);
775 std::string targetPath = "";
776 int32_t err = CopyLocalFile(resultSet, ownerAlbumId, displayName, targetPath, assetId);
777 if (err != E_OK) {
778 MEDIA_INFO_LOG("Failed to copy local file.");
779 return E_ERR;
780 }
781
782 MediaAssetCopyInfo copyInfo(targetPath, false, ownerAlbumId, displayName, false);
783 err = CopyMateData(upgradeStore, resultSet, newAssetId, targetPath, copyInfo);
784 if (err != E_OK) {
785 MEDIA_INFO_LOG("Failed to copy local file.");
786 return E_ERR;
787 }
788
789 err = UpdateRelationship(upgradeStore, assetId, newAssetId, ownerAlbumId, true);
790 if (err != E_OK) {
791 MEDIA_ERR_LOG("UpdateRelationship fail, assetId: %{public}d, newAssetId: %{public}lld,"
792 "ownerAlbumId: %{public}d, ret = %{public}d",
793 assetId, static_cast<long long>(newAssetId), ownerAlbumId, err);
794 return E_OK;
795 }
796
797 err = PhotoFileOperation().CopyThumbnail(resultSet, targetPath, newAssetId);
798 if (err != E_OK && GenerateThumbnail(newAssetId, targetPath, resultSet, true) != E_SUCCESS) {
799 MediaLibraryRdbUtils::UpdateThumbnailRelatedDataToDefault(upgradeStore, newAssetId);
800 MEDIA_ERR_LOG("Copy thumbnail failed, targetPath = %{public}s, ret = %{public}d, newAssetId = %{public}" PRId64,
801 targetPath.c_str(), err, newAssetId);
802 return err;
803 }
804 UpdateCoverInfoForAlbum(upgradeStore, assetId, ownerAlbumId, newAssetId, targetPath);
805 return E_OK;
806 }
807
SetRefreshAlbum(bool needRefresh)808 void MediaLibraryAlbumFusionUtils::SetRefreshAlbum(bool needRefresh)
809 {
810 isNeedRefreshAlbum = needRefresh;
811 }
812
CopyCloudSingleFile(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & assetId,const int32_t & ownerAlbumId,shared_ptr<NativeRdb::ResultSet> & resultSet,int64_t & newAssetId)813 int32_t MediaLibraryAlbumFusionUtils::CopyCloudSingleFile(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
814 const int32_t &assetId, const int32_t &ownerAlbumId, shared_ptr<NativeRdb::ResultSet> &resultSet,
815 int64_t &newAssetId)
816 {
817 if (upgradeStore == nullptr) {
818 MEDIA_INFO_LOG("fail to get rdbstore");
819 return E_DB_FAIL;
820 }
821 MEDIA_INFO_LOG("Begin copy cloud file, fileId is %{public}d, and target album is %{public}d",
822 assetId, ownerAlbumId);
823 std::string srcPath = "";
824 std::string targetPath = "";
825 GetSourceFilePath(srcPath, resultSet);
826
827 std::string displayName;
828 int32_t mediaType;
829 GetStringValueFromResultSet(resultSet, MediaColumn::MEDIA_NAME, displayName);
830 GetIntValueFromResultSet(resultSet, MediaColumn::MEDIA_TYPE, mediaType);
831 buildTargetFilePath(targetPath, displayName, mediaType);
832 if (targetPath.empty()) {
833 MEDIA_ERR_LOG("Build target path fail, origin file is %{public}s", srcPath.c_str());
834 return E_INVALID_PATH;
835 }
836 MEDIA_INFO_LOG("Begin copy thumbnail original scrPath is %{public}s, and target path is %{public}s",
837 srcPath.c_str(), targetPath.c_str());
838 int32_t err = CopyOriginThumbnail(srcPath, targetPath);
839 CHECK_AND_RETURN_RET(err == E_OK, err);
840
841 MediaAssetCopyInfo copyInfo(targetPath, true, ownerAlbumId);
842 NativeRdb::ValuesBucket values;
843 err = BuildInsertValuesBucket(upgradeStore, values, resultSet, copyInfo);
844 if (err != E_OK) {
845 MEDIA_ERR_LOG("Build meta data fail and delete migrated file %{public}s ", targetPath.c_str());
846 DeleteThumbnail(targetPath);
847 return err;
848 }
849 err = copyMetaData(upgradeStore, newAssetId, values);
850 if (err != E_OK) {
851 // If insert fails, delete the moved file to avoid wasted space
852 MEDIA_ERR_LOG("Build meta data fail and delete migrated file %{public}s ", targetPath.c_str());
853 DeleteThumbnail(targetPath);
854 return err;
855 }
856 ThumbnailService::GetInstance()->CreateAstcCloudDownload(to_string(newAssetId), true);
857 err = UpdateRelationship(upgradeStore, assetId, newAssetId, ownerAlbumId, false);
858 CHECK_AND_RETURN_RET(err == E_OK, err);
859 UpdateCoverInfoForAlbum(upgradeStore, assetId, ownerAlbumId, newAssetId, targetPath);
860 return E_OK;
861 }
862
SendNewAssetNotify(string newFileAssetUri,const shared_ptr<MediaLibraryRdbStore> & rdbStore)863 void SendNewAssetNotify(string newFileAssetUri, const shared_ptr<MediaLibraryRdbStore> &rdbStore)
864 {
865 vector<string> systemAlbumsExcludeSource = {
866 to_string(PhotoAlbumSubType::FAVORITE),
867 to_string(PhotoAlbumSubType::VIDEO),
868 to_string(PhotoAlbumSubType::HIDDEN),
869 to_string(PhotoAlbumSubType::TRASH),
870 to_string(PhotoAlbumSubType::IMAGE),
871 to_string(PhotoAlbumSubType::CLOUD_ENHANCEMENT),
872 };
873 MediaLibraryRdbUtils::UpdateSystemAlbumInternal(rdbStore, systemAlbumsExcludeSource, true);
874 MediaLibraryRdbUtils::UpdateUserAlbumByUri(rdbStore, { newFileAssetUri });
875 MediaLibraryRdbUtils::UpdateSourceAlbumByUri(rdbStore, { newFileAssetUri });
876
877 auto watch = MediaLibraryNotify::GetInstance();
878 if (watch == nullptr) {
879 MEDIA_ERR_LOG("Can not get MediaLibraryNotify, fail to send new asset notify.");
880 return;
881 }
882 watch->Notify(newFileAssetUri, NotifyType::NOTIFY_ADD);
883 watch->Notify(newFileAssetUri, NotifyType::NOTIFY_ALBUM_ADD_ASSET);
884 }
885
CloneSingleAsset(const int64_t & assetId,const string title)886 int32_t MediaLibraryAlbumFusionUtils::CloneSingleAsset(const int64_t &assetId, const string title)
887 {
888 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
889 if (rdbStore == nullptr) {
890 MEDIA_ERR_LOG("Failed to get rdbStore.");
891 return E_DB_FAIL;
892 }
893
894 const std::string querySql = "SELECT * FROM Photos WHERE file_id = ?";
895 std::vector<NativeRdb::ValueObject> params = { assetId };
896 shared_ptr<NativeRdb::ResultSet> resultSet = rdbStore->QuerySql(querySql, params);
897 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
898 MEDIA_INFO_LOG("Query not matched data fails");
899 return E_DB_FAIL;
900 }
901
902 string oldDisplayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
903 string suffix = MediaFileUtils::SplitByChar(oldDisplayName, '.');
904 if (suffix.empty()) {
905 MEDIA_ERR_LOG("Failed to get file suffix.");
906 return E_FAIL;
907 }
908
909 string displayName = title + "." + suffix;
910 int32_t ownerAlbumId;
911 GetIntValueFromResultSet(resultSet, PhotoColumn::PHOTO_OWNER_ALBUM_ID, ownerAlbumId);
912 int64_t newAssetId = -1;
913 int32_t err = CopyLocalSingleFileSync(rdbStore, ownerAlbumId, resultSet, newAssetId, displayName);
914 if (err != E_OK) {
915 MEDIA_ERR_LOG("Clone local asset failed, ret = %{public}d, assetId = %{public}lld", err, (long long)assetId);
916 return err;
917 }
918
919 RdbPredicates newPredicates(PhotoColumn::PHOTOS_TABLE);
920 newPredicates.EqualTo(PhotoColumn::MEDIA_ID, newAssetId);
921 vector<string> columns = {
922 PhotoColumn::MEDIA_FILE_PATH, MediaColumn::MEDIA_HIDDEN
923 };
924 shared_ptr<NativeRdb::ResultSet> newResultSet = rdbStore->Query(newPredicates, columns);
925 if (newResultSet == nullptr || newResultSet->GoToFirstRow() != NativeRdb::E_OK) {
926 MEDIA_INFO_LOG("Query not matched data fails");
927 return E_DB_FAIL;
928 }
929
930 string newFileAssetUri = MediaFileUtils::GetFileAssetUri(GetStringVal(MediaColumn::MEDIA_FILE_PATH, newResultSet),
931 displayName, newAssetId);
932 int32_t isHidden = GetInt32Val(MediaColumn::MEDIA_HIDDEN, newResultSet);
933 if (isHidden == PHOTO_HIDDEN_FLAG) {
934 MediaLibraryRdbUtils::UpdateSysAlbumHiddenState(rdbStore);
935 }
936 SendNewAssetNotify(newFileAssetUri, rdbStore);
937 MEDIA_INFO_LOG("End clone asset, newAssetId = %{public}lld", (long long)newAssetId);
938 return newAssetId;
939 }
940
GetNoOwnerDataCnt(const std::shared_ptr<MediaLibraryRdbStore> store)941 static int32_t GetNoOwnerDataCnt(const std::shared_ptr<MediaLibraryRdbStore> store)
942 {
943 NativeRdb::RdbPredicates rdbPredicates(PhotoColumn::PHOTOS_TABLE);
944 rdbPredicates.EqualTo(PhotoColumn::PHOTO_OWNER_ALBUM_ID, 0);
945 vector<string> columns;
946 int rowCount = 0;
947 shared_ptr<NativeRdb::ResultSet> resultSet = store->Query(rdbPredicates, columns);
948 if (resultSet == nullptr || resultSet->GetRowCount(rowCount) != NativeRdb::E_OK) {
949 MEDIA_ERR_LOG("Query not matched data fails");
950 }
951 MEDIA_INFO_LOG("Begin handle no owner data: count %{public}d", rowCount);
952 return rowCount;
953 }
954
HandleNoOwnerData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)955 int32_t MediaLibraryAlbumFusionUtils::HandleNoOwnerData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
956 {
957 if (upgradeStore == nullptr) {
958 MEDIA_INFO_LOG("fail to get rdbstore");
959 return E_DB_FAIL;
960 }
961 auto rowCount = GetNoOwnerDataCnt(upgradeStore);
962 SetRefreshAlbum(rowCount > 0);
963 const std::string UPDATE_NO_OWNER_ASSET_INTO_OTHER_ALBUM = "UPDATE PHOTOS SET owner_album_id = "
964 "(SELECT album_id FROM PhotoAlbum where album_name = '其它') WHERE owner_album_id = 0";
965 int32_t ret = upgradeStore->ExecuteSql(UPDATE_NO_OWNER_ASSET_INTO_OTHER_ALBUM);
966 if (ret != NativeRdb::E_OK) {
967 MEDIA_ERR_LOG("UPDATE_NO_OWNER_ASSET_INTO_OTHER_ALBUM failed, ret = %{public}d", ret);
968 return E_HAS_DB_ERROR;
969 }
970 return E_OK;
971 }
972
HandleRestData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & assetId,const std::vector<int32_t> & restOwnerAlbumIds,int32_t & handledCount)973 int32_t MediaLibraryAlbumFusionUtils::HandleRestData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
974 const int32_t &assetId, const std::vector<int32_t> &restOwnerAlbumIds, int32_t &handledCount)
975 {
976 MEDIA_INFO_LOG("Begin handle rest data assetId is %{public}d", assetId);
977 if (upgradeStore == nullptr) {
978 MEDIA_INFO_LOG("fail to get rdbstore");
979 return E_DB_FAIL;
980 }
981 const std::string QUERY_FILE_META_INFO =
982 "SELECT * FROM Photos WHERE file_id = " + to_string(assetId);
983 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_FILE_META_INFO);
984 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
985 MEDIA_INFO_LOG("Query not matched data fails");
986 return E_DB_FAIL;
987 }
988 int64_t newAssetId = -1;
989 if (isLocalAsset(resultSet)) {
990 MEDIA_INFO_LOG("file is local asset %{public}d", assetId);
991 // skip first one, already handled
992 for (size_t i = 0; i < restOwnerAlbumIds.size(); i++) {
993 int32_t err = CopyLocalSingleFile(upgradeStore, restOwnerAlbumIds[i], resultSet, newAssetId);
994 if (err != E_OK) {
995 MEDIA_WARN_LOG("Copy file fails, fileId is %{public}d", assetId);
996 continue;
997 }
998 MEDIA_INFO_LOG("Copy file success, fileId is %{public}d, albumId is %{public}d",
999 assetId, restOwnerAlbumIds[i]);
1000 handledCount++;
1001 }
1002 } else {
1003 MEDIA_INFO_LOG("file is cloud asset %{public}d", assetId);
1004 // skip first one, already handled
1005 for (size_t i = 0; i < restOwnerAlbumIds.size(); i++) {
1006 int32_t err = CopyCloudSingleFile(upgradeStore, assetId, restOwnerAlbumIds[i], resultSet, newAssetId);
1007 if (err != E_OK) {
1008 MEDIA_WARN_LOG("Copy cloud file fails, fileId is %{public}d", assetId);
1009 continue;
1010 }
1011 MEDIA_INFO_LOG("Copy cloud file success, fileId is %{public}d, albumId is %{public}d",
1012 assetId, restOwnerAlbumIds[i]);
1013 handledCount++;
1014 }
1015 }
1016 return E_OK;
1017 }
1018
HandleNotMatchedDataMigration(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,std::multimap<int32_t,vector<int32_t>> & notMathedMap)1019 int32_t MediaLibraryAlbumFusionUtils::HandleNotMatchedDataMigration(
1020 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore, std::multimap<int32_t, vector<int32_t>> ¬MathedMap)
1021 {
1022 if (upgradeStore == nullptr) {
1023 MEDIA_INFO_LOG("fail to get rdbstore");
1024 return E_DB_FAIL;
1025 }
1026 static int handledCount = 0;
1027 for (auto it = notMathedMap.begin(); it != notMathedMap.end(); ++it) {
1028 HandleRestData(upgradeStore, it->first, it->second, handledCount);
1029 }
1030 MEDIA_INFO_LOG("handled %{public}d not matched items", handledCount);
1031 // Put no relationship asset into other album
1032 HandleNoOwnerData(upgradeStore);
1033 return E_OK;
1034 }
1035
HandleSingleFileCopy(const shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & assetId,const int32_t & ownerAlbumId,int64_t & newAssetId)1036 int32_t MediaLibraryAlbumFusionUtils::HandleSingleFileCopy(const shared_ptr<MediaLibraryRdbStore> upgradeStore,
1037 const int32_t &assetId, const int32_t &ownerAlbumId, int64_t &newAssetId)
1038 {
1039 MEDIA_INFO_LOG("Begin copy single file assetId is %{public}d", assetId);
1040 if (upgradeStore == nullptr) {
1041 MEDIA_INFO_LOG("fail to get rdbstore");
1042 return E_DB_FAIL;
1043 }
1044 const std::string QUERY_FILE_META_INFO =
1045 "SELECT * FROM Photos WHERE file_id = " + to_string(assetId);
1046 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_FILE_META_INFO);
1047 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1048 MEDIA_INFO_LOG("Query not matched data fails");
1049 return E_DB_FAIL;
1050 }
1051 int32_t err = E_OK;
1052 if (isLocalAsset(resultSet)) {
1053 err = CopyLocalSingleFile(upgradeStore, ownerAlbumId, resultSet, newAssetId);
1054 } else {
1055 err = CopyCloudSingleFile(upgradeStore, assetId, ownerAlbumId, resultSet, newAssetId);
1056 }
1057 if (err != E_OK) {
1058 MEDIA_ERR_LOG("Copy file fails, is file local : %{public}d, fileId is %{public}d",
1059 isLocalAsset(resultSet), assetId);
1060 return err;
1061 }
1062 MEDIA_INFO_LOG("Copy file success, fileId is %{public}d, albumId is %{public}d,"
1063 "and copyed file id is %{public}" PRId64, assetId, ownerAlbumId, newAssetId);
1064 return E_OK;
1065 }
1066
QueryTotalNumberNeedToHandle(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const std::string & querySql)1067 static int32_t QueryTotalNumberNeedToHandle(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1068 const std::string &querySql)
1069 {
1070 int32_t rowCount = 0;
1071 if (upgradeStore == nullptr) {
1072 MEDIA_INFO_LOG("fail to get rdbstore");
1073 return rowCount;
1074 }
1075 if (querySql.empty()) {
1076 return rowCount;
1077 }
1078 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(querySql);
1079 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1080 MEDIA_INFO_LOG("No need to update cover_uri");
1081 return rowCount;
1082 }
1083 if (resultSet->GetInt(0, rowCount) != NativeRdb::E_OK) {
1084 return rowCount;
1085 }
1086 return rowCount;
1087 }
1088
HandleNotMatchedDataFusion(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1089 int32_t MediaLibraryAlbumFusionUtils::HandleNotMatchedDataFusion(
1090 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1091 {
1092 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_2: Start handle not matched relationship");
1093 if (upgradeStore == nullptr) {
1094 MEDIA_INFO_LOG("fail to get rdbstore");
1095 return E_DB_FAIL;
1096 }
1097 int64_t beginTime = MediaFileUtils::UTCTimeMilliSeconds();
1098 int32_t totalNumber = QueryTotalNumberNeedToHandle(upgradeStore, QUERY_NOT_MATCHED_COUNT_IN_PHOTOMAP);
1099 MEDIA_INFO_LOG("QueryTotalNumberNeedToHandle, totalNumber=%{public}d", totalNumber);
1100 std::multimap<int32_t, vector<int32_t>> notMatchedMap;
1101 for (int32_t offset = 0; offset < totalNumber; offset += ALBUM_FUSION_BATCH_COUNT) {
1102 MEDIA_INFO_LOG("ALBUM_FUSE: handle batch clean, offset: %{public}d", offset);
1103 notMatchedMap.clear();
1104 int32_t err = QueryNoMatchedMap(upgradeStore, notMatchedMap, true);
1105 if (err != NativeRdb::E_OK) {
1106 MEDIA_ERR_LOG("Fatal error! Failed to query not matched map data");
1107 break;
1108 }
1109 if (notMatchedMap.size() != 0) {
1110 MEDIA_INFO_LOG("There are %{public}d items need to migrate", (int)notMatchedMap.size());
1111 HandleNotMatchedDataMigration(upgradeStore, notMatchedMap);
1112 }
1113 }
1114 MEDIA_INFO_LOG("ALBUM_FUSE: STEP_2: end handle not matched relationship, cost %{public}ld",
1115 (long)(MediaFileUtils::UTCTimeMilliSeconds() - beginTime));
1116 return E_OK;
1117 }
1118
QuerySourceAlbumLPath(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,std::string & lPath,const std::string bundle_name,const std::string album_name)1119 static void QuerySourceAlbumLPath(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1120 std::string &lPath, const std::string bundle_name, const std::string album_name)
1121 {
1122 std::string queryExpiredAlbumInfo = "";
1123 if (bundle_name.empty()) {
1124 queryExpiredAlbumInfo = "SELECT lPath FROM album_plugin WHERE "
1125 "album_name = '" + album_name + "' AND priority = '1'";
1126 } else {
1127 queryExpiredAlbumInfo = "SELECT lPath FROM album_plugin WHERE bundle_name = '" + bundle_name +
1128 "' OR album_name = '" + album_name + "' AND priority = '1'";
1129 }
1130 shared_ptr<NativeRdb::ResultSet> albumPluginResultSet = upgradeStore->QuerySql(queryExpiredAlbumInfo);
1131 if (albumPluginResultSet == nullptr || albumPluginResultSet->GoToFirstRow() != NativeRdb::E_OK) {
1132 MEDIA_INFO_LOG("Query lpath data fails, bundleName is %{public}s and albumName is %{public}s",
1133 bundle_name.c_str(), album_name.c_str());
1134 lPath = "/Pictures/" + album_name;
1135 return;
1136 }
1137 GetStringValueFromResultSet(albumPluginResultSet, PhotoAlbumColumns::ALBUM_LPATH, lPath);
1138 if (lPath.empty()) {
1139 lPath = "/Pictures/" + album_name;
1140 }
1141 MEDIA_ERR_LOG("Album lPath is %{public}s", lPath.c_str());
1142 }
1143
BuildAlbumInsertValuesSetName(const std::shared_ptr<MediaLibraryRdbStore> & upgradeStore,NativeRdb::ValuesBucket & values,shared_ptr<NativeRdb::ResultSet> & resultSet,const string & newAlbumName)1144 void MediaLibraryAlbumFusionUtils::BuildAlbumInsertValuesSetName(
1145 const std::shared_ptr<MediaLibraryRdbStore>& upgradeStore, NativeRdb::ValuesBucket &values,
1146 shared_ptr<NativeRdb::ResultSet> &resultSet, const string &newAlbumName)
1147 {
1148 for (auto it = albumColumnTypeMap.begin(); it != albumColumnTypeMap.end(); ++it) {
1149 string columnName = it->first;
1150 ResultSetDataType columnType = it->second;
1151 ParsingAndFillValue(values, columnName, columnType, resultSet);
1152 }
1153
1154 std::string lPath = "/Pictures/Users/" + newAlbumName;
1155 values.PutInt(PhotoAlbumColumns::ALBUM_PRIORITY, 1);
1156 values.PutString(PhotoAlbumColumns::ALBUM_LPATH, lPath);
1157 values.Delete(PhotoAlbumColumns::ALBUM_NAME);
1158 values.PutString(PhotoAlbumColumns::ALBUM_NAME, newAlbumName);
1159 int64_t albumDataAdded = 0;
1160 GetLongValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_DATE_ADDED, albumDataAdded);
1161 values.PutLong(PhotoAlbumColumns::ALBUM_DATE_ADDED, albumDataAdded);
1162 }
1163
CopyAlbumMetaData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,std::shared_ptr<NativeRdb::ResultSet> & resultSet,const int32_t & oldAlbumId,int64_t & newAlbumId)1164 static int32_t CopyAlbumMetaData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1165 std::shared_ptr<NativeRdb::ResultSet> &resultSet, const int32_t &oldAlbumId, int64_t &newAlbumId)
1166 {
1167 MEDIA_INFO_LOG("Begin copy album Meta Data!!!");
1168 if (upgradeStore == nullptr || resultSet == nullptr || oldAlbumId == -1) {
1169 MEDIA_ERR_LOG("invalid parameter");
1170 return E_INVALID_ARGUMENTS;
1171 }
1172 NativeRdb::ValuesBucket values;
1173 for (auto it = albumColumnTypeMap.begin(); it != albumColumnTypeMap.end(); ++it) {
1174 std::string columnName = it->first;
1175 ResultSetDataType columnType = it->second;
1176 ParsingAndFillValue(values, columnName, columnType, resultSet);
1177 }
1178
1179 newAlbumId =
1180 PhotoAlbumCopyMetaDataOperation()
1181 .SetRdbStore(upgradeStore)
1182 .CopyAlbumMetaData(values);
1183 if (newAlbumId <= 0) {
1184 return E_HAS_DB_ERROR;
1185 }
1186 MEDIA_ERR_LOG("Insert copyed album success,oldAlbumId is = %{public}d newAlbumId is %{public}" PRId64,
1187 oldAlbumId, newAlbumId);
1188 return E_OK;
1189 }
1190
BatchDeleteAlbumAndUpdateRelation(const int32_t & oldAlbumId,const int64_t & newAlbumId,bool isCloudAblum,std::shared_ptr<TransactionOperations> trans)1191 static int32_t BatchDeleteAlbumAndUpdateRelation(const int32_t &oldAlbumId, const int64_t &newAlbumId,
1192 bool isCloudAblum, std::shared_ptr<TransactionOperations> trans)
1193 {
1194 if (trans == nullptr) {
1195 MEDIA_ERR_LOG("transactionOprn is null");
1196 return E_HAS_DB_ERROR;
1197 }
1198 std::string DELETE_EXPIRED_ALBUM = "";
1199 if (isCloudAblum) {
1200 DELETE_EXPIRED_ALBUM = "UPDATE PhotoAlbum SET dirty = '4' WHERE album_id = " + to_string(oldAlbumId);
1201 } else {
1202 DELETE_EXPIRED_ALBUM = "DELETE FROM PhotoAlbum WHERE album_id = " + to_string(oldAlbumId);
1203 }
1204 int32_t ret = trans->ExecuteSql(DELETE_EXPIRED_ALBUM);
1205 if (ret != NativeRdb::E_OK) {
1206 MEDIA_ERR_LOG("DELETE expired album failed, ret = %{public}d, albumId is %{public}d",
1207 ret, oldAlbumId);
1208 return E_HAS_DB_ERROR;
1209 }
1210 const std::string UPDATE_NEW_ALBUM_ID_IN_PHOTO_MAP = "UPDATE PhotoMap SET map_album = " +
1211 to_string(newAlbumId) + " WHERE dirty != '4' AND map_album = " + to_string(oldAlbumId);
1212 ret = trans->ExecuteSql(UPDATE_NEW_ALBUM_ID_IN_PHOTO_MAP);
1213 if (ret != NativeRdb::E_OK) {
1214 MEDIA_ERR_LOG("Update relationship in photo map fails, ret = %{public}d, albumId is %{public}d",
1215 ret, oldAlbumId);
1216 return E_HAS_DB_ERROR;
1217 }
1218 const std::string UPDATE_NEW_ALBUM_ID_IN_PHOTOS = "UPDATE Photos SET owner_album_id = " +
1219 to_string(newAlbumId) + " WHERE dirty != '4' AND owner_album_id = " + to_string(oldAlbumId);
1220 ret = trans->ExecuteSql(UPDATE_NEW_ALBUM_ID_IN_PHOTOS);
1221 if (ret != NativeRdb::E_OK) {
1222 MEDIA_ERR_LOG("Update relationship in photo map fails, ret = %{public}d, albumId is %{public}d",
1223 ret, oldAlbumId);
1224 return E_HAS_DB_ERROR;
1225 }
1226 return E_OK;
1227 }
1228
DeleteAlbumAndUpdateRelationship(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,const int32_t & oldAlbumId,const int64_t & newAlbumId,bool isCloudAblum)1229 int32_t MediaLibraryAlbumFusionUtils::DeleteAlbumAndUpdateRelationship(
1230 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore, const int32_t &oldAlbumId, const int64_t &newAlbumId,
1231 bool isCloudAblum)
1232 {
1233 if (upgradeStore == nullptr) {
1234 MEDIA_ERR_LOG("invalid rdbstore or nullptr map");
1235 return E_INVALID_ARGUMENTS;
1236 }
1237 if (newAlbumId == -1) {
1238 MEDIA_ERR_LOG("Target album id error, origin albumId is %{public}d", oldAlbumId);
1239 return E_INVALID_ARGUMENTS;
1240 }
1241
1242 std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
1243 int32_t errCode = E_OK;
1244 std::function<int(void)> func = [&]()->int {
1245 return BatchDeleteAlbumAndUpdateRelation(oldAlbumId, newAlbumId, isCloudAblum, trans);
1246 };
1247 errCode = trans->RetryTrans(func);
1248 if (errCode != E_OK) {
1249 MEDIA_ERR_LOG("DeleteAlbumAndUpdateRelationship trans retry fail!, ret = %{public}d", errCode);
1250 }
1251 return errCode;
1252 }
1253
IsCloudAlbum(shared_ptr<NativeRdb::ResultSet> resultSet)1254 bool MediaLibraryAlbumFusionUtils::IsCloudAlbum(shared_ptr<NativeRdb::ResultSet> resultSet)
1255 {
1256 string cloudId = "";
1257 GetStringValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_CLOUD_ID, cloudId);
1258 return !cloudId.empty();
1259 }
1260
HandleExpiredAlbumData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1261 int32_t MediaLibraryAlbumFusionUtils::HandleExpiredAlbumData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1262 {
1263 if (upgradeStore == nullptr) {
1264 MEDIA_ERR_LOG("invalid rdbstore or nullptr map");
1265 return E_INVALID_ARGUMENTS;
1266 }
1267 const std::string QUERY_EXPIRED_ALBUM_INFO =
1268 "SELECT * FROM PhotoAlbum WHERE (album_type = 2048 OR album_type = 0) "
1269 "AND cloud_id not like '%default-album%' AND (lpath IS NULL OR lpath = '') AND dirty != 4";
1270 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_EXPIRED_ALBUM_INFO);
1271 if (resultSet == nullptr) {
1272 MEDIA_ERR_LOG("Query not matched data fails");
1273 return E_HAS_DB_ERROR;
1274 }
1275 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1276 int32_t oldAlbumId = -1;
1277 int64_t newAlbumId = -1;
1278 GetIntValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_ID, oldAlbumId);
1279 CopyAlbumMetaData(upgradeStore, resultSet, oldAlbumId, newAlbumId);
1280 DeleteAlbumAndUpdateRelationship(upgradeStore, oldAlbumId, newAlbumId, IsCloudAlbum(resultSet));
1281 MEDIA_ERR_LOG("Finish handle old album %{public}d, new inserted album id is %{public}" PRId64,
1282 oldAlbumId, newAlbumId);
1283 }
1284 return E_OK;
1285 }
1286
KeepHiddenAlbumAssetSynced(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1287 static int32_t KeepHiddenAlbumAssetSynced(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1288 {
1289 if (upgradeStore == nullptr) {
1290 MEDIA_INFO_LOG("fail to get rdbstore");
1291 return E_DB_FAIL;
1292 }
1293 const std::string UPDATE_DIRTY_FLAG_FOR_DUAL_HIDDEN_ASSET =
1294 "UPDATE " + PhotoColumn::PHOTOS_TABLE + " SET dirty = 0 WHERE owner_album_id ="
1295 "(SELECT album_id FROM PhotoALbum where (cloud_id = "
1296 "'default-album-4' OR album_name = '.hiddenAlbum') and dirty != 4)";
1297 int32_t err = upgradeStore->ExecuteSql(UPDATE_DIRTY_FLAG_FOR_DUAL_HIDDEN_ASSET);
1298 if (err != NativeRdb::E_OK) {
1299 MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s",
1300 UPDATE_DIRTY_FLAG_FOR_DUAL_HIDDEN_ASSET.c_str());
1301 return err;
1302 }
1303 return E_OK;
1304 }
1305
RemediateErrorSourceAlbumSubType(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1306 static int32_t RemediateErrorSourceAlbumSubType(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1307 {
1308 if (upgradeStore == nullptr) {
1309 MEDIA_INFO_LOG("fail to get rdbstore");
1310 return E_DB_FAIL;
1311 }
1312 const std::string REMEDIATE_ERROR_SOURCE_ALBUM_SUBTYPE =
1313 "UPDATE " + PhotoAlbumColumns::TABLE + " SET album_subtype = 2049 "
1314 "WHERE album_type = 2048 and album_subtype <> 2049";
1315 int32_t err = upgradeStore->ExecuteSql(REMEDIATE_ERROR_SOURCE_ALBUM_SUBTYPE);
1316 if (err != NativeRdb::E_OK) {
1317 MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s",
1318 REMEDIATE_ERROR_SOURCE_ALBUM_SUBTYPE.c_str());
1319 return err;
1320 }
1321 return E_OK;
1322 }
1323
RebuildAlbumAndFillCloudValue(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1324 int32_t MediaLibraryAlbumFusionUtils::RebuildAlbumAndFillCloudValue(
1325 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1326 {
1327 MEDIA_INFO_LOG("Start rebuild album table and compensate loss value");
1328 if (upgradeStore == nullptr) {
1329 MEDIA_INFO_LOG("fail to get rdbstore");
1330 return E_DB_FAIL;
1331 }
1332 int32_t err = HandleChangeNameAlbum(upgradeStore);
1333 CompensateLpathForLocalAlbum(upgradeStore);
1334 HandleExpiredAlbumData(upgradeStore);
1335 // Keep dual hidden assets dirty state synced, let cloudsync handle compensating for hidden flags
1336 KeepHiddenAlbumAssetSynced(upgradeStore);
1337 RemediateErrorSourceAlbumSubType(upgradeStore);
1338 HandleMisMatchScreenRecord(upgradeStore);
1339 int32_t albumAffectedCount = PhotoAlbumLPathOperation::GetInstance()
1340 .SetRdbStore(upgradeStore)
1341 .Start()
1342 .CleanInvalidPhotoAlbums()
1343 .CleanDuplicatePhotoAlbums()
1344 .CleanEmptylPathPhotoAlbums()
1345 .GetAlbumAffectedCount();
1346 MediaLibraryAlbumFusionUtils::SetRefreshAlbum(albumAffectedCount > 0);
1347 MEDIA_INFO_LOG("End rebuild album table and compensate loss value");
1348 return E_OK;
1349 }
1350
MergeClashSourceAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,shared_ptr<NativeRdb::ResultSet> & resultSet,const int32_t & sourceAlbumId,const int64_t & targetAlbumId)1351 int32_t MediaLibraryAlbumFusionUtils::MergeClashSourceAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1352 shared_ptr<NativeRdb::ResultSet> &resultSet, const int32_t &sourceAlbumId, const int64_t &targetAlbumId)
1353 {
1354 CHECK_AND_RETURN_RET_LOG(upgradeStore != nullptr, E_DB_FAIL, "fail to get rdbstore");
1355 MEDIA_INFO_LOG("MergeClashSourceAlbum %{public}d, target album is %{public}" PRId64,
1356 sourceAlbumId, targetAlbumId);
1357 if (sourceAlbumId == targetAlbumId) {
1358 return E_OK;
1359 }
1360
1361 DeleteAlbumAndUpdateRelationship(upgradeStore, sourceAlbumId, targetAlbumId, IsCloudAlbum(resultSet));
1362 return E_OK;
1363 }
1364
MergeScreenShotAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,shared_ptr<NativeRdb::ResultSet> & resultSet)1365 static int32_t MergeScreenShotAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1366 shared_ptr<NativeRdb::ResultSet> &resultSet)
1367 {
1368 CHECK_AND_RETURN_RET_LOG(upgradeStore != nullptr, E_DB_FAIL, "fail to get rdbstore");
1369 MEDIA_INFO_LOG("Begin handle expired screen shot album data ");
1370 int32_t oldAlbumId = -1;
1371 int64_t newAlbumId = -1;
1372 GetIntValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_ID, oldAlbumId);
1373 const std::string QUERY_NEW_SCREEN_SHOT_ALBUM_INFO =
1374 "SELECT * FROM PhotoAlbum WHERE album_type = 2048 AND bundle_name = 'com.huawei.hmos.screenshot'"
1375 " AND dirty != 4";
1376 shared_ptr<NativeRdb::ResultSet> newAlbumResultSet = upgradeStore->QuerySql(QUERY_NEW_SCREEN_SHOT_ALBUM_INFO);
1377 MEDIA_INFO_LOG("Begin merge screenshot album, old album is %{public}d", oldAlbumId);
1378 if (newAlbumResultSet == nullptr || newAlbumResultSet->GoToFirstRow() != NativeRdb::E_OK) {
1379 // Create a new bundle name screenshot album
1380 CopyAlbumMetaData(upgradeStore, resultSet, oldAlbumId, newAlbumId);
1381 MEDIA_INFO_LOG("Create new screenshot album, album id is %{public}" PRId64, newAlbumId);
1382 } else {
1383 GetLongValueFromResultSet(newAlbumResultSet, PhotoAlbumColumns::ALBUM_ID, newAlbumId);
1384 }
1385 MEDIA_INFO_LOG("Begin merge screenshot album, new album is %{public}" PRId64, newAlbumId);
1386 MediaLibraryAlbumFusionUtils::MergeClashSourceAlbum(upgradeStore, resultSet, oldAlbumId, newAlbumId);
1387 MEDIA_INFO_LOG("End handle expired screen shot album data ");
1388 return E_OK;
1389 }
1390
MergeScreenRecordAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,shared_ptr<NativeRdb::ResultSet> & resultSet)1391 static int32_t MergeScreenRecordAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1392 shared_ptr<NativeRdb::ResultSet> &resultSet)
1393 {
1394 if (upgradeStore == nullptr) {
1395 MEDIA_INFO_LOG("fail to get rdbstore");
1396 return E_DB_FAIL;
1397 }
1398 MEDIA_INFO_LOG("Begin merge screenrecord album");
1399 int32_t oldAlbumId = -1;
1400 int64_t newAlbumId = -1;
1401 GetIntValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_ID, oldAlbumId);
1402 const std::string QUERY_NEW_SCREEN_RECORD_ALBUM_INFO =
1403 "SELECT * FROM PhotoAlbum WHERE album_type = 2048 AND bundle_name = 'com.huawei.hmos.screenrecorder'"
1404 " AND dirty != 4";
1405 shared_ptr<NativeRdb::ResultSet> newAlbumResultSet = upgradeStore->QuerySql(QUERY_NEW_SCREEN_RECORD_ALBUM_INFO);
1406 if (newAlbumResultSet == nullptr || newAlbumResultSet->GoToFirstRow() != NativeRdb::E_OK) {
1407 // Create a new bundle name screenshot album
1408 CopyAlbumMetaData(upgradeStore, resultSet, oldAlbumId, newAlbumId);
1409 MEDIA_INFO_LOG("Create new screenrecord album, album id is %{public}" PRId64, newAlbumId);
1410 } else {
1411 GetLongValueFromResultSet(newAlbumResultSet, PhotoAlbumColumns::ALBUM_ID, newAlbumId);
1412 }
1413 MediaLibraryAlbumFusionUtils::MergeClashSourceAlbum(upgradeStore, resultSet, oldAlbumId, newAlbumId);
1414 MEDIA_INFO_LOG("End merge screenrecord album");
1415 return E_OK;
1416 }
1417
HandleChangeNameAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1418 int32_t MediaLibraryAlbumFusionUtils::HandleChangeNameAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1419 {
1420 MEDIA_INFO_LOG("Begin handle change name album data");
1421 if (upgradeStore == nullptr) {
1422 MEDIA_ERR_LOG("invalid rdbstore or nullptr map");
1423 return E_INVALID_ARGUMENTS;
1424 }
1425 const std::string QUERY_CHANGE_NAME_ALBUM_INFO =
1426 "SELECT * FROM PhotoAlbum WHERE album_type = 2048"
1427 " AND (bundle_name = 'com.huawei.ohos.screenshot' OR bundle_name = 'com.huawei.ohos.screenrecorder')"
1428 " AND dirty != 4";
1429 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_CHANGE_NAME_ALBUM_INFO);
1430 if (resultSet == nullptr) {
1431 MEDIA_ERR_LOG("Query expired bundle_name fails");
1432 return E_HAS_DB_ERROR;
1433 }
1434 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1435 std::string bundle_name = "";
1436 GetStringValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_BUNDLE_NAME, bundle_name);
1437 if (bundle_name == "com.huawei.ohos.screenshot") {
1438 MergeScreenShotAlbum(upgradeStore, resultSet);
1439 } else {
1440 MergeScreenRecordAlbum(upgradeStore, resultSet);
1441 }
1442 }
1443 MEDIA_INFO_LOG("End handle change name album data");
1444 return E_OK;
1445 }
1446
CompensateLpathForLocalAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1447 int32_t MediaLibraryAlbumFusionUtils::CompensateLpathForLocalAlbum(
1448 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1449 {
1450 MEDIA_INFO_LOG("Begin compensate Lpath for local album");
1451 if (upgradeStore == nullptr) {
1452 MEDIA_ERR_LOG("invalid rdbstore or nullptr map");
1453 return E_INVALID_ARGUMENTS;
1454 }
1455 const std::string QUERY_COMPENSATE_ALBUM_INFO =
1456 "SELECT * FROM PhotoAlbum WHERE cloud_id IS NULL"
1457 " AND (priority IS NULL OR lpath IS NULL) AND dirty != 4 AND album_type IN (0, 2048)";
1458 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_COMPENSATE_ALBUM_INFO);
1459 if (resultSet == nullptr) {
1460 MEDIA_ERR_LOG("Query album info fails");
1461 return E_HAS_DB_ERROR;
1462 }
1463
1464 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1465 int album_id = -1;
1466 int32_t album_type = -1;
1467 std::string album_name = "";
1468 std::string bundle_name = "";
1469 std::string lpath = "";
1470
1471 GetIntValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_ID, album_id);
1472 GetIntValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_TYPE, album_type);
1473 GetStringValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_NAME, album_name);
1474 GetStringValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_BUNDLE_NAME, bundle_name);
1475 GetStringValueFromResultSet(resultSet, PhotoAlbumColumns::ALBUM_LPATH, lpath);
1476
1477 if (lpath.empty()) {
1478 if (album_type == OHOS::Media::PhotoAlbumType::SOURCE) {
1479 QuerySourceAlbumLPath(upgradeStore, lpath, bundle_name, album_name);
1480 } else {
1481 lpath = "/Pictures/Users/" + album_name;
1482 MEDIA_INFO_LOG("Album type is user type and lPath is %{public}s!!!", lpath.c_str());
1483 }
1484 }
1485
1486 const std::string UPDATE_COMPENSATE_ALBUM_DATA =
1487 "UPDATE PhotoAlbum SET lpath = '" + lpath + "', "
1488 "priority = COALESCE ((SELECT priority FROM album_plugin WHERE lpath = '" + lpath + "'), 1) "
1489 "WHERE album_id = " + to_string(album_id);
1490 int32_t err = upgradeStore->ExecuteSql(UPDATE_COMPENSATE_ALBUM_DATA);
1491 if (err != NativeRdb::E_OK) {
1492 MEDIA_ERR_LOG("Fatal error! Failed to exec: %{public}s", UPDATE_COMPENSATE_ALBUM_DATA.c_str());
1493 continue;
1494 }
1495 }
1496 MEDIA_INFO_LOG("End compensate Lpath for local album");
1497 return E_OK;
1498 }
1499
SetParameterToStopSync()1500 void MediaLibraryAlbumFusionUtils::SetParameterToStopSync()
1501 {
1502 auto currentTime = to_string(MediaFileUtils::UTCTimeSeconds());
1503 MEDIA_INFO_LOG("Set parameter for album fusion currentTime:%{public}s", currentTime.c_str());
1504 bool retFlag = system::SetParameter(ALBUM_FUSION_FLAG, currentTime);
1505 if (!retFlag) {
1506 MEDIA_ERR_LOG("Failed to set parameter cloneFlag, retFlag:%{public}d", retFlag);
1507 }
1508 }
1509
SetParameterToStartSync()1510 void MediaLibraryAlbumFusionUtils::SetParameterToStartSync()
1511 {
1512 MEDIA_INFO_LOG("Reset parameter for album fusion");
1513 bool retFlag = system::SetParameter(ALBUM_FUSION_FLAG, "0");
1514 if (!retFlag) {
1515 MEDIA_ERR_LOG("Failed to Set parameter for album fusion, retFlag:%{public}d", retFlag);
1516 }
1517 }
1518
GetAlbumFuseUpgradeStatus()1519 int32_t MediaLibraryAlbumFusionUtils::GetAlbumFuseUpgradeStatus()
1520 {
1521 std::string albumFuseUpgradeStatus = system::GetParameter(ALBUM_FUSION_UPGRADE_STATUS_FLAG, "1");
1522 MEDIA_ERR_LOG("Current album upgrade status :%{public}s", albumFuseUpgradeStatus.c_str());
1523 if (albumFuseUpgradeStatus == "1") {
1524 return ALBUM_FUSION_UPGRADE_SUCCESS;
1525 } else {
1526 return ALBUM_FUSION_UPGRADE_FAIL;
1527 }
1528 }
1529
SetAlbumFuseUpgradeStatus(int32_t upgradeStatus)1530 int32_t MediaLibraryAlbumFusionUtils::SetAlbumFuseUpgradeStatus(int32_t upgradeStatus)
1531 {
1532 if (upgradeStatus != ALBUM_FUSION_UPGRADE_SUCCESS && upgradeStatus != ALBUM_FUSION_UPGRADE_FAIL) {
1533 MEDIA_ERR_LOG("Invalid parameter for album fusion upgrade status :%{public}d", upgradeStatus);
1534 return E_INVALID_ARGUMENTS;
1535 }
1536 MEDIA_INFO_LOG("Set parameter for album fusion upgrade status :%{public}d", upgradeStatus);
1537 bool retFlag = system::SetParameter(ALBUM_FUSION_UPGRADE_STATUS_FLAG, to_string(upgradeStatus));
1538 if (!retFlag) {
1539 MEDIA_ERR_LOG("Failed to set parameter, retFlag:%{public}d", retFlag);
1540 return E_INVALID_MODE;
1541 }
1542 return E_OK;
1543 }
1544
ToLower(const std::string & str)1545 static std::string ToLower(const std::string &str)
1546 {
1547 std::string lowerStr;
1548 std::transform(
1549 str.begin(), str.end(), std::back_inserter(lowerStr), [](unsigned char c) { return std::tolower(c); });
1550 return lowerStr;
1551 }
1552
DeleteDuplicatePhoto(const std::shared_ptr<MediaLibraryRdbStore> store)1553 static int32_t DeleteDuplicatePhoto(const std::shared_ptr<MediaLibraryRdbStore> store)
1554 {
1555 const string sql = "UPDATE Photos SET dirty = 8 WHERE file_id IN ( " +
1556 SQL_GET_DUPLICATE_PHOTO + " )";
1557
1558 int32_t err = store->ExecuteSql(sql);
1559 CHECK_AND_PRINT_LOG(err == NativeRdb::E_OK, "DeleteDuplicatePhoto fail %{public}d", err);
1560 return err;
1561 }
1562
DuplicateDebugPrint(const vector<int32_t> & idArr)1563 void DuplicateDebugPrint(const vector<int32_t> &idArr)
1564 {
1565 constexpr int32_t maxPrintWidth = 50;
1566 string assetStr;
1567 for (auto assetId: idArr) {
1568 assetStr += to_string(assetId) + ",";
1569 if (assetStr.size() > maxPrintWidth) {
1570 MEDIA_DEBUG_LOG("delete dup photo %{public}s", assetStr.c_str());
1571 assetStr = "";
1572 }
1573 }
1574 if (assetStr.size() != 0) {
1575 MEDIA_DEBUG_LOG("delete dup photo %{public}s", assetStr.c_str());
1576 }
1577 }
1578
DuplicateDebug(std::shared_ptr<NativeRdb::ResultSet> resultSet,vector<int32_t> & idArr)1579 void DuplicateDebug(std::shared_ptr<NativeRdb::ResultSet> resultSet, vector<int32_t> &idArr)
1580 {
1581 while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
1582 int32_t colIndex = -1;
1583 int32_t assetId = 0;
1584 resultSet->GetColumnIndex(MediaColumn::MEDIA_ID, colIndex);
1585 if (resultSet->GetInt(colIndex, assetId) != NativeRdb::E_OK) {
1586 MEDIA_ERR_LOG("db error");
1587 break;
1588 }
1589 idArr.push_back(assetId);
1590 }
1591 }
1592
HandleDuplicatePhoto(const std::shared_ptr<MediaLibraryRdbStore> store)1593 static int32_t HandleDuplicatePhoto(const std::shared_ptr<MediaLibraryRdbStore> store)
1594 {
1595 int32_t row = 0;
1596 int32_t count = 0;
1597 // set max loop count to avoid trapped in loop if delete fail
1598 constexpr int32_t maxLoopCount = 1000;
1599 do {
1600 count++;
1601 shared_ptr<NativeRdb::ResultSet> resultSet = store->QuerySql(SQL_GET_DUPLICATE_PHOTO);
1602 if (resultSet == nullptr || resultSet->GetRowCount(row) != NativeRdb::E_OK) {
1603 MEDIA_INFO_LOG("rdb fail");
1604 return E_DB_FAIL;
1605 }
1606 MEDIA_INFO_LOG("duplicate photo %{public}d, need to delete", row);
1607 if (row == 0) {
1608 return E_OK;
1609 }
1610 vector<int32_t> idArr;
1611 DuplicateDebug(resultSet, idArr);
1612 auto err = DeleteDuplicatePhoto(store);
1613 if (err == NativeRdb::E_OK) {
1614 DuplicateDebugPrint(idArr);
1615 } else {
1616 MEDIA_ERR_LOG("duplicate photo %{public}d, delete fail %{public}d", row, err);
1617 }
1618 } while (row > 0 && count < maxLoopCount);
1619
1620 return E_OK;
1621 }
1622
HandleDuplicateAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1623 int32_t MediaLibraryAlbumFusionUtils::HandleDuplicateAlbum(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1624 {
1625 MEDIA_INFO_LOG("Media_Operation: Skip HandleDuplicateAlbum.");
1626 return E_OK;
1627 }
1628
HandleNewCloudDirtyDataImp(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,shared_ptr<NativeRdb::ResultSet> & resultSet,std::vector<int32_t> & restOwnerAlbumIds,int32_t & assetId)1629 static void HandleNewCloudDirtyDataImp(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1630 shared_ptr<NativeRdb::ResultSet> &resultSet, std::vector<int32_t> &restOwnerAlbumIds, int32_t &assetId)
1631 {
1632 int64_t newAssetId = -1;
1633 if (isLocalAsset(resultSet)) {
1634 MEDIA_INFO_LOG("File is local asset %{public}d", assetId);
1635 // skip first one, already handled
1636 for (size_t i = 0; i < restOwnerAlbumIds.size(); i++) {
1637 int32_t err = MediaLibraryAlbumFusionUtils::CopyLocalSingleFile(upgradeStore,
1638 restOwnerAlbumIds[i], resultSet, newAssetId);
1639 if (err != E_OK) {
1640 MEDIA_WARN_LOG("Copy file fails, fileId is %{public}d", assetId);
1641 continue;
1642 }
1643 MEDIA_INFO_LOG("Copy file success, fileId is %{public}d, albumId is %{public}d",
1644 assetId, restOwnerAlbumIds[i]);
1645 }
1646 } else {
1647 MEDIA_INFO_LOG("File is cloud asset %{public}d", assetId);
1648 // skip first one, already handled
1649 for (size_t i = 0; i < restOwnerAlbumIds.size(); i++) {
1650 int32_t err = MediaLibraryAlbumFusionUtils::CopyCloudSingleFile(upgradeStore,
1651 assetId, restOwnerAlbumIds[i], resultSet, newAssetId);
1652 if (err != E_OK) {
1653 MEDIA_WARN_LOG("Copy cloud file fails, fileId is %{public}d", assetId);
1654 continue;
1655 }
1656 MEDIA_INFO_LOG("Copy cloud file success, fileId is %{public}d, albumId is %{public}d",
1657 assetId, restOwnerAlbumIds[i]);
1658 }
1659 }
1660 }
1661
HandleNewCloudDirtyData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,std::multimap<int32_t,vector<int32_t>> & notMathedMap)1662 int32_t MediaLibraryAlbumFusionUtils::HandleNewCloudDirtyData(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore,
1663 std::multimap<int32_t, vector<int32_t>> ¬MathedMap)
1664 {
1665 if (upgradeStore == nullptr) {
1666 MEDIA_ERR_LOG("invalid rdbstore or nullptr map");
1667 return E_INVALID_ARGUMENTS;
1668 }
1669 for (auto it = notMathedMap.begin(); it != notMathedMap.end(); ++it) {
1670 int32_t assetId = it->first;
1671 std::vector<int32_t> &restOwnerAlbumIds = it->second;
1672 const std::string QUERY_FILE_META_INFO =
1673 "SELECT * FROM Photos WHERE file_id = " + to_string(assetId);
1674 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_FILE_META_INFO);
1675 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1676 MEDIA_INFO_LOG("Query not matched data fails");
1677 return E_DB_FAIL;
1678 }
1679 HandleNewCloudDirtyDataImp(upgradeStore, resultSet, restOwnerAlbumIds, assetId);
1680 }
1681 return E_OK;
1682 }
1683
TransferMisMatchScreenRecord(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1684 static int32_t TransferMisMatchScreenRecord(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1685 {
1686 MEDIA_INFO_LOG("Transfer miss matched screeRecord begin");
1687 const std::string QUERY_SCREEN_RECORD_ALBUM =
1688 "SELECT album_id FROM PhotoAlbum WHERE bundle_name ='com.huawei.hmos.screenrecorder' AND dirty <>4";
1689 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_SCREEN_RECORD_ALBUM);
1690 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1691 MEDIA_INFO_LOG("No screen record album");
1692 const std::string CREATE_SCREEN_RECORDS_ALBUM =
1693 "INSERT INTO " + PhotoAlbumColumns::TABLE +
1694 "(album_type, album_subtype, album_name,bundle_name, dirty, is_local, date_added, lpath, priority)"
1695 " Values ('2048', '2049', '屏幕录制', 'com.huawei.hmos.screenrecorder', '1', '1',"
1696 " strftime('%s000', 'now'), '/Pictures/Screenrecords', '1')";
1697 int32_t err = upgradeStore->ExecuteSql(CREATE_SCREEN_RECORDS_ALBUM);
1698 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
1699 "Fatal error! Failed to exec: %{public}s", CREATE_SCREEN_RECORDS_ALBUM.c_str());
1700 }
1701 const std::string TRANSFER_MISS_MATCH_ASSET =
1702 "UPDATE Photos SET owner_album_id = "
1703 "(SELECT album_id FROM PhotoAlbum WHERE bundle_name ='com.huawei.hmos.screenrecorder' AND dirty <>4) "
1704 "WHERE owner_album_id = (SELECT album_id FROM PhotoAlbum WHERE "
1705 "bundle_name ='com.huawei.hmos.screenshot' AND dirty <>'4' limit 1) AND media_type =2";
1706 int32_t err = upgradeStore->ExecuteSql(TRANSFER_MISS_MATCH_ASSET);
1707 CHECK_AND_RETURN_RET_LOG(err == NativeRdb::E_OK, err,
1708 "Fatal error! Failed to exec: %{public}s", TRANSFER_MISS_MATCH_ASSET.c_str());
1709 MEDIA_INFO_LOG("Transfer miss matched screenRecord end");
1710 return E_OK;
1711 }
1712
HandleMisMatchScreenRecord(const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)1713 int32_t MediaLibraryAlbumFusionUtils::HandleMisMatchScreenRecord(
1714 const std::shared_ptr<MediaLibraryRdbStore> upgradeStore)
1715 {
1716 if (upgradeStore == nullptr) {
1717 MEDIA_ERR_LOG("invalid rdbstore");
1718 return E_INVALID_ARGUMENTS;
1719 }
1720 const std::string QUERY_MISS_MATCHED_RECORDS =
1721 "SELECT file_id FROM Photos WHERE owner_album_id = "
1722 "(SELECT album_id FROM PhotoAlbum WHERE bundle_name ='com.huawei.hmos.screenshot' AND dirty <>4) "
1723 " AND media_type =2";
1724 shared_ptr<NativeRdb::ResultSet> resultSet = upgradeStore->QuerySql(QUERY_MISS_MATCHED_RECORDS);
1725 if (resultSet == nullptr || resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1726 MEDIA_INFO_LOG("No miss matched screen record");
1727 return E_OK;
1728 }
1729 return TransferMisMatchScreenRecord(upgradeStore);
1730 }
1731
RefreshAllAlbums()1732 int32_t MediaLibraryAlbumFusionUtils::RefreshAllAlbums()
1733 {
1734 MEDIA_INFO_LOG("Froce refresh all albums start");
1735 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1736 CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_HAS_DB_ERROR, "Failed to get rdbStore.");
1737 MediaLibraryRdbUtils::UpdateAllAlbums(rdbStore);
1738 auto watch = MediaLibraryNotify::GetInstance();
1739 CHECK_AND_RETURN_RET_LOG(watch != nullptr, E_ERR, "Can not get MediaLibraryNotify Instance");
1740 watch->Notify(PhotoAlbumColumns::ALBUM_URI_PREFIX, NotifyType::NOTIFY_UPDATE);
1741 MEDIA_INFO_LOG("Froce refresh all albums end");
1742 return E_OK;
1743 }
1744
CleanInvalidCloudAlbumAndData()1745 int32_t MediaLibraryAlbumFusionUtils::CleanInvalidCloudAlbumAndData()
1746 {
1747 auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1748 if (rdbStore == nullptr) {
1749 MEDIA_ERR_LOG("Failed to get rdbstore, try again!");
1750 rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
1751 if (rdbStore == nullptr) {
1752 MEDIA_ERR_LOG("Fatal error! Failed to get rdbstore, new cloud data is not processed!!");
1753 return E_DB_FAIL;
1754 }
1755 }
1756 if (GetAlbumFuseUpgradeStatus() != ALBUM_FUSION_UPGRADE_SUCCESS) {
1757 MEDIA_ERR_LOG("ALBUM_FUSE: First upgrade fails, perform upgrade again.");
1758 MediaLibraryRdbStore::ReconstructMediaLibraryStorageFormat(rdbStore);
1759 return E_OK;
1760 }
1761 std::unique_lock<std::mutex> cloudAlbumAndDataUniqueLock(
1762 MediaLibraryAlbumFusionUtils::cloudAlbumAndDataMutex_, std::defer_lock);
1763 if (!cloudAlbumAndDataUniqueLock.try_lock()) {
1764 MEDIA_WARN_LOG("ALBUM_FUSE: Failed to acquire lock, skipping task Clean.");
1765 return E_OK;
1766 }
1767 int64_t beginTime = MediaFileUtils::UTCTimeMilliSeconds();
1768 MEDIA_INFO_LOG("DATA_CLEAN:Clean invalid cloud album and dirty data start!");
1769 SetParameterToStopSync();
1770 int32_t totalNumber = QueryTotalNumberNeedToHandle(rdbStore, QUERY_NEW_NOT_MATCHED_COUNT_IN_PHOTOMAP);
1771 MEDIA_INFO_LOG("QueryTotalNumberNeedToHandle, totalNumber=%{public}d", totalNumber);
1772 SetRefreshAlbum(totalNumber > 0);
1773 std::multimap<int32_t, vector<int32_t>> notMatchedMap;
1774 for (int32_t offset = 0; offset < totalNumber; offset += ALBUM_FUSION_BATCH_COUNT) {
1775 MEDIA_INFO_LOG("DATA_CLEAN: handle batch clean, offset: %{public}d", offset);
1776 notMatchedMap.clear();
1777 int32_t err = QueryNoMatchedMap(rdbStore, notMatchedMap, false);
1778 if (err != NativeRdb::E_OK) {
1779 MEDIA_ERR_LOG("Fatal error! Failed to query not matched map data");
1780 break;
1781 }
1782 if (notMatchedMap.size() != 0) {
1783 MEDIA_INFO_LOG("There are %{public}d items need to migrate", (int)notMatchedMap.size());
1784 HandleNewCloudDirtyData(rdbStore, notMatchedMap);
1785 }
1786 }
1787 HandleDuplicateAlbum(rdbStore);
1788 HandleDuplicatePhoto(rdbStore);
1789 // Put no relationship asset into other album
1790 HandleNoOwnerData(rdbStore);
1791 // Clean duplicative album and rebuild expired album
1792 RebuildAlbumAndFillCloudValue(rdbStore);
1793
1794 PhotoAlbumUpdateDateModifiedOperation photoAlbumOperation;
1795 if (photoAlbumOperation.CheckAlbumDateNeedFix(rdbStore)) {
1796 photoAlbumOperation.UpdateAlbumDateNeedFix(rdbStore);
1797 SetRefreshAlbum(true);
1798 }
1799
1800 SetParameterToStartSync();
1801 if (isNeedRefreshAlbum.load() == true) {
1802 RefreshAllAlbums();
1803 isNeedRefreshAlbum = false;
1804 }
1805 PhotoSourcePathOperation().ResetPhotoSourcePath(rdbStore);
1806 MEDIA_INFO_LOG("DATA_CLEAN:Clean invalid cloud album and dirty data, cost %{public}ld",
1807 (long)(MediaFileUtils::UTCTimeMilliSeconds() - beginTime));
1808 return E_OK;
1809 }
1810
QueryCount(const std::shared_ptr<MediaLibraryRdbStore> rdbStore,const string & sql,const string & column)1811 static int QueryCount(const std::shared_ptr<MediaLibraryRdbStore> rdbStore, const string& sql, const string& column)
1812 {
1813 if (rdbStore == nullptr) {
1814 MEDIA_INFO_LOG("fail to get rdbstore");
1815 return -1;
1816 }
1817 auto resultSet = rdbStore->QueryByStep(sql);
1818 if (resultSet == nullptr) {
1819 MEDIA_ERR_LOG("Query failed, failed when executing sql: %{public}s", sql.c_str());
1820 return -1;
1821 }
1822 if (resultSet->GoToFirstRow() != NativeRdb::E_OK) {
1823 MEDIA_ERR_LOG("Query result go to first row failed, sql: %{public}s", sql.c_str());
1824 return -1;
1825 }
1826 return GetInt32Val(column, resultSet);
1827 }
1828
ReportAlbumFusionData(int64_t albumFusionTag,AlbumFusionState albumFusionState,const std::shared_ptr<MediaLibraryRdbStore> rdbStore)1829 void MediaLibraryAlbumFusionUtils::ReportAlbumFusionData(int64_t albumFusionTag, AlbumFusionState albumFusionState,
1830 const std::shared_ptr<MediaLibraryRdbStore> rdbStore)
1831 {
1832 AlbumFusionDfxDataPoint dataPoint;
1833 dataPoint.albumFusionTag = albumFusionTag;
1834 dataPoint.reportTimeStamp = MediaFileUtils::UTCTimeMilliSeconds();
1835 dataPoint.albumFusionState = static_cast<int32_t>(albumFusionState);
1836 MEDIA_INFO_LOG("ALBUM_FUSE: Report album fusion data start, tag is %{public}" PRId64 ", fusion state is %{public}d",
1837 albumFusionTag, static_cast<int32_t>(albumFusionState));
1838
1839 dataPoint.imageAssetCount = QueryCount(rdbStore,
1840 "SELECT count FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::IMAGE),
1841 "count");
1842 dataPoint.videoAssetCount = QueryCount(rdbStore,
1843 "SELECT count FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::VIDEO),
1844 "count");
1845 dataPoint.numberOfSourceAlbum = QueryCount(rdbStore,
1846 "SELECT count(*) FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::SOURCE_GENERIC),
1847 "count(*)");
1848 dataPoint.numberOfUserAlbum = QueryCount(rdbStore,
1849 "SELECT count(*) FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::USER_GENERIC),
1850 "count(*)");
1851 dataPoint.totalAssetsInSourceAlbums = QueryCount(rdbStore,
1852 "SELECT sum(count) FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::SOURCE_GENERIC),
1853 "sum(count)");
1854 dataPoint.totalAssetsInUserAlbums = QueryCount(rdbStore,
1855 "SELECT sum(count) FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::USER_GENERIC),
1856 "sum(count)");
1857 dataPoint.albumDetails = "";
1858 int32_t hiddenAssetCount = QueryCount(rdbStore,
1859 "SELECT count FROM PhotoAlbum WHERE album_subtype = " + to_string(PhotoAlbumSubType::HIDDEN),
1860 "count");
1861 int32_t dotHiddenAlbumAssetCount = QueryCount(rdbStore,
1862 "SELECT count FROM PhotoAlbum WHERE album_name = '.hiddenAlbum' AND dirty <> 4 AND album_subtype = " +
1863 to_string(PhotoAlbumSubType::SOURCE_GENERIC),
1864 "count");
1865 dataPoint.hiddenAssetInfo = "{hidden assets: " + to_string(hiddenAssetCount) + ", .hiddenAlbum assets: " +
1866 to_string(dotHiddenAlbumAssetCount) + "}";
1867
1868 DfxReporter::ReportAlbumFusion(dataPoint);
1869 MEDIA_INFO_LOG("ALBUM_FUSE: Report album fusion data end, tag is %{public}" PRId64 ", fusion state is %{public}d",
1870 albumFusionTag, albumFusionState);
1871 }
1872 } // namespace OHOS::Media