• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 #define MLOG_TAG "FileNotify"
16 #include "medialibrary_notify.h"
17 
18 #include "medialibrary_async_worker.h"
19 #include "medialibrary_period_worker.h"
20 #include "data_ability_helper_impl.h"
21 #include "dfx_utils.h"
22 #include "media_file_utils.h"
23 #include "media_log.h"
24 #include "medialibrary_command.h"
25 #include "medialibrary_data_manager_utils.h"
26 #include "medialibrary_db_const.h"
27 #include "medialibrary_errno.h"
28 #include "medialibrary_object_utils.h"
29 #include "medialibrary_tracer.h"
30 #include "medialibrary_unistore_manager.h"
31 #include "photo_album_column.h"
32 #include "photo_map_column.h"
33 #include "result_set_utils.h"
34 #include "uri.h"
35 
36 using namespace std;
37 
38 namespace OHOS::Media {
39 using ChangeType = AAFwk::ChangeInfo::ChangeType;
40 using NotifyDataMap = unordered_map<NotifyType, list<Uri>>;
41 static const int32_t WAIT_TIME = 2;
42 shared_ptr<MediaLibraryNotify> MediaLibraryNotify::instance_;
43 mutex MediaLibraryNotify::mutex_;
44 unordered_map<string, NotifyDataMap> MediaLibraryNotify::nfListMap_ = {};
45 atomic<uint16_t> MediaLibraryNotify::thumbCounts_(0);
46 atomic<uint16_t> MediaLibraryNotify::counts_(0);
47 static const uint16_t IDLING_TIME = 50;
48 const static uint16_t THUMB_LOOP = 5;
49 const static uint16_t THUMB_NOTIFY_SEQ_NUM = 1;
50 
GetInstance()51 shared_ptr<MediaLibraryNotify> MediaLibraryNotify::GetInstance()
52 {
53     if (instance_ != nullptr) {
54         return instance_;
55     }
56     lock_guard<mutex> lock(mutex_);
57     if (instance_ == nullptr) {
58         instance_ = shared_ptr<MediaLibraryNotify>(new MediaLibraryNotify());
59         if (instance_ == nullptr) {
60             MEDIA_ERR_LOG("GetInstance nullptr");
61             return instance_;
62         }
63         instance_->Init();
64     }
65     return instance_;
66 }
MediaLibraryNotify()67 MediaLibraryNotify::MediaLibraryNotify() {};
68 
~MediaLibraryNotify()69 MediaLibraryNotify::~MediaLibraryNotify() {}
70 
SolveUris(const list<Uri> & uris,Parcel & parcel)71 static bool SolveUris(const list<Uri> &uris, Parcel &parcel)
72 {
73     if (uris.size() > numeric_limits<uint32_t>::max() ||
74         !parcel.WriteUint32(static_cast<uint32_t>(uris.size()))) {
75         MEDIA_ERR_LOG("Failed to write uri list length, list size = %{private}zu", uris.size());
76         return false;
77     }
78     for (auto const &uri : uris) {
79         if (!parcel.WriteString(uri.ToString())) {
80             MEDIA_ERR_LOG("Failed to write strUri uri = %{private}s", uri.ToString().c_str());
81             return false;
82         }
83     }
84     return true;
85 }
86 
SendAlbumSub(const Uri & notifyUri,NotifyType type,list<Uri> & uris)87 static int SendAlbumSub(const Uri &notifyUri, NotifyType type, list<Uri> &uris)
88 {
89     Parcel parcel;
90     CHECK_AND_RETURN_RET_LOG(SolveUris(uris, parcel), E_SOLVE_URIS_FAILED, "SolveUris failed");
91     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
92     uintptr_t buf = parcel.GetData();
93     if (parcel.GetDataSize() == 0) {
94         MEDIA_ERR_LOG("NotifyChangeExt parcel.GetDataSize failed");
95         return E_PARCEL_GET_SIZE_FAILED;
96     }
97     auto *uBuf = new (std::nothrow) uint8_t[parcel.GetDataSize()];
98     if (uBuf == nullptr) {
99         MEDIA_ERR_LOG("parcel.GetDataSize is null");
100         return E_PARCEL_GET_SIZE_FAILED;
101     }
102     int ret = memcpy_s(uBuf, parcel.GetDataSize(), reinterpret_cast<uint8_t *>(buf), parcel.GetDataSize());
103     if (ret != 0) {
104         MEDIA_ERR_LOG("Parcel data copy failed, err = %{public}d", ret);
105     }
106     ChangeType changeType;
107     if (type == NotifyType::NOTIFY_ALBUM_ADD_ASSET) {
108         changeType = ChangeType::INSERT;
109     } else {
110         changeType = ChangeType::DELETE;
111     }
112     MEDIA_DEBUG_LOG("obsMgrClient->NotifyChangeExt URI is %{public}s, NotifyType is %{public}d",
113         notifyUri.ToString().c_str(), type);
114     return obsMgrClient->NotifyChangeExt({changeType, {notifyUri}, uBuf, parcel.GetDataSize()});
115 }
116 
SolveAlbumUri(const Uri & notifyUri,NotifyType type,list<Uri> & uris)117 static int SolveAlbumUri(const Uri &notifyUri, NotifyType type, list<Uri> &uris)
118 {
119     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
120     MEDIA_DEBUG_LOG("obsMgrClient->NotifyChangeExt URI is %{public}s, NotifyType is %{public}d",
121         notifyUri.ToString().c_str(), type);
122     if ((type == NotifyType::NOTIFY_ALBUM_ADD_ASSET) || (type == NotifyType::NOTIFY_ALBUM_REMOVE_ASSET)) {
123         return SendAlbumSub(notifyUri, type, uris);
124     } else {
125         return obsMgrClient->NotifyChangeExt({static_cast<ChangeType>(type), uris});
126     }
127 }
128 
PrintNotifyInfo(NotifyType type,const list<Uri> & uris,const string & uri="")129 static void PrintNotifyInfo(NotifyType type, const list<Uri> &uris, const string &uri = "")
130 {
131     string temp;
132     for (auto it : uris) {
133         temp += DfxUtils::GetSafeUri(it.ToString()) + ",";
134     }
135     if (!uri.empty()) {
136         MEDIA_INFO_LOG("album uri is %{public}s", uri.c_str());
137     }
138     MEDIA_INFO_LOG("type is %{public}d, info is %{public}s", static_cast<int>(type), temp.c_str());
139 }
140 
PushNotifyDataMap(const string & uri,NotifyDataMap notifyDataMap)141 static void PushNotifyDataMap(const string &uri, NotifyDataMap notifyDataMap)
142 {
143     int ret;
144     for (auto &[type, uris] : notifyDataMap) {
145         if (uri.find(PhotoAlbumColumns::ALBUM_URI_PREFIX) != string::npos) {
146             Uri notifyUri = Uri(uri);
147             ret = SolveAlbumUri(notifyUri, type, uris);
148             PrintNotifyInfo(type, uris, uri);
149         } else {
150             auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
151             MEDIA_DEBUG_LOG("obsMgrClient->NotifyChangeExt URI is %{public}s, type is %{public}d",
152                 uri.c_str(), static_cast<int>(type));
153             ret = obsMgrClient->NotifyChangeExt({static_cast<ChangeType>(type), uris});
154             PrintNotifyInfo(type, uris);
155         }
156         if (ret != E_OK) {
157             MEDIA_ERR_LOG("PushNotification failed, errorCode = %{public}d", ret);
158         }
159     }
160     return;
161 }
162 
ExtractDataMapWithNotifyType(NotifyType type,unordered_map<string,NotifyDataMap> & listMap,NotifyDataMap & dataMap)163 static void ExtractDataMapWithNotifyType(NotifyType type, unordered_map<string, NotifyDataMap>& listMap,
164     NotifyDataMap& dataMap)
165 {
166     if (listMap.count(PhotoColumn::PHOTO_URI_PREFIX) == 0) {
167         return;
168     }
169     auto iter = listMap.find(PhotoColumn::PHOTO_URI_PREFIX);
170     auto typeIter = iter->second.find(type);
171     if (typeIter == iter->second.end()) {
172         return;
173     }
174     dataMap.emplace(type, typeIter->second);
175     iter->second.erase(type);
176 }
177 
178 // only call this function after clear listMap
InsertDataMapToListMap(NotifyType type,unordered_map<string,NotifyDataMap> & listMap,NotifyDataMap & dataMap)179 static void InsertDataMapToListMap(NotifyType type, unordered_map<string, NotifyDataMap>& listMap,
180     NotifyDataMap& dataMap)
181 {
182     if (dataMap.size() == 0) {
183         return;
184     }
185     if (listMap.count(PhotoColumn::PHOTO_URI_PREFIX) == 0) {
186         listMap.emplace(PhotoColumn::PHOTO_URI_PREFIX, dataMap);
187         return;
188     }
189     auto iter = listMap.find(PhotoColumn::PHOTO_URI_PREFIX);
190     if (iter->second.count(type) == 0) {
191         iter->second.emplace(type, dataMap.at(type));
192     }
193 }
194 
PushNotification(PeriodTaskData * data)195 static void PushNotification(PeriodTaskData *data)
196 {
197     MediaLibraryNotify::thumbCounts_ = (++MediaLibraryNotify::thumbCounts_) % THUMB_LOOP;
198     unordered_map<string, NotifyDataMap> tmpNfListMap;
199     {
200         lock_guard<mutex> lock(MediaLibraryNotify::mutex_);
201         if (MediaLibraryNotify::nfListMap_.empty()) {
202             ++MediaLibraryNotify::counts_;
203             if (MediaLibraryNotify::counts_.load() > IDLING_TIME) {
204                 auto periodWorker = MediaLibraryPeriodWorker::GetInstance();
205                 if (periodWorker == nullptr) {
206                     MEDIA_ERR_LOG("failed to get period worker instance");
207                     return;
208                 }
209                 MediaLibraryNotify::thumbCounts_ = 0;
210                 periodWorker->StopThread(PeriodTaskType::COMMON_NOTIFY);
211                 MEDIA_INFO_LOG("notify task close");
212             }
213             return;
214         } else {
215             MediaLibraryNotify::counts_.store(0);
216         }
217         NotifyDataMap thumbAddMap = {};
218         NotifyDataMap thumbUpdateMap = {};
219         if (MediaLibraryNotify::thumbCounts_ != THUMB_NOTIFY_SEQ_NUM) {
220             ExtractDataMapWithNotifyType(NotifyType::NOTIFY_THUMB_ADD, MediaLibraryNotify::nfListMap_, thumbAddMap);
221             ExtractDataMapWithNotifyType(NotifyType::NOTIFY_THUMB_UPDATE, MediaLibraryNotify::nfListMap_,
222                 thumbUpdateMap);
223         }
224         MediaLibraryNotify::nfListMap_.swap(tmpNfListMap);
225         MediaLibraryNotify::nfListMap_.clear();
226         InsertDataMapToListMap(NotifyType::NOTIFY_THUMB_ADD, MediaLibraryNotify::nfListMap_, thumbAddMap);
227         InsertDataMapToListMap(NotifyType::NOTIFY_THUMB_UPDATE, MediaLibraryNotify::nfListMap_, thumbUpdateMap);
228     }
229     for (auto &[uri, notifyDataMap] : tmpNfListMap) {
230         if (notifyDataMap.empty()) {
231             continue;
232         }
233         PushNotifyDataMap(uri, notifyDataMap);
234     }
235 }
236 
IsThumbReadyById(const string & fileId)237 static int32_t IsThumbReadyById(const string &fileId)
238 {
239     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
240     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "Failed to get rdbStore.");
241     vector<string> columns = {
242         MediaColumn::MEDIA_HIDDEN,
243         MediaColumn::MEDIA_DATE_TRASHED,
244         PhotoColumn::PHOTO_THUMBNAIL_VISIBLE,
245         PhotoColumn::PHOTO_SUBTYPE,
246         PhotoColumn::PHOTO_BURST_COVER_LEVEL,
247     };
248     NativeRdb::RdbPredicates rdbPredicates(PhotoColumn::PHOTOS_TABLE);
249     rdbPredicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
250     auto resultSet = uniStore->Query(rdbPredicates, columns);
251     if (resultSet == nullptr) {
252         MEDIA_ERR_LOG("GetThumbVisibleById failed");
253         return 0;
254     }
255     int ret = resultSet->GoToFirstRow();
256     CHECK_AND_RETURN_RET_LOG(ret == E_OK, 0, "Failed to GoToFirstRow");
257     int32_t isVisible = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_THUMBNAIL_VISIBLE,
258         resultSet, TYPE_INT32));
259     int64_t isTrashed = get<int64_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::MEDIA_DATE_TRASHED,
260         resultSet, TYPE_INT64));
261     int32_t subtype = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_SUBTYPE,
262         resultSet, TYPE_INT32));
263     int32_t burstCoverLevel = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
264         resultSet, TYPE_INT32));
265     int32_t isHidden = get<int32_t>(ResultSetUtils::GetValFromColumn(MediaColumn::MEDIA_HIDDEN,
266         resultSet, TYPE_INT32));
267     resultSet->Close();
268     return isVisible && isTrashed == 0 && isHidden == 0 && !(subtype == static_cast<int32_t>(PhotoSubType::BURST) &&
269         burstCoverLevel == static_cast<int32_t>(BurstCoverLevelType::MEMBER));
270 }
271 
SkipThumbNotifyIfNotReady(NotifyTaskData * taskData)272 static bool SkipThumbNotifyIfNotReady(NotifyTaskData* taskData)
273 {
274     if (taskData == nullptr) {
275         return false;
276     }
277     if (taskData->notifyType_ != NotifyType::NOTIFY_THUMB_ADD) {
278         return false;
279     }
280     string fileId = MediaLibraryDataManagerUtils::GetFileIdFromPhotoUri(taskData->uri_);
281     if (fileId.empty()) {
282         return false;
283     }
284     return !IsThumbReadyById(fileId);
285 }
286 
AddNotify(const string & srcUri,const string & keyUri,NotifyTaskData * taskData)287 static void AddNotify(const string &srcUri, const string &keyUri, NotifyTaskData* taskData)
288 {
289     if (SkipThumbNotifyIfNotReady(taskData)) {
290         MEDIA_DEBUG_LOG("Skip taskData %{public}s, because not visible", taskData->uri_.c_str());
291         return;
292     }
293     NotifyDataMap notifyDataMap;
294     list<Uri> sendUris;
295     Uri uri(srcUri);
296     MEDIA_DEBUG_LOG("AddNotify ,keyUri = %{private}s, uri = %{private}s, "
297         "notifyType = %{private}d", keyUri.c_str(), uri.ToString().c_str(), taskData->notifyType_);
298     lock_guard<mutex> lock(MediaLibraryNotify::mutex_);
299     if (MediaLibraryNotify::nfListMap_.count(keyUri) == 0) {
300         sendUris.emplace_back(uri);
301         notifyDataMap.insert(make_pair(taskData->notifyType_, sendUris));
302         MediaLibraryNotify::nfListMap_.insert(make_pair(keyUri, notifyDataMap));
303     } else {
304         auto iter = MediaLibraryNotify::nfListMap_.find(keyUri);
305         if (iter->second.count(taskData->notifyType_) == 0) {
306             sendUris.emplace_back(uri);
307             iter->second.insert(make_pair(taskData->notifyType_, sendUris));
308         } else {
309             auto haveIter = find_if(
310                 iter->second.at(taskData->notifyType_).begin(),
311                 iter->second.at(taskData->notifyType_).end(),
312                 [uri](const Uri &listUri) { return uri.Equals(listUri); });
313             if (haveIter == iter->second.at(taskData->notifyType_).end()) {
314                 iter->second.find(taskData->notifyType_)->second.emplace_back(uri);
315             }
316         }
317     }
318 }
319 
GetAlbumsById(const string & fileId,list<string> & albumIdList)320 static int32_t GetAlbumsById(const string &fileId, list<string> &albumIdList)
321 {
322     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
323     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "rdbstore is nullptr");
324     MediaLibraryCommand queryAlbumMapCmd(OperationObject::PAH_PHOTO, OperationType::QUERY);
325     queryAlbumMapCmd.GetAbsRdbPredicates()->EqualTo(PhotoColumn::MEDIA_ID, fileId);
326     auto resultSet = uniStore->Query(queryAlbumMapCmd, {PhotoColumn::PHOTO_OWNER_ALBUM_ID});
327     if (resultSet == nullptr) {
328         MEDIA_ERR_LOG("GetAlbumsById failed");
329         return E_INVALID_FILEID;
330     }
331     int32_t count = -1;
332     int32_t ret = resultSet->GetRowCount(count);
333     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to get count");
334     if (count <= 0) {
335         return E_OK;
336     }
337     ret = resultSet->GoToFirstRow();
338     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to GoToFirstRow");
339     do {
340         int32_t albumId = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoColumn::PHOTO_OWNER_ALBUM_ID,
341             resultSet, TYPE_INT32));
342         albumIdList.emplace_back(to_string(albumId));
343     } while (!resultSet->GoToNextRow());
344     return E_OK;
345 }
346 
HandleAlbumNotify(NotifyTaskData * taskData)347 static void HandleAlbumNotify(NotifyTaskData *taskData)
348 {
349     list<string> albumIdList;
350     string id = MediaFileUtils::GetIdFromUri(taskData->uri_);
351     int err = GetAlbumsById(id, albumIdList);
352     CHECK_AND_RETURN_LOG(err == E_OK, "Fail to get albumId");
353     for (const string &id : albumIdList) {
354         AddNotify(taskData->uri_, PhotoAlbumColumns::ALBUM_URI_PREFIX + id, taskData);
355     }
356 
357     if (!taskData->hiddenOnly_) {
358         return;
359     }
360     NotifyType hiddenAlbumsNotifyType = taskData->notifyType_;
361     if (taskData->notifyType_ == NotifyType::NOTIFY_ALBUM_ADD_ASSET) {
362         hiddenAlbumsNotifyType = NotifyType::NOTIFY_ALBUM_REMOVE_ASSET;
363     } else if (taskData->notifyType_ == NotifyType::NOTIFY_ALBUM_REMOVE_ASSET) {
364         hiddenAlbumsNotifyType = NotifyType::NOTIFY_ALBUM_ADD_ASSET;
365     }
366     taskData->notifyType_ = hiddenAlbumsNotifyType;
367     for (const string &id : albumIdList) {
368         AddNotify(taskData->uri_, PhotoAlbumColumns::HIDDEN_ALBUM_URI_PREFIX + id, taskData);
369     }
370 }
371 
AddNfListMap(AsyncTaskData * data)372 static void AddNfListMap(AsyncTaskData *data)
373 {
374     if (data == nullptr) {
375         return;
376     }
377     auto* taskData = static_cast<NotifyTaskData*>(data);
378     if ((taskData->notifyType_ == NotifyType::NOTIFY_ALBUM_ADD_ASSET) ||
379         (taskData->notifyType_ == NotifyType::NOTIFY_ALBUM_REMOVE_ASSET)) {
380         if (taskData->albumId_ > 0) {
381             AddNotify(taskData->uri_,
382                 PhotoAlbumColumns::ALBUM_URI_PREFIX  + to_string(taskData->albumId_), taskData);
383         } else {
384             HandleAlbumNotify(taskData);
385         }
386     } else {
387         string typeUri = MediaLibraryDataManagerUtils::GetTypeUriByUri(taskData->uri_);
388         AddNotify(taskData->uri_, typeUri, taskData);
389     }
390     auto periodWorker = MediaLibraryPeriodWorker::GetInstance();
391     if (periodWorker != nullptr && !periodWorker->IsThreadRunning(PeriodTaskType::COMMON_NOTIFY)) {
392         MediaLibraryNotify::counts_.store(0);
393         periodWorker->StartTask(PeriodTaskType::COMMON_NOTIFY, PushNotification, nullptr);
394         MEDIA_INFO_LOG("common notify thread is started");
395     }
396 }
397 
Init()398 int32_t MediaLibraryNotify::Init()
399 {
400     auto periodWorker = MediaLibraryPeriodWorker::GetInstance();
401     if (periodWorker == nullptr) {
402         MEDIA_ERR_LOG("failed to get period worker instance");
403         return E_ERR;
404     }
405     periodWorker->StartTask(PeriodTaskType::COMMON_NOTIFY, PushNotification, nullptr);
406     MEDIA_INFO_LOG("add notify task");
407     return E_OK;
408 }
409 
Notify(const string & uri,const NotifyType notifyType,const int albumId,const bool hiddenOnly)410 int32_t MediaLibraryNotify::Notify(const string &uri, const NotifyType notifyType, const int albumId,
411     const bool hiddenOnly)
412 {
413     unique_ptr<NotifyTaskWorker> &asyncWorker = NotifyTaskWorker::GetInstance();
414     CHECK_AND_RETURN_RET_LOG(asyncWorker != nullptr, E_ASYNC_WORKER_IS_NULL, "AsyncWorker is null");
415     auto *taskData = new (nothrow) NotifyTaskData(uri, notifyType, albumId, hiddenOnly);
416     CHECK_AND_RETURN_RET_LOG(taskData != nullptr, E_NOTIFY_TASK_DATA_IS_NULL, "taskData is null");
417     MEDIA_DEBUG_LOG("Notify ,uri = %{private}s, notifyType = %{private}d, albumId = %{private}d",
418         uri.c_str(), notifyType, albumId);
419     shared_ptr<MediaLibraryAsyncTask> notifyAsyncTask = make_shared<MediaLibraryAsyncTask>(AddNfListMap, taskData);
420     if (notifyAsyncTask != nullptr) {
421         asyncWorker->AddTask(notifyAsyncTask);
422     }
423     return E_OK;
424 }
425 
Notify(const shared_ptr<FileAsset> & closeAsset)426 int32_t MediaLibraryNotify::Notify(const shared_ptr<FileAsset> &closeAsset)
427 {
428     bool isCreateFile = false;
429     if (closeAsset->GetDateModified() == 0) {
430         isCreateFile = true;
431     }
432     if (closeAsset->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE ||
433         closeAsset->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) {
434         if (isCreateFile) {
435             return Notify(PhotoColumn::PHOTO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_ADD);
436         }
437         return Notify(PhotoColumn::PHOTO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_UPDATE);
438     } else if (closeAsset->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO) {
439         if (isCreateFile) {
440             return Notify(AudioColumn::AUDIO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_ADD);
441         }
442         return Notify(AudioColumn::AUDIO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_UPDATE);
443     } else {
444         return E_CHECK_MEDIATYPE_FAIL;
445     }
446 }
447 
GetDefaultAlbums(std::unordered_map<PhotoAlbumSubType,int> & outAlbums)448 int32_t MediaLibraryNotify::GetDefaultAlbums(std::unordered_map<PhotoAlbumSubType, int> &outAlbums)
449 {
450     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
451     MediaLibraryCommand queryAlbumMapCmd(OperationObject::PHOTO_ALBUM, OperationType::QUERY);
452     queryAlbumMapCmd.GetAbsRdbPredicates()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
453     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr!");
454     auto resultSet = uniStore->Query(queryAlbumMapCmd,
455         {PhotoAlbumColumns::ALBUM_ID, PhotoAlbumColumns::ALBUM_SUBTYPE});
456     if (resultSet == nullptr) {
457         return E_HAS_DB_ERROR;
458     }
459     int32_t count = -1;
460     int32_t ret = resultSet->GetRowCount(count);
461     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to get count");
462     ret = resultSet->GoToFirstRow();
463     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to GoToFirstRow");
464     do {
465         int32_t albumId = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
466             TYPE_INT32));
467         int32_t albumSubType = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE,
468             resultSet, TYPE_INT32));
469         MEDIA_INFO_LOG("GetDefaultAlbums albumId: %{public}d, albumSubType: %{public}d", albumId, albumSubType);
470         outAlbums.insert(make_pair(static_cast<PhotoAlbumSubType>(albumSubType), albumId));
471     } while (!resultSet->GoToNextRow());
472     return E_OK;
473 }
474 
GetAlbumIdBySubType(const PhotoAlbumSubType subType)475 int32_t MediaLibraryNotify::GetAlbumIdBySubType(const PhotoAlbumSubType subType)
476 {
477     int errCode = E_OK;
478     if (defaultAlbums_.size() == 0) {
479         errCode = GetDefaultAlbums(defaultAlbums_);
480     }
481     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to GetDefaultAlbums");
482     if (defaultAlbums_.count(subType) == 0) {
483         return E_ERR;
484     }
485     return defaultAlbums_.find(subType)->second;
486 }
487 
GetNotifyUri(shared_ptr<NativeRdb::ResultSet> & resultSet,vector<string> & notifyUris)488 static void GetNotifyUri(shared_ptr<NativeRdb::ResultSet> &resultSet, vector<string> &notifyUris)
489 {
490     int32_t fileId = MediaLibraryRdbStore::GetInt(resultSet, PhotoColumn::MEDIA_ID);
491     string path = MediaLibraryRdbStore::GetString(resultSet, PhotoColumn::MEDIA_FILE_PATH);
492     string displayName = MediaLibraryRdbStore::GetString(resultSet, PhotoColumn::MEDIA_NAME);
493     string notifyUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileId),
494         MediaFileUtils::GetExtraUri(displayName, path));
495     notifyUris.push_back(notifyUri);
496 }
497 
GetNotifyUris(const NativeRdb::AbsRdbPredicates & predicates,vector<string> & notifyUris)498 void MediaLibraryNotify::GetNotifyUris(const NativeRdb::AbsRdbPredicates &predicates, vector<string> &notifyUris)
499 {
500     MediaLibraryTracer tracer;
501     tracer.Start("GetNotifyUris");
502     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
503     if (rdbStore == nullptr) {
504         return;
505     }
506     auto resultSet = rdbStore->QueryWithFilter(predicates, {
507         PhotoColumn::MEDIA_ID,
508         PhotoColumn::MEDIA_FILE_PATH,
509         PhotoColumn::MEDIA_NAME
510     });
511     if (resultSet == nullptr) {
512         return;
513     }
514 
515     int32_t count = 0;
516     int32_t err = resultSet->GetRowCount(count);
517     if (err != E_OK || count <= 0) {
518         MEDIA_WARN_LOG("Failed to get row count: %{public}d", err);
519         return;
520     }
521     err = resultSet->GoToFirstRow();
522     if (err != E_OK) {
523         MEDIA_WARN_LOG("Failed to go to first row: %{public}d", err);
524         return;
525     }
526     do {
527         GetNotifyUri(resultSet, notifyUris);
528         count--;
529         if (count > 0) {
530             err = resultSet->GoToNextRow();
531             if (err < 0) {
532                 MEDIA_WARN_LOG("Failed to go to next row err: %{public}d", err);
533                 return;
534             }
535         }
536     } while (count > 0);
537 }
538 
NotifyTaskWorker()539 NotifyTaskWorker::NotifyTaskWorker() : isThreadRunning_(false)
540 {}
541 
~NotifyTaskWorker()542 NotifyTaskWorker::~NotifyTaskWorker()
543 {
544     isThreadRunning_ = false;
545     if (thread_.joinable()) {
546         thread_.join();
547     }
548 }
549 
StartThread()550 void NotifyTaskWorker::StartThread()
551 {
552     MEDIA_INFO_LOG("Start notify thread");
553     isThreadRunning_ = true;
554     if (thread_.joinable()) {
555         thread_.join();
556     }
557     thread_ = std::thread([this]() { this->StartWorker(); });
558 }
559 
AddTask(const shared_ptr<MediaLibraryAsyncTask> & task)560 int32_t NotifyTaskWorker::AddTask(const shared_ptr<MediaLibraryAsyncTask> &task)
561 {
562     lock_guard<mutex> lockGuard(taskLock_);
563     taskQueue_.push(task);
564     if (isThreadRunning_) {
565         taskCv_.notify_all();
566     } else {
567         StartThread();
568     }
569     return 0;
570 }
571 
GetTask()572 shared_ptr<MediaLibraryAsyncTask> NotifyTaskWorker::GetTask()
573 {
574     lock_guard<mutex> lockGuard(taskLock_);
575     if (taskQueue_.empty()) {
576         return nullptr;
577     }
578     shared_ptr<MediaLibraryAsyncTask> task = taskQueue_.front();
579     taskQueue_.pop();
580     return task;
581 }
582 
IsQueueEmpty()583 bool NotifyTaskWorker::IsQueueEmpty()
584 {
585     lock_guard<mutex> lock_Guard(taskLock_);
586     return taskQueue_.empty();
587 }
588 
WaitForTask()589 bool NotifyTaskWorker::WaitForTask()
590 {
591     std::unique_lock<std::mutex> lock(cvLock_);
592     return taskCv_.wait_for(lock, std::chrono::minutes(WAIT_TIME),
593         [this]() { return !IsQueueEmpty(); });
594 }
595 
StartWorker()596 void NotifyTaskWorker::StartWorker()
597 {
598     string name("NotifyTaskWorker");
599     pthread_setname_np(pthread_self(), name.c_str());
600     while (true) {
601         if (WaitForTask()) {
602             shared_ptr<MediaLibraryAsyncTask> task = GetTask();
603             if (task != nullptr) {
604                 task->executor_(task->data_);
605                 task = nullptr;
606             }
607         } else {
608             MEDIA_INFO_LOG("Notify queue is empty, end thread");
609             isThreadRunning_ = false;
610             return;
611         }
612     }
613 }
614 } // namespace OHOS::Media
615