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