• 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 "cloud_sync_notify_handler.h"
17 
18 #include "cloud_media_asset_manager.h"
19 #include "cloud_media_asset_types.h"
20 #include "cloud_sync_utils.h"
21 
22 #include <sys/stat.h>
23 
24 #include "medialibrary_album_fusion_utils.h"
25 #include "medialibrary_album_operations.h"
26 #include "notify_responsibility_chain_factory.h"
27 #include "result_set_utils.h"
28 #include "thumbnail_service.h"
29 #include "medialibrary_notify.h"
30 #include "medialibrary_rdb_utils.h"
31 #include "parameters.h"
32 #include "photo_album_column.h"
33 #include "media_log.h"
34 
35 using namespace std;
36 
37 namespace OHOS {
38 namespace Media {
39 using ChangeType = DataShare::DataShareObserver::ChangeType;
40 
41 const std::string INVALID_ZERO_ID = "0";
42 
IsCloudInsertTaskPriorityHigh()43 static bool IsCloudInsertTaskPriorityHigh()
44 {
45     int32_t cloudSyncStatus = static_cast<int32_t>(system::GetParameter(CLOUDSYNC_STATUS_KEY, "0").at(0) - '0');
46     return cloudSyncStatus == CloudSyncStatus::FIRST_FIVE_HUNDRED ||
47         cloudSyncStatus == CloudSyncStatus::INCREMENT_DOWNLOAD;
48 }
49 
IsCloudNotifyInfoValid(const string & cloudNotifyInfo)50 static inline bool IsCloudNotifyInfoValid(const string& cloudNotifyInfo)
51 {
52     if (cloudNotifyInfo.empty()) {
53         return false;
54     }
55     for (char const& ch : cloudNotifyInfo) {
56         if (isdigit(ch) == 0) {
57             return false;
58         }
59     }
60     return true;
61 }
62 
UpdateCloudAssetDownloadTask(const bool verifyFlag)63 static void UpdateCloudAssetDownloadTask(const bool verifyFlag)
64 {
65     if (!verifyFlag) {
66         MEDIA_INFO_LOG("Current status is not suitable for task.");
67         return;
68     }
69     if (!CloudMediaAssetManager::GetInstance().SetIsThumbnailUpdate() && CloudSyncUtils::IsCloudSyncSwitchOn() &&
70         CloudSyncUtils::IsCloudDataAgingPolicyOn()) {
71         CloudMediaAssetManager::GetInstance().StartDownloadCloudAsset(CloudMediaDownloadType::DOWNLOAD_GENTLE);
72     }
73 }
74 
HandleInsertEvent(const std::list<Uri> & uris)75 void CloudSyncNotifyHandler::HandleInsertEvent(const std::list<Uri> &uris)
76 {
77     bool isCloudInsertTaskPriorityHigh = IsCloudInsertTaskPriorityHigh();
78     if (!isCloudInsertTaskPriorityHigh && !ThumbnailService::GetInstance()->GetCurrentStatusForTask()) {
79         MEDIA_INFO_LOG("current status is not suitable for task");
80         return;
81     }
82     bool verifyFlag = false;
83     for (auto &uri : uris) {
84         string uriString = uri.ToString();
85         auto pos = uriString.find_last_of('/');
86         if (pos == string::npos) {
87             continue;
88         }
89         string idString = uriString.substr(pos + 1);
90         if (idString.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(idString)) {
91             MEDIA_WARN_LOG("cloud observer get no valid fileId and uri : %{public}s", uriString.c_str());
92             continue;
93         }
94         if (!verifyFlag) {
95             verifyFlag = true;
96         }
97         ThumbnailService::GetInstance()->CreateAstcCloudDownload(idString, isCloudInsertTaskPriorityHigh);
98     }
99     UpdateCloudAssetDownloadTask(verifyFlag);
100 }
101 
HandleDeleteEvent(const std::list<Uri> & uris)102 void CloudSyncNotifyHandler::HandleDeleteEvent(const std::list<Uri> &uris)
103 {
104     bool verifyFlag = false;
105     for (auto &uri : uris) {
106         string uriString = uri.ToString();
107         auto dateTakenPos = uriString.rfind('/');
108         if (dateTakenPos == string::npos) {
109             continue;
110         }
111         auto fileIdPos = uriString.rfind('/', dateTakenPos - 1);
112         if (fileIdPos == string::npos) {
113             continue;
114         }
115 
116         string dateTaken = uriString.substr(dateTakenPos + 1);
117         string fileId = uriString.substr(fileIdPos + 1, dateTakenPos - fileIdPos - 1);
118         if (!IsCloudNotifyInfoValid(dateTaken) || !IsCloudNotifyInfoValid(fileId)) {
119             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
120             continue;
121         }
122         if (!verifyFlag) {
123             verifyFlag = true;
124         }
125 
126         ThumbnailService::GetInstance()->DeleteAstcWithFileIdAndDateTaken(fileId, dateTaken);
127     }
128     if (verifyFlag) {
129         CloudMediaAssetManager::GetInstance().SetIsThumbnailUpdate();
130     }
131 }
132 
HandleTimeUpdateEvent(const std::list<Uri> & uris)133 void CloudSyncNotifyHandler::HandleTimeUpdateEvent(const std::list<Uri> &uris)
134 {
135     for (auto &uri : uris) {
136         string uriString = uri.ToString();
137         auto newDateTakenPos = uriString.rfind('/');
138         if (newDateTakenPos == string::npos) {
139             continue;
140         }
141         auto formerDateTakenPos = uriString.rfind('/', newDateTakenPos - 1);
142         if (formerDateTakenPos == string::npos) {
143             continue;
144         }
145         auto fileIdPos = uriString.rfind('/', formerDateTakenPos - 1);
146         if (fileIdPos == string::npos) {
147             continue;
148         }
149 
150         string newDateTaken = uriString.substr(newDateTakenPos + 1);
151         string formerDateTaken = uriString.substr(formerDateTakenPos + 1, newDateTakenPos - formerDateTakenPos - 1);
152         string fileId = uriString.substr(fileIdPos + 1, formerDateTakenPos - fileIdPos - 1);
153         if (!IsCloudNotifyInfoValid(newDateTaken) || !IsCloudNotifyInfoValid(formerDateTaken) ||
154             !IsCloudNotifyInfoValid(fileId)) {
155             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
156             continue;
157         }
158 
159         ThumbnailService::GetInstance()->UpdateAstcWithNewDateTaken(fileId, newDateTaken, formerDateTaken);
160     }
161 }
162 
HandleExtraEvent(const std::list<Uri> & uris,const ChangeType & type)163 void CloudSyncNotifyHandler::HandleExtraEvent(const std::list<Uri> &uris, const ChangeType &type)
164 {
165     ExtraChangeType extraType = static_cast<ExtraChangeType>(type);
166     if (extraType == ExtraChangeType::PHOTO_TIME_UPDATE) {
167         HandleTimeUpdateEvent(uris);
168         return;
169     }
170     MEDIA_DEBUG_LOG("change type is %{public}d, no need ThumbnailObserverOnChange", type);
171 }
172 
ThumbnailObserverOnChange(const list<Uri> & uris,const ChangeType & type)173 void CloudSyncNotifyHandler::ThumbnailObserverOnChange(const list<Uri> &uris, const ChangeType &type)
174 {
175     MediaLibraryRdbUtils::SetNeedRefreshAlbum(true);
176     switch (type) {
177         case ChangeType::INSERT:
178             HandleInsertEvent(uris);
179             break;
180         case ChangeType::DELETE:
181             HandleDeleteEvent(uris);
182             break;
183         default:
184             HandleExtraEvent(uris, type);
185             break;
186     }
187 }
188 
HandleDirtyDataFix(const std::list<Uri> & uris,const CloudSyncErrType & errType)189 void CloudSyncNotifyHandler::HandleDirtyDataFix(const std::list<Uri> &uris, const CloudSyncErrType &errType)
190 {
191     MediaLibraryRdbUtils::SetNeedRefreshAlbum(true);
192     switch (errType) {
193         case CloudSyncErrType::CONTENT_NOT_FOUND:
194             HandleContentNotFound(uris);
195             break;
196         case CloudSyncErrType::THM_NOT_FOUND:
197             HandleThumbnailNotFound(uris);
198             break;
199         case CloudSyncErrType::LCD_NOT_FOUND:
200             HandleLCDNotFound(uris);
201             break;
202         case CloudSyncErrType::LCD_SIZE_IS_TOO_LARGE:
203             HandleLCDSizeTooLarge(uris);
204             break;
205         case CloudSyncErrType::CONTENT_SIZE_IS_ZERO:
206             HandleContentSizeIsZero(uris);
207             break;
208         case CloudSyncErrType::ALBUM_NOT_FOUND:
209             HandleAlbumNotFound(uris);
210             break;
211         default:
212             MEDIA_ERR_LOG("HandleDirtyDataFix, Unrecognized error type : %{public}d", errType);
213         }
214 }
215 
GetfileIdFromPastDirtyDataFixUri(std::string uriString)216 std::string CloudSyncNotifyHandler::GetfileIdFromPastDirtyDataFixUri(std::string uriString)
217 {
218     auto fileIdPos = uriString.rfind('/');
219     if (fileIdPos == string::npos) {
220         return "";
221     }
222     std::string fileId = uriString.substr(fileIdPos + 1, uriString.size() - fileIdPos);
223     return fileId;
224 }
225 
HandleContentNotFound(const std::list<Uri> & uris)226 void CloudSyncNotifyHandler::HandleContentNotFound(const std::list<Uri> &uris)
227 {
228     for (auto &uri : uris) {
229         std::string uriString = uri.ToString();
230         std::string fileId = GetfileIdFromPastDirtyDataFixUri(uriString);
231         if (fileId == "") {
232             continue;
233         }
234         if (fileId.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(fileId)) {
235             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
236             continue;
237         }
238         MEDIA_INFO_LOG(
239             "ContentNotFound, uri : %{public}s", uriString.c_str());
240     }
241 }
242 
HandleThumbnailNotFound(const std::list<Uri> & uris)243 void CloudSyncNotifyHandler::HandleThumbnailNotFound(const std::list<Uri> &uris)
244 {
245     for (auto &uri : uris) {
246         std::string uriString = uri.ToString();
247         std::string fileId = GetfileIdFromPastDirtyDataFixUri(uriString);
248         if (fileId == "") {
249             continue;
250         }
251         if (fileId.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(fileId)) {
252             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
253             continue;
254         }
255 
256         int32_t err = ThumbnailService::GetInstance()->CreateThumbnailPastDirtyDataFix(fileId);
257         if (err != E_SUCCESS) {
258             MEDIA_ERR_LOG("ThumbnailService CreateThumbnailPastDirtyDataFix failed : %{public}d", err);
259             continue;
260         }
261         MEDIA_INFO_LOG("Generate thumbnail %{public}s, success ", uriString.c_str());
262     }
263 }
264 
HandleLCDNotFound(const std::list<Uri> & uris)265 void CloudSyncNotifyHandler::HandleLCDNotFound(const std::list<Uri> &uris)
266 {
267     for (auto &uri : uris) {
268         std::string uriString = uri.ToString();
269         std::string fileId = GetfileIdFromPastDirtyDataFixUri(uriString);
270         if (fileId == "") {
271             continue;
272         }
273         if (fileId.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(fileId)) {
274             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
275             continue;
276         }
277 
278         int32_t err = ThumbnailService::GetInstance()->CreateLcdPastDirtyDataFix(fileId);
279         if (err != E_SUCCESS) {
280             MEDIA_ERR_LOG("ThumbnailService CreateLCDPastDirtyDataFix failed : %{public}d", err);
281             continue;
282         }
283         MEDIA_INFO_LOG("Generate Lcd %{public}s, success ", uriString.c_str());
284     }
285     return;
286 }
287 
HandleLCDSizeTooLarge(const std::list<Uri> & uris)288 void CloudSyncNotifyHandler::HandleLCDSizeTooLarge(const std::list<Uri> &uris)
289 {
290     for (auto &uri : uris) {
291         std::string uriString = uri.ToString();
292         std::string fileId = GetfileIdFromPastDirtyDataFixUri(uriString);
293         if (fileId == "") {
294             continue;
295         }
296         if (fileId.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(fileId)) {
297             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
298             continue;
299         }
300 
301         int32_t err = ThumbnailService::GetInstance()->CreateLcdPastDirtyDataFix(fileId, THUMBNAIL_EIGHTY);
302         if (err != E_SUCCESS) {
303             MEDIA_ERR_LOG("ThumbnailService CreateLcdPastDirtyDataFix to eighty quality failed : %{public}d", err);
304             continue;
305         }
306         MEDIA_INFO_LOG("Regenerate Lcd %{public}s to eighty quality, success ", uriString.c_str());
307     }
308     return;
309 }
310 
HandleContentSizeIsZero(const std::list<Uri> & uris)311 void CloudSyncNotifyHandler::HandleContentSizeIsZero(const std::list<Uri> &uris)
312 {
313     for (auto &uri : uris) {
314         std::string uriString = uri.ToString();
315         std::string fileId = GetfileIdFromPastDirtyDataFixUri(uriString);
316         if (fileId == "") {
317             continue;
318         }
319         if (fileId.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(fileId)) {
320             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
321             continue;
322         }
323 
324         std::string filePath;
325         auto err = QueryFilePathFromFileId(fileId, filePath);
326         if (err != E_SUCCESS) {
327             MEDIA_ERR_LOG("QueryFilePathFromFileId failed : %{public}d", err);
328             continue;
329         }
330         auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
331         int changeRows = 0;
332         struct stat st;
333         err = stat(filePath.c_str(), &st);
334         if (err != E_SUCCESS) {
335             MEDIA_ERR_LOG("stat failed : %{public}d", err);
336             continue;
337         }
338         if (st.st_size == 0) {
339             MEDIA_INFO_LOG("HandleContentSizeIsZero, file size is zero");
340             continue;
341         }
342         NativeRdb::ValuesBucket valuesNew;
343         valuesNew.PutLong(PhotoColumn::MEDIA_SIZE, st.st_size);
344         NativeRdb::RdbPredicates rdbPredicates(PhotoColumn::PHOTOS_TABLE);
345         rdbPredicates.EqualTo(PhotoColumn::MEDIA_ID, fileId);
346         rdbStore->Update(changeRows, valuesNew, rdbPredicates);
347         CHECK_AND_PRINT_LOG(changeRows >= 0, "Failed to update content size , ret = %{public}d", changeRows);
348         MEDIA_INFO_LOG("refresh photo size field to : %{public}d , success", static_cast<int>(st.st_size));
349     }
350     return;
351 }
352 
QueryFilePathFromFileId(const std::string & id,std::string & filePath)353 int32_t CloudSyncNotifyHandler::QueryFilePathFromFileId(const std::string &id, std::string &filePath)
354 {
355     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
356     CHECK_AND_RETURN_RET_LOG(rdbStore != nullptr, E_DB_FAIL, "QueryFilePathFromFileId failed. rdbStore is null");
357     const string sqlQuery = "SELECT * From " + PhotoColumn::PHOTOS_TABLE +
358                             " WHERE " + PhotoColumn::MEDIA_ID + " = " + id;
359     auto resultSet = rdbStore->QuerySql(sqlQuery);
360     CHECK_AND_RETURN_RET_LOG(
361         resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK,
362         E_DB_FAIL, "Query not matched data fails");
363 
364     filePath = get<std::string>(
365         ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_FILE_PATH, resultSet, ResultSetDataType::TYPE_STRING));
366     return E_OK;
367 }
368 
QueryAlbumLpathFromFileId(const std::string & id,std::string & lpath)369 int32_t CloudSyncNotifyHandler::QueryAlbumLpathFromFileId(const std::string &id, std::string &lpath)
370 {
371     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
372     CHECK_AND_RETURN_RET_LOG(
373         rdbStore != nullptr,
374         E_DB_FAIL, "QueryAlbumLpathFromFileId failed. rdbStore is null");
375     const string sqlQuery = "SELECT * From " + PhotoColumn::PHOTOS_TABLE + " WHERE " + PhotoColumn::MEDIA_ID +
376                             " = " + id;
377     auto resultSet = rdbStore->QuerySql(sqlQuery);
378     CHECK_AND_RETURN_RET_LOG(
379         resultSet != nullptr && resultSet->GoToFirstRow() == NativeRdb::E_OK,
380         E_DB_FAIL, "Query not matched data fails");
381 
382     auto sourcePath = get<std::string>(
383         ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_SOURCE_PATH, resultSet, ResultSetDataType::TYPE_STRING));
384     int32_t mediaType = GetInt32Val(PhotoColumn::MEDIA_TYPE, resultSet);
385     int32_t err = MediaLibraryAlbumOperations::GetLPathFromSourcePath(sourcePath, lpath, mediaType);
386     CHECK_AND_RETURN_RET_LOG(err == E_OK, E_DB_FAIL, "GetLPathFromSourcePath fail : %{public}s ", lpath.c_str());
387     MEDIA_INFO_LOG("QueryAlbumLpathFromFileId succcess, lpath is : %{public}s ", lpath.c_str());
388     return E_OK;
389 }
390 
HandleAlbumNotFound(const std::list<Uri> & uris)391 void CloudSyncNotifyHandler::HandleAlbumNotFound(const std::list<Uri> &uris)
392 {
393     for (auto &uri : uris) {
394         std::string uriString = uri.ToString();
395         std::string fileId = GetfileIdFromPastDirtyDataFixUri(uriString);
396         if (fileId == "") {
397             continue;
398         }
399         if (fileId.compare(INVALID_ZERO_ID) == 0 || !IsCloudNotifyInfoValid(fileId)) {
400             MEDIA_WARN_LOG("cloud observer get no valid uri : %{public}s", uriString.c_str());
401             continue;
402         }
403 
404         std::string lpath;
405         int64_t newAlbumId = -1;
406         bool isUserAlbum = false;
407         auto err = QueryAlbumLpathFromFileId(fileId, lpath);
408         if (err != E_SUCCESS) {
409             MEDIA_ERR_LOG("QueryAlbumLpathFromFileId failed : %{public}d", err);
410             continue;
411         }
412         MediaLibraryAlbumOperations::RecoverAlbum(fileId, lpath, isUserAlbum, newAlbumId);
413         if (newAlbumId == -1) {
414             MEDIA_ERR_LOG("HandleAlbumNotFound Fail, Recover album fails");
415             continue;
416         }
417 
418         if (isUserAlbum) {
419         MediaLibraryRdbUtils::UpdateUserAlbumInternal(
420             MediaLibraryUnistoreManager::GetInstance().GetRdbStore(), {to_string(newAlbumId)});
421         } else {
422             MediaLibraryRdbUtils::UpdateSourceAlbumInternal(
423                 MediaLibraryUnistoreManager::GetInstance().GetRdbStore(), {to_string(newAlbumId)});
424         }
425         auto watch = MediaLibraryNotify::GetInstance();
426         watch->Notify(MediaFileUtils::GetUriByExtrConditions(
427             PhotoAlbumColumns::ALBUM_URI_PREFIX, to_string(newAlbumId)), NotifyType::NOTIFY_ADD);
428     }
429     return;
430 }
431 
MakeResponsibilityChain()432 void CloudSyncNotifyHandler::MakeResponsibilityChain()
433 {
434     string uriString = notifyInfo_.uris.front().ToString();
435     MEDIA_DEBUG_LOG("observer get first uri is : %{public}s", uriString.c_str());
436 
437     if (uriString.find("file://cloudsync/Photo/HeightError/") != string::npos) {
438         return;
439     }
440 
441     if (uriString.find("file://cloudsync/Photo/DownloadSuccessed/") != string::npos) {
442         return;
443     }
444 
445     if (uriString.find(PhotoColumn::PHOTO_CLOUD_URI_PREFIX) != string::npos) {
446         ThumbnailObserverOnChange(notifyInfo_.uris, notifyInfo_.type);
447     }
448 
449     if (uriString.find("file://cloudsync/Photo/RebuildCloudData/") != string::npos) {
450         MEDIA_INFO_LOG("Get cloud rebuild cloud data notification : %{public}s",
451             "file://cloudsync/Photo/RebuildCloudData/");
452         MediaLibraryAlbumFusionUtils::CleanInvalidCloudAlbumAndData();
453     }
454 
455     shared_ptr<BaseHandler> chain = nullptr;
456 
457     if (uriString.find(PhotoAlbumColumns::ALBUM_CLOUD_URI_PREFIX) != string::npos) {
458         if (notifyInfo_.type == ChangeType::DELETE) {
459             chain = NotifyResponsibilityChainFactory::CreateChain(ALBUM_DELETE);
460         } else {
461             chain = NotifyResponsibilityChainFactory::CreateChain(TRANSPARENT);
462         }
463     }
464 
465     if (uriString.find(PhotoColumn::PHOTO_CLOUD_URI_PREFIX) != string::npos) {
466         if (notifyInfo_.type == ChangeType::UPDATE || notifyInfo_.type == ChangeType::OTHER) {
467             chain = NotifyResponsibilityChainFactory::CreateChain(PHOTODELETE);
468         } else {
469             chain = NotifyResponsibilityChainFactory::CreateChain(TRANSPARENT);
470         }
471     }
472 
473     if (uriString.find(PhotoColumn::PHOTO_CLOUD_GALLERY_REBUILD_URI_PREFIX) != string::npos) {
474         HandleDirtyDataFix(notifyInfo_.uris, static_cast<CloudSyncErrType>(notifyInfo_.type));
475     }
476     CloudSyncHandleData handleData;
477     handleData.orgInfo = notifyInfo_;
478     if (chain == nullptr) {
479         MEDIA_ERR_LOG("uri OR type is Invalid");
480         return;
481     }
482     chain->Handle(handleData);
483 }
484 } //namespace Media
485 } //namespace OHOS
486