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 ¬ifyUri, 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 ¬ifyUri, 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> ¬ifyUris)
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> ¬ifyUris)
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