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