• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>> &notMathedMap, 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 &copyInfo)
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 &copyInfo)
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>> &notMathedMap)
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>> &notMathedMap)
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