• 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 "ptp_media_sync_observer.h"
17 
18 #include <chrono>
19 #include <cctype>
20 #include <securec.h>
21 
22 #include "media_log.h"
23 #include "ptp_album_handles.h"
24 #include "photo_album_column.h"
25 #include "datashare_predicates.h"
26 #include "datashare_abs_result_set.h"
27 #include "result_set_utils.h"
28 #include "media_file_uri.h"
29 
30 using namespace std;
31 
32 namespace OHOS {
33 namespace Media {
34 constexpr int32_t RESERVE_ALBUM = 10;
35 constexpr int32_t PARENT_ID = 0;
36 constexpr int32_t DELETE_LIMIT_TIME = 5000;
37 constexpr int32_t ERR_NUM = -1;
38 constexpr int32_t MAX_PARCEL_LEN_LIMIT = 5000;
39 const string BURST_COVER_LEVEL = "1";
40 const string BURST_NOT_COVER_LEVEL = "2";
41 const string IS_LOCAL = "2";
42 const std::string HIDDEN_ALBUM = ".hiddenAlbum";
43 const string POSITION = "2";
44 const string INVALID_FILE_ID = "-1";
45 constexpr uint64_t DELAY_MS = 5000;
startsWith(const std::string & str,const std::string & prefix)46 bool startsWith(const std::string& str, const std::string& prefix)
47 {
48     bool cond = (prefix.size() > str.size() || prefix.empty() || str.empty());
49     CHECK_AND_RETURN_RET_LOG(!cond, false, "MtpMediaLibrary::StartsWith prefix size error");
50 
51     for (size_t i = 0; i < prefix.size(); ++i) {
52         CHECK_AND_RETURN_RET(str[i] == prefix[i], false);
53     }
54     return true;
55 }
56 
SendEventPackets(uint32_t objectHandle,uint16_t eventCode)57 void MediaSyncObserver::SendEventPackets(uint32_t objectHandle, uint16_t eventCode)
58 {
59     EventMtp event;
60     event.length = MTP_CONTAINER_HEADER_SIZE + sizeof(objectHandle);
61     vector<uint8_t> outBuffer;
62     MtpPacketTool::PutUInt32(outBuffer, event.length);
63     MtpPacketTool::PutUInt16(outBuffer, EVENT_CONTAINER_TYPE);
64     MtpPacketTool::PutUInt16(outBuffer, eventCode);
65     CHECK_AND_RETURN_LOG(context_ != nullptr, "Mtp Ptp context is nullptr");
66     MtpPacketTool::PutUInt32(outBuffer, context_->transactionID);
67     MtpPacketTool::PutUInt32(outBuffer, objectHandle);
68     MEDIA_DEBUG_LOG("MtpMediaLibrary album [%{public}d]", objectHandle);
69 
70     event.data = outBuffer;
71     CHECK_AND_RETURN_LOG(context_->mtpDriver != nullptr, "Mtp Ptp mtpDriver is nullptr");
72     context_->mtpDriver->WriteEvent(event);
73 }
74 
SendEventPacketAlbum(uint32_t objectHandle,uint16_t eventCode)75 void MediaSyncObserver::SendEventPacketAlbum(uint32_t objectHandle, uint16_t eventCode)
76 {
77     EventMtp event;
78     event.length = MTP_CONTAINER_HEADER_SIZE + sizeof(objectHandle);
79     vector<uint8_t> outBuffer;
80     MtpPacketTool::PutUInt32(outBuffer, event.length);
81     MtpPacketTool::PutUInt16(outBuffer, EVENT_CONTAINER_TYPE);
82     MtpPacketTool::PutUInt16(outBuffer, eventCode);
83     MtpPacketTool::PutUInt32(outBuffer, PARENT_ID);
84     MtpPacketTool::PutUInt32(outBuffer, objectHandle);
85 
86     event.data = outBuffer;
87     MEDIA_DEBUG_LOG("MtpMediaLibrary album [%{public}d]", objectHandle);
88     CHECK_AND_RETURN_LOG(context_ != nullptr, "Mtp Ptp context is nullptr");
89     CHECK_AND_RETURN_LOG(context_->mtpDriver != nullptr, "Mtp Ptp mtpDriver is nullptr");
90     context_->mtpDriver->WriteEvent(event);
91 }
92 
IsNumber(const string & str)93 static bool IsNumber(const string& str)
94 {
95     CHECK_AND_RETURN_RET_LOG(!str.empty(), false, "IsNumber input is empty");
96     for (char const& c : str) {
97         CHECK_AND_RETURN_RET(isdigit(c) != 0, false);
98     }
99     return true;
100 }
101 
GetHandlesFromPhotosInfoBurstKeys(vector<std::string> & handles)102 vector<int32_t> MediaSyncObserver::GetHandlesFromPhotosInfoBurstKeys(vector<std::string> &handles)
103 {
104     vector<int32_t> handlesResult;
105     CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, handlesResult,
106         "Mtp GetHandlesFromPhotosInfoBurstKeys fail to get datasharehelper");
107     CHECK_AND_RETURN_RET_LOG(!handles.empty(), handlesResult, "Mtp handles have no elements!");
108     Uri uri(PAH_QUERY_PHOTO);
109     vector<string> columns;
110     columns.push_back(PhotoColumn::PHOTO_BURST_KEY);
111     DataShare::DataSharePredicates predicates;
112     predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL, BURST_COVER_LEVEL);
113     predicates.IsNotNull(PhotoColumn::PHOTO_BURST_KEY);
114     predicates.In(PhotoColumn::MEDIA_ID, handles);
115     shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
116 
117     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
118         handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys fail to get PHOTO_BURST_KEY");
119     CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
120         handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys have no PHOTO_BURST_KEY");
121     vector<string> burstKey;
122     do {
123         burstKey.push_back(GetStringVal(PhotoColumn::PHOTO_BURST_KEY, resultSet));
124     } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
125 
126     CHECK_AND_RETURN_RET_LOG(!burstKey.empty(), handlesResult,
127         "Mtp GetHandlesFromPhotosInfoBurstKeys burstKey is empty");
128 
129     columns.clear();
130     columns.push_back(PhotoColumn::MEDIA_ID);
131     DataShare::DataSharePredicates predicatesHandles;
132     predicatesHandles.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL, BURST_NOT_COVER_LEVEL);
133     predicatesHandles.IsNotNull(PhotoColumn::PHOTO_BURST_KEY);
134     predicatesHandles.In(PhotoColumn::PHOTO_BURST_KEY, burstKey);
135     resultSet = dataShareHelper_->Query(uri, predicatesHandles, columns);
136     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
137         handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys fail to get handles");
138     CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
139         handlesResult, "Mtp GetHandlesFromPhotosInfoBurstKeys have no handles");
140     do {
141         string file_id = GetStringVal(PhotoColumn::MEDIA_ID, resultSet);
142         if (!IsNumber(file_id)) {
143             MEDIA_ERR_LOG("Mtp GetHandlesFromPhotosInfoBurstKeys id is incorrect ");
144             continue;
145         }
146         handlesResult.push_back(atoi(file_id.c_str()));
147     } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
148     return handlesResult;
149 }
150 
GetAllDeleteHandles()151 vector<string> MediaSyncObserver::GetAllDeleteHandles()
152 {
153     vector<string> handlesResult;
154     CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr, handlesResult,
155         "Mtp GetAllDeleteHandles fail to get datasharehelper");
156     Uri uri(PAH_QUERY_PHOTO);
157     vector<string> columns;
158     columns.push_back(MediaColumn::MEDIA_ID);
159     DataShare::DataSharePredicates predicates;
160     auto now = std::chrono::system_clock::now();
161     auto now_milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count();
162     auto new_timestamp = now_milliseconds - DELETE_LIMIT_TIME;
163     predicates.GreaterThan(MediaColumn::MEDIA_DATE_TRASHED, to_string(new_timestamp));
164     shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
165 
166     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
167         handlesResult, "Mtp GetAllDeleteHandles fail to get PHOTO_ALL_DELETE_KEY");
168     CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
169         handlesResult, "Mtp GetAllDeleteHandles have no PHOTO_ALL_DELETE_KEY");
170     do {
171         string file_id = GetStringVal(PhotoColumn::MEDIA_ID, resultSet);
172         handlesResult.push_back(file_id);
173     } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
174     return handlesResult;
175 }
176 
StartDelayInfoThread()177 void MediaSyncObserver::StartDelayInfoThread()
178 {
179     CHECK_AND_RETURN_LOG(!isRunningDelay_.load(), "MediaSyncObserver delay thread is already running");
180     isRunningDelay_.store(true);
181     delayThread_ = std::thread([&] { DelayInfoThread(); });
182 }
183 
StopDelayInfoThread()184 void MediaSyncObserver::StopDelayInfoThread()
185 {
186     isRunningDelay_.store(false);
187     cvDelay_.notify_all();
188     if (delayThread_.joinable()) {
189         delayThread_.join();
190     }
191 }
192 
DelayInfoThread()193 void MediaSyncObserver::DelayInfoThread()
194 {
195     while (isRunningDelay_.load()) {
196         DelayInfo delayInfo;
197         {
198             std::unique_lock<std::mutex> lock(mutexDelay_);
199             cvDelay_.wait(lock, [&] { return !delayQueue_.empty() || !isRunningDelay_.load(); });
200             if (!isRunningDelay_.load()) {
201                 std::queue<DelayInfo>().swap(delayQueue_);
202                 MEDIA_INFO_LOG("delay thread is stopped");
203                 break;
204             }
205             delayInfo = delayQueue_.front();
206             delayQueue_.pop();
207         }
208         auto now = std::chrono::steady_clock::now();
209         if (now < delayInfo.tp) {
210             std::this_thread::sleep_until(delayInfo.tp);
211         }
212         SendEventPackets(delayInfo.objectHandle, delayInfo.eventCode);
213         SendEventPacketAlbum(delayInfo.objectHandleAlbum, delayInfo.eventCodeAlbum);
214     }
215 }
216 
AddPhotoHandle(int32_t handle)217 void MediaSyncObserver::AddPhotoHandle(int32_t handle)
218 {
219     CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp AddPhotoHandle fail to get datasharehelper");
220     Uri uri(PAH_QUERY_PHOTO);
221     vector<string> columns;
222     DataShare::DataSharePredicates predicates;
223     shared_ptr<DataShare::DataShareResultSet> resultSet;
224     columns.push_back(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
225     columns.push_back(PhotoColumn::PHOTO_SUBTYPE);
226     predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(handle));
227     predicates.NotEqualTo(PhotoColumn::PHOTO_POSITION, POSITION);
228     CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp AddPhotoHandle dataShareHelper_ is nullptr");
229     resultSet = dataShareHelper_->Query(uri, predicates, columns);
230     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp AddPhotoHandle fail to get handles");
231     CHECK_AND_RETURN_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
232         "Mtp AddPhotoHandle failed to get resultSet");
233     SendEventPackets(handle + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_ADDED_CODE);
234     int32_t ownerAlbumId = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
235     int32_t subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
236     if (subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
237         DelayInfo delayInfo = {
238             .objectHandle = handle + COMMON_MOVING_OFFSET,
239             .eventCode = MTP_EVENT_OBJECT_ADDED_CODE,
240             .objectHandleAlbum = ownerAlbumId,
241             .eventCodeAlbum = MTP_EVENT_OBJECT_INFO_CHANGED_CODE,
242             .tp = std::chrono::steady_clock::now() + std::chrono::milliseconds(DELAY_MS)
243         };
244         {
245             std::lock_guard<std::mutex> lock(mutexDelay_);
246             if (isRunningDelay_.load()) {
247                 delayQueue_.push(delayInfo);
248             }
249         }
250         cvDelay_.notify_all();
251     }
252     auto albumHandles = PtpAlbumHandles::GetInstance();
253     if (!albumHandles->FindHandle(ownerAlbumId)) {
254         albumHandles->AddHandle(ownerAlbumId);
255         SendEventPacketAlbum(ownerAlbumId, MTP_EVENT_OBJECT_ADDED_CODE);
256         SendEventPacketAlbum(ownerAlbumId, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
257         SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
258     }
259 }
260 
GetAddEditPhotoHandles(int32_t handle)261 void MediaSyncObserver::GetAddEditPhotoHandles(int32_t handle)
262 {
263     vector<int32_t> handlesResult;
264     CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr,
265         "Mtp GetAddEditPhotoHandles fail to get datasharehelper");
266     Uri uri(PAH_QUERY_PHOTO);
267     vector<string> columns;
268     DataShare::DataSharePredicates predicates;
269     columns.push_back(PhotoColumn::PHOTO_SUBTYPE);
270     predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(handle));
271     shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
272     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp GetAddEditPhotoHandles fail to get PHOTO_ALL_DELETE_KEY");
273     CHECK_AND_RETURN_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
274         "Mtp GetAddEditPhotoHandles have no PHOTO_ALL_DELETE_KEY");
275 
276     do {
277         int32_t subType = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
278         if (subType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
279             SendEventPackets(handle + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
280         } else if (subType == static_cast<int32_t>(PhotoSubType::DEFAULT)) {
281             SendEventPackets(handle + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
282         }
283     } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
284 }
285 
GetAddEditAlbumHandle(int32_t handle)286 int32_t MediaSyncObserver::GetAddEditAlbumHandle(int32_t handle)
287 {
288     Uri uri(PAH_QUERY_PHOTO);
289     vector<string> columns;
290     DataShare::DataSharePredicates predicates;
291     columns.push_back(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
292     predicates.EqualTo(MediaColumn::MEDIA_ID, to_string(handle));
293     CHECK_AND_RETURN_RET_LOG(dataShareHelper_ != nullptr,
294         ERR_NUM, "Mtp GetAddEditAlbumHandle dataShareHelper_ is nullptr");
295     shared_ptr<DataShare::DataShareResultSet> resultSet = dataShareHelper_->Query(uri, predicates, columns);
296     CHECK_AND_RETURN_RET_LOG(resultSet != nullptr,
297         ERR_NUM, "Mtp GetAddEditAlbumHandle fail to get album id");
298     CHECK_AND_RETURN_RET_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK,
299         ERR_NUM, "Mtp GetAddEditAlbumHandle have no row");
300     int32_t album_id = GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet);
301     return album_id;
302 }
303 
SendPhotoRemoveEvent(std::string & suffixString)304 void MediaSyncObserver::SendPhotoRemoveEvent(std::string &suffixString)
305 {
306     vector<string> allDeletedHandles;
307     vector<int32_t> handles;
308     if (suffixString.empty()) {
309         allDeletedHandles = GetAllDeleteHandles();
310         for (auto deleteHandle : allDeletedHandles) {
311             if (!IsNumber(deleteHandle)) {
312                 MEDIA_ERR_LOG("Mtp SendPhotoRemoveEvent deleteHandle is incorrect ");
313                 continue;
314             }
315             SendEventPackets(atoi(deleteHandle.c_str()) + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
316             SendEventPackets(atoi(deleteHandle.c_str()) + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
317         }
318     } else {
319         CHECK_AND_RETURN_LOG(IsNumber(suffixString), "Mtp SendPhotoRemoveEvent deleteHandle is incorrect ");
320         SendEventPackets(atoi(suffixString.c_str()) + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
321         SendEventPackets(atoi(suffixString.c_str()) + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
322         vector<std::string> allDeleted;
323         allDeletedHandles.push_back(suffixString);
324     }
325     handles = GetHandlesFromPhotosInfoBurstKeys(allDeletedHandles);
326     for (const auto handle : handles) {
327         SendEventPackets(handle + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
328     }
329 }
330 
SendPhotoEvent(ChangeType changeType,string suffixString)331 void MediaSyncObserver::SendPhotoEvent(ChangeType changeType, string suffixString)
332 {
333     if (!suffixString.empty() && !std::isdigit(suffixString[0])) {
334         return;
335     }
336     if (!suffixString.empty() && atoi(suffixString.c_str()) <= 0) {
337         return;
338     }
339     switch (changeType) {
340         case static_cast<int32_t>(NotifyType::NOTIFY_ADD):
341             MEDIA_DEBUG_LOG("MtpMediaLibrary PHOTO ADD");
342             AddPhotoHandle(atoi(suffixString.c_str()));
343             break;
344         case static_cast<int32_t>(NotifyType::NOTIFY_UPDATE):
345             MEDIA_DEBUG_LOG("MtpMediaLibrary PHOTO UPDATE");
346             SendEventPackets(atoi(suffixString.c_str()) + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
347             GetAddEditPhotoHandles(atoi(suffixString.c_str()));
348             break;
349         case static_cast<int32_t>(NotifyType::NOTIFY_REMOVE):
350             MEDIA_DEBUG_LOG("MtpMediaLibrary PHOTO REMOVE");
351             SendPhotoRemoveEvent(suffixString);
352             break;
353         default:
354             break;
355     }
356 }
357 
GetAlbumIdList(std::set<int32_t> & albumIds)358 void MediaSyncObserver::GetAlbumIdList(std::set<int32_t> &albumIds)
359 {
360     CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp GetAlbumIdList dataShareHelper_ is nullptr");
361     DataShare::DataSharePredicates predicates;
362     Uri uri(PAH_QUERY_PHOTO_ALBUM);
363     vector<string> columns;
364     columns.push_back(PhotoAlbumColumns::ALBUM_ID);
365     predicates.IsNotNull(MEDIA_DATA_DB_ALBUM_NAME);
366     predicates.NotEqualTo(MEDIA_DATA_DB_ALBUM_NAME, HIDDEN_ALBUM);
367     predicates.BeginWrap();
368     predicates.NotEqualTo(MEDIA_DATA_DB_IS_LOCAL, IS_LOCAL);
369     predicates.Or();
370     predicates.IsNull(MEDIA_DATA_DB_IS_LOCAL);
371     predicates.EndWrap();
372     auto resultSet = dataShareHelper_->Query(uri, predicates, columns);
373     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp GetAlbumIdList Query fail");
374     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
375         albumIds.insert(GetInt32Val(PhotoAlbumColumns::ALBUM_ID, resultSet));
376     }
377 }
378 
GetOwnerAlbumIdList(std::set<int32_t> & albumIds)379 void MediaSyncObserver::GetOwnerAlbumIdList(std::set<int32_t> &albumIds)
380 {
381     CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp GetOwnerAlbumIdList dataShareHelper_ is nullptr");
382     Uri uri(PAH_QUERY_PHOTO);
383     vector<string> columns;
384     columns.push_back(PhotoColumn::PHOTO_OWNER_ALBUM_ID);
385     DataShare::DataSharePredicates predicates;
386     predicates.NotEqualTo(PhotoColumn::PHOTO_POSITION, POSITION);
387     predicates.EqualTo(MediaColumn::MEDIA_DATE_TRASHED, "0");
388     predicates.EqualTo(MediaColumn::MEDIA_TIME_PENDING, "0");
389     predicates.EqualTo(MediaColumn::MEDIA_HIDDEN, "0");
390     predicates.Distinct();
391     auto resultSet = dataShareHelper_->Query(uri, predicates, columns);
392     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp GetOwnerAlbumIdList Query fail");
393     while (resultSet->GoToNextRow() == NativeRdb::E_OK) {
394         albumIds.insert(GetInt32Val(PhotoColumn::PHOTO_OWNER_ALBUM_ID, resultSet));
395     }
396 }
397 
SendEventToPTP(ChangeType changeType,const std::vector<int32_t> & albumIds)398 void MediaSyncObserver::SendEventToPTP(ChangeType changeType, const std::vector<int32_t> &albumIds)
399 {
400     std::vector<int32_t> removeIds;
401     std::set<int32_t> localAlbumIds;
402     auto albumHandles = PtpAlbumHandles::GetInstance();
403     CHECK_AND_RETURN_LOG(albumHandles != nullptr, "albumHandles is nullptr");
404     switch (changeType) {
405         case static_cast<int32_t>(NotifyType::NOTIFY_ADD):
406         case static_cast<int32_t>(NotifyType::NOTIFY_UPDATE):
407             MEDIA_DEBUG_LOG("MtpMediaLibrary ALBUM ADD OR UPDATE");
408             GetAlbumIdList(localAlbumIds);
409             GetOwnerAlbumIdList(localAlbumIds);
410             albumHandles->UpdateHandle(localAlbumIds, removeIds);
411             for (auto removeId : removeIds) {
412                 albumHandles->RemoveHandle(removeId);
413                 SendEventPacketAlbum(removeId, MTP_EVENT_OBJECT_REMOVED_CODE);
414             }
415             for (auto albumId : albumIds) {
416                 if (localAlbumIds.count(albumId) == 0) {
417                     MEDIA_DEBUG_LOG("MtpMediaLibrary ignore cloud albumId:%{public}d", albumId);
418                     continue;
419                 }
420                 if (!albumHandles->FindHandle(albumId)) {
421                     albumHandles->AddHandle(albumId);
422                     SendEventPacketAlbum(albumId, MTP_EVENT_OBJECT_ADDED_CODE);
423                 }
424                 SendEventPacketAlbum(albumId, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
425             }
426             SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
427             break;
428         case static_cast<int32_t>(NotifyType::NOTIFY_REMOVE):
429             MEDIA_DEBUG_LOG("MtpMediaLibrary ALBUM REMOVE");
430             for (auto albumId : albumIds) {
431                 albumHandles->RemoveHandle(albumId);
432                 SendEventPacketAlbum(albumId, MTP_EVENT_OBJECT_REMOVED_CODE);
433             }
434             SendEventPacketAlbum(PARENT_ID, MTP_EVENT_OBJECT_INFO_CHANGED_CODE);
435             break;
436         default:
437             break;
438     }
439 }
440 
ParseNotifyData(const ChangeInfo & changeInfo,vector<string> & fileIds)441 bool MediaSyncObserver::ParseNotifyData(const ChangeInfo &changeInfo, vector<string> &fileIds)
442 {
443     if (changeInfo.data_ == nullptr || changeInfo.size_ <= 0) {
444         MEDIA_DEBUG_LOG("changeInfo.data_ is null or changeInfo.size_ is invalid");
445         return false;
446     }
447     MEDIA_DEBUG_LOG("changeInfo.size_ is %{public}d.", changeInfo.size_);
448     uint8_t *parcelData = static_cast<uint8_t *>(malloc(changeInfo.size_));
449     CHECK_AND_RETURN_RET_LOG(parcelData != nullptr, false, "parcelData malloc failed");
450     if (memcpy_s(parcelData, changeInfo.size_, changeInfo.data_, changeInfo.size_) != 0) {
451         MEDIA_ERR_LOG("parcelData copy parcel data failed");
452         free(parcelData);
453         return false;
454     }
455     shared_ptr<MessageParcel> parcel = make_shared<MessageParcel>();
456     // parcel析构函数中会free掉parcelData,成功调用ParseFrom后不可进行free(parcelData)
457     if (!parcel->ParseFrom(reinterpret_cast<uintptr_t>(parcelData), changeInfo.size_)) {
458         MEDIA_ERR_LOG("Parse parcelData failed");
459         free(parcelData);
460         return false;
461     }
462     uint32_t len = 0;
463     CHECK_AND_RETURN_RET_LOG(!(!parcel->ReadUint32(len)), false, "Failed to read sub uri list length");
464     MEDIA_DEBUG_LOG("read sub uri list length: %{public}u .", len);
465     CHECK_AND_RETURN_RET_LOG(len <= MAX_PARCEL_LEN_LIMIT, false, "len length exceed the limit.");
466     for (uint32_t i = 0; i < len; i++) {
467         string subUri = parcel->ReadString();
468         CHECK_AND_RETURN_RET_LOG(!subUri.empty(), false, "Failed to read sub uri");
469         MEDIA_DEBUG_LOG("notify data subUri string %{public}s.", subUri.c_str());
470         MediaFileUri fileUri(subUri);
471         string fileId = fileUri.GetFileId();
472         if (!IsNumber(fileId)) {
473             MEDIA_ERR_LOG("Failed to read sub uri fileId");
474             continue;
475         }
476         fileIds.push_back(fileId);
477     }
478     return true;
479 }
480 
HandleMovePhotoEvent(const ChangeInfo & changeInfo)481 void MediaSyncObserver::HandleMovePhotoEvent(const ChangeInfo &changeInfo)
482 {
483     if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_ADD)) {
484         return;
485     }
486     vector<string> fileIds;
487     bool errCode = ParseNotifyData(changeInfo, fileIds);
488     if (!errCode || fileIds.empty()) {
489         MEDIA_DEBUG_LOG("parse changInfo data failed or have no fileId");
490         return;
491     }
492     Uri uri(PAH_QUERY_PHOTO);
493     vector<string> columns;
494     DataShare::DataSharePredicates predicates;
495     shared_ptr<DataShare::DataShareResultSet> resultSet;
496     columns.push_back(MediaColumn::MEDIA_ID);
497     columns.push_back(PhotoColumn::PHOTO_SUBTYPE);
498     predicates.In(MediaColumn::MEDIA_ID, fileIds);
499     predicates.NotEqualTo(PhotoColumn::PHOTO_POSITION, POSITION);
500     CHECK_AND_RETURN_LOG(dataShareHelper_ != nullptr, "Mtp dataShareHelper_ is nullptr");
501     resultSet = dataShareHelper_->Query(uri, predicates, columns);
502     CHECK_AND_RETURN_LOG(resultSet != nullptr, "Mtp get handles failed");
503     CHECK_AND_RETURN_LOG(resultSet->GoToFirstRow() == NativeRdb::E_OK, "Mtp get resultSet failed");
504     do {
505         int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
506         int32_t subtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
507         SendEventPackets(fileId + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
508         SendEventPackets(fileId + COMMON_PHOTOS_OFFSET, MTP_EVENT_OBJECT_ADDED_CODE);
509         if (subtype == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) {
510             SendEventPackets(fileId + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_REMOVED_CODE);
511             SendEventPackets(fileId + COMMON_MOVING_OFFSET, MTP_EVENT_OBJECT_ADDED_CODE);
512         }
513     } while (resultSet->GoToNextRow() == NativeRdb::E_OK);
514 }
515 
OnChangeEx(const ChangeInfo & changeInfo)516 void MediaSyncObserver::OnChangeEx(const ChangeInfo &changeInfo)
517 {
518     std::vector<int32_t> albumIds;
519     std::string PhotoPrefix = PhotoColumn::PHOTO_URI_PREFIX;
520     std::string PhotoAlbumPrefix = PhotoAlbumColumns::ALBUM_URI_PREFIX;
521     MEDIA_DEBUG_LOG("MtpMediaLibrary changeType [%{public}d]", changeInfo.changeType_);
522     for (const auto& it : changeInfo.uris_) {
523         std::string uri = it.ToString();
524         MediaFileUri fileUri(uri);
525         MEDIA_DEBUG_LOG("MtpMediaLibrary uris [%{public}s]", uri.c_str());
526         if (startsWith(uri, PhotoPrefix)) {
527             std::string fileId = fileUri.GetFileId();
528             if (fileId.compare(INVALID_FILE_ID) == 0) {
529                 fileId = "";
530             }
531             if (fileId.empty() && changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_REMOVE)) {
532                 MEDIA_DEBUG_LOG("MtpMediaLibrary suffixString is empty");
533                 continue;
534             }
535             MEDIA_DEBUG_LOG("MtpMediaLibrary suffixString [%{public}s]", fileId.c_str());
536             SendPhotoEvent(changeInfo.changeType_, fileId);
537         } else if (startsWith(uri, PhotoAlbumPrefix)) {
538             std::string albumId = fileUri.GetFileId();
539             MEDIA_DEBUG_LOG("MtpMediaLibrary suffixString [%{public}s]", albumId.c_str());
540             if (!IsNumber(albumId)) {
541                 continue;
542             }
543             int32_t albumIdNum = atoi(albumId.c_str());
544             if (albumIdNum <= RESERVE_ALBUM) {
545                 continue;
546             }
547             albumIds.push_back(albumIdNum);
548         }
549     }
550 
551     if (!albumIds.empty()) {
552         HandleMovePhotoEvent(changeInfo);
553         SendEventToPTP(changeInfo.changeType_, albumIds);
554     }
555 }
556 
OnChange(const ChangeInfo & changeInfo)557 void MediaSyncObserver::OnChange(const ChangeInfo &changeInfo)
558 {
559     CHECK_AND_RETURN_LOG(isRunning_.load(), "MediaSyncObserver::OnChange thread is not running");
560     {
561         std::lock_guard<std::mutex> lock(mutex_);
562         ChangeInfo changeInfoCopy = changeInfo;
563         if (changeInfo.data_ != nullptr && changeInfo.size_ > 0) {
564             changeInfoCopy.data_ = malloc(changeInfo.size_);
565             CHECK_AND_RETURN_LOG(changeInfoCopy.data_ != nullptr, "changeInfoCopy.data_ is nullptr.");
566             if (memcpy_s(const_cast<void*>(changeInfoCopy.data_),
567                 changeInfo.size_, changeInfo.data_, changeInfo.size_) != 0) {
568                 MEDIA_ERR_LOG("changeInfoCopy copy data failed");
569                 free(const_cast<void*>(changeInfoCopy.data_));
570                 changeInfoCopy.data_ = nullptr;
571                 return;
572             }
573         }
574         changeInfoQueue_.push(changeInfoCopy);
575     }
576     cv_.notify_one();
577 }
578 
StartNotifyThread()579 void MediaSyncObserver::StartNotifyThread()
580 {
581     MEDIA_INFO_LOG("start notify thread");
582     CHECK_AND_RETURN_LOG(!isRunning_.load(), "MediaSyncObserver notify thread is already running");
583     isRunning_.store(true);
584     notifythread_ = std::thread([this] {this->ChangeNotifyThread();});
585     StartDelayInfoThread();
586 }
587 
StopNotifyThread()588 void MediaSyncObserver::StopNotifyThread()
589 {
590     MEDIA_INFO_LOG("stop notify thread");
591     StopDelayInfoThread();
592     isRunning_.store(false);
593     cv_.notify_all();
594     {
595         std::lock_guard<std::mutex> lock(mutex_);
596         while (!changeInfoQueue_.empty()) {
597             ChangeInfo changeInfo = changeInfoQueue_.front();
598             changeInfoQueue_.pop();
599             if (changeInfo.data_ != nullptr) {
600                 free(const_cast<void*>(changeInfo.data_));
601                 changeInfo.data_ = nullptr;
602             }
603         }
604     }
605     if (notifythread_.joinable()) {
606         notifythread_.join();
607     }
608 }
609 
ChangeNotifyThread()610 void MediaSyncObserver::ChangeNotifyThread()
611 {
612     while (isRunning_.load()) {
613         ChangeInfo changeInfo;
614         {
615             std::unique_lock<std::mutex> lock(mutex_);
616             cv_.wait(lock, [this] { return !changeInfoQueue_.empty() || !isRunning_.load(); });
617             if (!isRunning_.load()) {
618                 MEDIA_INFO_LOG("notify thread is stopped");
619                 break;
620             }
621             changeInfo = changeInfoQueue_.front();
622             changeInfoQueue_.pop();
623         }
624         OnChangeEx(changeInfo);
625         if (changeInfo.data_ != nullptr) {
626             free(const_cast<void*>(changeInfo.data_));
627             changeInfo.data_ = nullptr;
628         }
629     }
630 }
631 } // namespace Media
632 } // namespace OHOS