• 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 #include "data_ability_helper_impl.h"
18 #include "media_file_utils.h"
19 #include "media_log.h"
20 #include "medialibrary_command.h"
21 #include "medialibrary_data_manager_utils.h"
22 #include "medialibrary_db_const.h"
23 #include "medialibrary_errno.h"
24 #include "medialibrary_object_utils.h"
25 #include "medialibrary_unistore_manager.h"
26 #include "photo_album_column.h"
27 #include "photo_map_column.h"
28 #include "result_set_utils.h"
29 #include "uri.h"
30 
31 using namespace std;
32 
33 namespace OHOS::Media {
34 using ChangeType = AAFwk::ChangeInfo::ChangeType;
35 using NotifyDataMap = unordered_map<NotifyType, list<Uri>>;
36 shared_ptr<MediaLibraryNotify> MediaLibraryNotify::instance_;
37 mutex MediaLibraryNotify::mutex_;
38 unordered_map<string, NotifyDataMap> MediaLibraryNotify::nfListMap_ = {};
39 Utils::Timer MediaLibraryNotify::timer_("on_notify");
40 uint32_t MediaLibraryNotify::timerId_ = 0;
41 
GetInstance()42 shared_ptr<MediaLibraryNotify> MediaLibraryNotify::GetInstance()
43 {
44     if (instance_ != nullptr) {
45         return instance_;
46     }
47     lock_guard<mutex> lock(mutex_);
48     if (instance_ == nullptr) {
49         instance_ = shared_ptr<MediaLibraryNotify>(new MediaLibraryNotify());
50         if (instance_ == nullptr) {
51             MEDIA_ERR_LOG("GetInstance nullptr");
52             return instance_;
53         }
54         instance_->Init();
55     }
56     return instance_;
57 }
58 MediaLibraryNotify::MediaLibraryNotify() = default;
59 
~MediaLibraryNotify()60 MediaLibraryNotify::~MediaLibraryNotify()
61 {
62     timer_.Shutdown();
63     timer_.Unregister(timerId_);
64 };
65 
SolveUris(const list<Uri> & uris,Parcel & parcel)66 static bool SolveUris(const list<Uri> &uris, Parcel &parcel)
67 {
68     if (uris.size() > numeric_limits<uint32_t>::max() ||
69         !parcel.WriteUint32(static_cast<uint32_t>(uris.size()))) {
70         MEDIA_ERR_LOG("Failed to write uri list length, list size = %{private}zu", uris.size());
71         return false;
72     }
73     for (auto const &uri : uris) {
74         if (!parcel.WriteString(uri.ToString())) {
75             MEDIA_ERR_LOG("Failed to write strUri uri = %{private}s", uri.ToString().c_str());
76             return false;
77         }
78     }
79     return true;
80 }
81 
SendAlbumSub(const Uri & notifyUri,NotifyType type,list<Uri> & uris)82 static int SendAlbumSub(const Uri &notifyUri, NotifyType type, list<Uri> &uris)
83 {
84     Parcel parcel;
85     CHECK_AND_RETURN_RET_LOG(SolveUris(uris, parcel), E_SOLVE_URIS_FAILED, "SolveUris failed");
86     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
87     uintptr_t buf = parcel.GetData();
88     if (parcel.GetDataSize() == 0) {
89         MEDIA_ERR_LOG("NotifyChangeExt parcel.GetDataSize failed");
90         return E_PARCEL_GET_SIZE_FAILED;
91     }
92     auto *uBuf = new (std::nothrow) uint8_t[parcel.GetDataSize()];
93     int ret = memcpy_s(uBuf, parcel.GetDataSize(), reinterpret_cast<uint8_t *>(buf), parcel.GetDataSize());
94     if (ret != 0) {
95         MEDIA_ERR_LOG("Parcel data copy failed, err = %{public}d", ret);
96     }
97     ChangeType changeType;
98     if (type == NotifyType::NOTIFY_ALBUM_ADD_ASSERT) {
99         changeType = ChangeType::INSERT;
100     } else {
101         changeType = ChangeType::DELETE;
102     }
103     return obsMgrClient->NotifyChangeExt({changeType, {notifyUri}, uBuf, parcel.GetDataSize()});
104 }
105 
SolveAlbumUri(const Uri & notifyUri,NotifyType type,list<Uri> & uris)106 static int SolveAlbumUri(const Uri &notifyUri, NotifyType type, list<Uri> &uris)
107 {
108     auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
109     if ((type == NotifyType::NOTIFY_ALBUM_ADD_ASSERT) || (type == NotifyType::NOTIFY_ALBUM_REMOVE_ASSET)) {
110         return SendAlbumSub(notifyUri, type, uris);
111     } else {
112         return obsMgrClient->NotifyChangeExt({static_cast<ChangeType>(type), uris});
113     }
114 }
115 
PushNotifyDataMap(const string & uri,NotifyDataMap notifyDataMap)116 static void PushNotifyDataMap(const string &uri, NotifyDataMap notifyDataMap)
117 {
118     int ret;
119     for (auto &[type, uris] : notifyDataMap) {
120         if (uri.find(PhotoAlbumColumns::ALBUM_URI_PREFIX) != string::npos) {
121             Uri notifyUri = Uri(uri);
122             ret = SolveAlbumUri(notifyUri, type, uris);
123         } else {
124             auto obsMgrClient = AAFwk::DataObsMgrClient::GetInstance();
125             ret = obsMgrClient->NotifyChangeExt({static_cast<ChangeType>(type), uris});
126         }
127         if (ret != E_OK) {
128             MEDIA_ERR_LOG("PushNotification failed, errorCode = %{public}d", ret);
129         }
130     }
131     return;
132 }
133 
PushNotification()134 static void PushNotification()
135 {
136     unordered_map<string, NotifyDataMap> tmpNfListMap;
137     {
138         lock_guard<mutex> lock(MediaLibraryNotify::mutex_);
139         if (MediaLibraryNotify::nfListMap_.empty()) {
140             return;
141         }
142         MediaLibraryNotify::nfListMap_.swap(tmpNfListMap);
143         MediaLibraryNotify::nfListMap_.clear();
144     }
145     for (auto &[uri, notifyDataMap] : tmpNfListMap) {
146         if (notifyDataMap.empty()) {
147             continue;
148         }
149         PushNotifyDataMap(uri, notifyDataMap);
150     }
151 }
152 
AddNotify(const string & srcUri,const string & keyUri,NotifyTaskData * taskData)153 static void AddNotify(const string &srcUri, const string &keyUri, NotifyTaskData* taskData)
154 {
155     NotifyDataMap notifyDataMap;
156     list<Uri> sendUris;
157     Uri uri(srcUri);
158     MEDIA_DEBUG_LOG("AddNotify ,keyUri = %{private}s, uri = %{private}s, "
159         "notifyType = %{private}d", keyUri.c_str(), uri.ToString().c_str(), taskData->notifyType_);
160     lock_guard<mutex> lock(MediaLibraryNotify::mutex_);
161     if (MediaLibraryNotify::nfListMap_.count(keyUri) == 0) {
162         sendUris.emplace_back(uri);
163         notifyDataMap.insert(make_pair(taskData->notifyType_, sendUris));
164         MediaLibraryNotify::nfListMap_.insert(make_pair(keyUri, notifyDataMap));
165     } else {
166         auto iter = MediaLibraryNotify::nfListMap_.find(keyUri);
167         if (iter->second.count(taskData->notifyType_) == 0) {
168             sendUris.emplace_back(uri);
169             iter->second.insert(make_pair(taskData->notifyType_, sendUris));
170         } else {
171             auto haveIter = find_if(
172                 iter->second.at(taskData->notifyType_).begin(),
173                 iter->second.at(taskData->notifyType_).end(),
174                 [uri](const Uri &listUri) { return uri.Equals(listUri); });
175             if (haveIter == iter->second.at(taskData->notifyType_).end()) {
176                 iter->second.find(taskData->notifyType_)->second.emplace_back(uri);
177             }
178         }
179     }
180 }
181 
GetAlbumUrisById(const string & fileId,list<string> & albumUriList)182 static int32_t GetAlbumUrisById(const string &fileId, list<string> &albumUriList)
183 {
184     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
185     MediaLibraryCommand queryAlbumMapCmd(OperationObject::PHOTO_MAP, OperationType::QUERY);
186     queryAlbumMapCmd.GetAbsRdbPredicates()->EqualTo(PhotoMap::ASSET_ID, fileId);
187     auto resultSet = uniStore->Query(queryAlbumMapCmd, {PhotoMap::ALBUM_ID});
188     if (resultSet == nullptr) {
189         MEDIA_ERR_LOG("GetAlbumUrisById failed");
190         return E_INVALID_FILEID;
191     }
192     int32_t count = -1;
193     int32_t ret = resultSet->GetRowCount(count);
194     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to get count");
195     ret = resultSet->GoToFirstRow();
196     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to GoToFirstRow");
197     do {
198         int32_t albumId = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoMap::ALBUM_ID, resultSet,
199             TYPE_INT32));
200         string albumUri = PhotoAlbumColumns::ALBUM_URI_PREFIX  + to_string(albumId);
201         albumUriList.emplace_back(albumUri);
202     } while (!resultSet->GoToNextRow());
203     return E_OK;
204 }
205 
AddNfListMap(AsyncTaskData * data)206 static void AddNfListMap(AsyncTaskData *data)
207 {
208     if (data == nullptr) {
209         return;
210     }
211     auto* taskData = static_cast<NotifyTaskData*>(data);
212     if ((taskData->notifyType_ == NotifyType::NOTIFY_ALBUM_ADD_ASSERT) ||
213         (taskData->notifyType_ == NotifyType::NOTIFY_ALBUM_REMOVE_ASSET)) {
214         if (taskData->albumId_ > 0) {
215             AddNotify(taskData->uri_,
216                 PhotoAlbumColumns::ALBUM_URI_PREFIX  + to_string(taskData->albumId_), taskData);
217         } else {
218             list<string> albumUriList;
219             string id = MediaLibraryDataManagerUtils::GetIdFromUri(taskData->uri_);
220             int err = GetAlbumUrisById(id, albumUriList);
221             CHECK_AND_RETURN_LOG(err == E_OK, "Fail to get albumId");
222             for (string uri : albumUriList) {
223                 AddNotify(taskData->uri_, uri, taskData);
224             }
225         }
226     } else {
227         string typeUri = MediaLibraryDataManagerUtils::GetTypeUriByUri(taskData->uri_);
228         AddNotify(taskData->uri_, typeUri, taskData);
229     }
230 }
231 
Init()232 int32_t MediaLibraryNotify::Init()
233 {
234     MediaLibraryNotify::timerId_ = MediaLibraryNotify::timer_.Register(PushNotification, MNOTIFY_TIME_INTERVAL);
235     MediaLibraryNotify::timer_.Setup();
236     return E_OK;
237 }
238 
Notify(const string & uri,const NotifyType notifyType,const int albumId)239 int32_t MediaLibraryNotify::Notify(const string &uri, const NotifyType notifyType, const int albumId)
240 {
241     if (MediaLibraryNotify::nfListMap_.size() > MAX_NOTIFY_LIST_SIZE) {
242         MediaLibraryNotify::timer_.Shutdown();
243         PushNotification();
244         MediaLibraryNotify::timer_.Register(PushNotification, MNOTIFY_TIME_INTERVAL);
245         MediaLibraryNotify::timer_.Setup();
246     }
247     shared_ptr<MediaLibraryAsyncWorker> asyncWorker = MediaLibraryAsyncWorker::GetInstance();
248     CHECK_AND_RETURN_RET_LOG(asyncWorker != nullptr, E_ASYNC_WORKER_IS_NULL, "AsyncWorker is null");
249     auto *taskData = new (nothrow) NotifyTaskData(uri, notifyType, albumId);
250     CHECK_AND_RETURN_RET_LOG(taskData != nullptr, E_NOTIFY_TASK_DATA_IS_NULL, "taskData is null");
251     MEDIA_DEBUG_LOG("Notify ,uri = %{private}s, notifyType = %{private}d, albumId = %{private}d",
252         uri.c_str(), notifyType, albumId);
253     shared_ptr<MediaLibraryAsyncTask> notifyAsyncTask = make_shared<MediaLibraryAsyncTask>(AddNfListMap, taskData);
254     if (notifyAsyncTask != nullptr) {
255         asyncWorker->AddTask(notifyAsyncTask, false);
256     }
257     return E_OK;
258 }
259 
Notify(const shared_ptr<FileAsset> & closeAsset)260 int32_t MediaLibraryNotify::Notify(const shared_ptr<FileAsset> &closeAsset)
261 {
262     bool isCreateFile = false;
263     if (closeAsset->GetDateModified() == 0) {
264         isCreateFile = true;
265     }
266     if (closeAsset->GetMediaType() == MediaType::MEDIA_TYPE_IMAGE ||
267         closeAsset->GetMediaType() == MediaType::MEDIA_TYPE_VIDEO) {
268         if (isCreateFile) {
269             return Notify(PhotoColumn::PHOTO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_ADD);
270         }
271         return Notify(PhotoColumn::PHOTO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_UPDATE);
272     } else if (closeAsset->GetMediaType() == MediaType::MEDIA_TYPE_AUDIO) {
273         if (isCreateFile) {
274             return Notify(AudioColumn::AUDIO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_ADD);
275         }
276         return Notify(AudioColumn::AUDIO_URI_PREFIX + to_string(closeAsset->GetId()), NotifyType::NOTIFY_UPDATE);
277     } else {
278         return E_CHECK_MEDIATYPE_FAIL;
279     }
280 }
281 
GetDefaultAlbums(std::unordered_map<PhotoAlbumSubType,int> & outAlbums)282 int32_t MediaLibraryNotify::GetDefaultAlbums(std::unordered_map<PhotoAlbumSubType, int> &outAlbums)
283 {
284     auto uniStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
285     MediaLibraryCommand queryAlbumMapCmd(OperationObject::PHOTO_ALBUM, OperationType::QUERY);
286     queryAlbumMapCmd.GetAbsRdbPredicates()->EqualTo(PhotoAlbumColumns::ALBUM_TYPE, to_string(PhotoAlbumType::SYSTEM));
287     CHECK_AND_RETURN_RET_LOG(uniStore != nullptr, E_HAS_DB_ERROR, "UniStore is nullptr!");
288     auto resultSet = uniStore->Query(queryAlbumMapCmd,
289         {PhotoAlbumColumns::ALBUM_ID, PhotoAlbumColumns::ALBUM_SUBTYPE});
290     if (resultSet == nullptr) {
291         return E_HAS_DB_ERROR;
292     }
293     int32_t count = -1;
294     int32_t ret = resultSet->GetRowCount(count);
295     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to get count");
296     ret = resultSet->GoToFirstRow();
297     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to GoToFirstRow");
298     do {
299         int32_t albumId = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_ID, resultSet,
300             TYPE_INT32));
301         int32_t albumSubType = get<int32_t>(ResultSetUtils::GetValFromColumn(PhotoAlbumColumns::ALBUM_SUBTYPE,
302             resultSet, TYPE_INT32));
303         MEDIA_INFO_LOG("GetDefaultAlbums albumId: %{public}d, albumSubType: %{public}d", albumId, albumSubType);
304         outAlbums.insert(make_pair(static_cast<PhotoAlbumSubType>(albumSubType), albumId));
305     } while (!resultSet->GoToNextRow());
306     return E_OK;
307 }
308 
GetAlbumIdBySubType(const PhotoAlbumSubType subType)309 int32_t MediaLibraryNotify::GetAlbumIdBySubType(const PhotoAlbumSubType subType)
310 {
311     int errCode = E_OK;
312     if (defaultAlbums_.size() == 0) {
313         errCode = GetDefaultAlbums(defaultAlbums_);
314     }
315     CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode, "Failed to GetDefaultAlbums");
316     if (defaultAlbums_.count(subType) == 0) {
317         return E_ERR;
318     }
319     return defaultAlbums_.find(subType)->second;
320 }
321 
GetNotifyUri(shared_ptr<NativeRdb::ResultSet> & resultSet,vector<string> & notifyUris)322 static void GetNotifyUri(shared_ptr<NativeRdb::ResultSet> &resultSet, vector<string> &notifyUris)
323 {
324     int32_t fileId = MediaLibraryRdbStore::GetInt(resultSet, PhotoColumn::MEDIA_ID);
325     string path = MediaLibraryRdbStore::GetString(resultSet, PhotoColumn::MEDIA_FILE_PATH);
326     string displayName = MediaLibraryRdbStore::GetString(resultSet, PhotoColumn::MEDIA_NAME);
327     string notifyUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileId),
328         MediaFileUtils::GetExtraUri(displayName, path));
329     notifyUris.push_back(notifyUri);
330 }
331 
GetNotifyUris(const RdbPredicates & predicates,vector<string> & notifyUris)332 void MediaLibraryNotify::GetNotifyUris(const RdbPredicates &predicates, vector<string> &notifyUris)
333 {
334     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStoreRaw();
335     if (rdbStore == nullptr) {
336         return;
337     }
338     auto resultSet = rdbStore->Query(predicates, {
339         PhotoColumn::MEDIA_ID,
340         PhotoColumn::MEDIA_FILE_PATH,
341         PhotoColumn::MEDIA_NAME
342     });
343     if (resultSet == nullptr) {
344         return;
345     }
346 
347     int32_t count = 0;
348     int32_t err = resultSet->GetRowCount(count);
349     if (err != E_OK || count <= 0) {
350         MEDIA_WARN_LOG("Failed to get row count: %{public}d", err);
351         return;
352     }
353     err = resultSet->GoToFirstRow();
354     if (err != E_OK) {
355         MEDIA_WARN_LOG("Failed to go to first row: %{public}d", err);
356         return;
357     }
358     do {
359         GetNotifyUri(resultSet, notifyUris);
360         count--;
361         if (count > 0) {
362             err = resultSet->GoToNextRow();
363             if (err < 0) {
364                 MEDIA_WARN_LOG("Failed to go to next row err: %{public}d", err);
365                 return;
366             }
367         }
368     } while (count > 0);
369 }
370 } // namespace OHOS::Media
371