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
16 #include "thumbnail_manager.h"
17
18 #include <memory>
19 #include <mutex>
20 #include <sys/mman.h>
21 #include <sys/stat.h>
22 #include <uuid/uuid.h>
23
24 #include "ashmem.h"
25 #include "image_source.h"
26 #include "image_type.h"
27 #include "js_native_api.h"
28 #include "media_file_uri.h"
29 #include "medialibrary_errno.h"
30 #include "medialibrary_napi_log.h"
31 #include "medialibrary_napi_utils.h"
32 #include "medialibrary_tracer.h"
33 #include "pixel_map.h"
34 #include "pixel_map_napi.h"
35 #include "post_proc.h"
36 #include "securec.h"
37 #include "string_ex.h"
38 #include "thumbnail_const.h"
39 #include "unique_fd.h"
40 #include "userfile_manager_types.h"
41 #include "uv.h"
42 #include "userfile_client.h"
43
44 #ifdef IMAGE_PURGEABLE_PIXELMAP
45 #include "purgeable_pixelmap_builder.h"
46 #endif
47
48 using namespace std;
49 const int UUID_STR_LENGTH = 37;
50
51 namespace OHOS {
52 namespace Media {
53 shared_ptr<ThumbnailManager> ThumbnailManager::instance_ = nullptr;
54 mutex ThumbnailManager::mutex_;
55 bool ThumbnailManager::init_ = false;
56 static constexpr int32_t DEFAULT_FD = -1;
57
ThumbnailRequest(const RequestPhotoParams ¶ms, napi_env env, napi_ref callback)58 ThumbnailRequest::ThumbnailRequest(const RequestPhotoParams ¶ms, napi_env env,
59 napi_ref callback) : callback_(env, callback), requestPhotoType(params.type), uri_(params.uri),
60 path_(params.path), requestSize_(params.size)
61 {
62 }
63
~ThumbnailRequest()64 ThumbnailRequest::~ThumbnailRequest()
65 {
66 }
67
ReleaseCallbackRef()68 void ThumbnailRequest::ReleaseCallbackRef()
69 {
70 std::lock_guard<std::mutex> lock(mutex_);
71 if (callback_.callBackRef_) {
72 napi_delete_reference(callback_.env_, callback_.callBackRef_);
73 callback_.callBackRef_ = nullptr;
74 }
75 }
76
UpdateStatus(ThumbnailStatus status)77 bool ThumbnailRequest::UpdateStatus(ThumbnailStatus status)
78 {
79 std::lock_guard<std::mutex> lock(mutex_);
80 if (status <= status_) {
81 return false;
82 }
83 status_ = status;
84 return true;
85 }
86
GetStatus()87 ThumbnailStatus ThumbnailRequest::GetStatus()
88 {
89 std::lock_guard<std::mutex> lock(mutex_);
90 return status_;
91 }
92
NeedContinue()93 bool ThumbnailRequest::NeedContinue()
94 {
95 return GetStatus() < ThumbnailStatus::THUMB_REMOVE;
96 }
97
IsPhotoSizeThumb(const Size &size)98 static bool IsPhotoSizeThumb(const Size &size)
99 {
100 return ((size.width >= DEFAULT_THUMB_SIZE || size.height >= DEFAULT_THUMB_SIZE) ||
101 (size.width == DEFAULT_MTH_SIZE || size.height == DEFAULT_MTH_SIZE));
102 }
103
NeedFastThumb(const Size &size, RequestPhotoType type)104 static bool NeedFastThumb(const Size &size, RequestPhotoType type)
105 {
106 return IsPhotoSizeThumb(size) && (type != RequestPhotoType::REQUEST_QUALITY_THUMBNAIL);
107 }
108
NeedQualityThumb(const Size &size, RequestPhotoType type)109 static bool NeedQualityThumb(const Size &size, RequestPhotoType type)
110 {
111 return IsPhotoSizeThumb(size) && (type != RequestPhotoType::REQUEST_FAST_THUMBNAIL);
112 }
113
MMapFdPtr(int32_t fd, bool isNeedRelease)114 MMapFdPtr::MMapFdPtr(int32_t fd, bool isNeedRelease)
115 {
116 if (fd < 0) {
117 NAPI_ERR_LOG("Fd is invalid: %{public}d", fd);
118 return;
119 }
120
121 struct stat st;
122 if (fstat(fd, &st) == -1) {
123 NAPI_ERR_LOG("fstat error, errno:%{public}d", errno);
124 return;
125 }
126 size_ = st.st_size;
127
128 // mmap ptr from fd
129 fdPtr_ = mmap(nullptr, size_, PROT_READ, MAP_SHARED, fd, 0);
130 if (fdPtr_ == MAP_FAILED || fdPtr_ == nullptr) {
131 NAPI_ERR_LOG("mmap uniqueFd failed, errno = %{public}d", errno);
132 return;
133 }
134
135 isValid_ = true;
136 isNeedRelease_ = isNeedRelease;
137 }
138
~MMapFdPtr()139 MMapFdPtr::~MMapFdPtr()
140 {
141 // munmap ptr from fd
142 if (isNeedRelease_) {
143 munmap(fdPtr_, size_);
144 }
145 }
146
GetFdPtr()147 void* MMapFdPtr::GetFdPtr()
148 {
149 return fdPtr_;
150 }
151
GetFdSize()152 off_t MMapFdPtr::GetFdSize()
153 {
154 return size_;
155 }
156
IsValid()157 bool MMapFdPtr::IsValid()
158 {
159 return isValid_;
160 }
161
GenerateRequestId()162 static string GenerateRequestId()
163 {
164 uuid_t uuid;
165 uuid_generate(uuid);
166 char str[UUID_STR_LENGTH] = {};
167 uuid_unparse(uuid, str);
168 return str;
169 }
170
GetInstance()171 shared_ptr<ThumbnailManager> ThumbnailManager::GetInstance()
172 {
173 if (instance_ == nullptr) {
174 lock_guard<mutex> lock(mutex_);
175 if (instance_ == nullptr) {
176 instance_ = shared_ptr<ThumbnailManager>(new ThumbnailManager());
177 }
178 }
179
180 return instance_;
181 }
182
Init()183 void ThumbnailManager::Init()
184 {
185 std::lock_guard<std::mutex> lock(mutex_);
186 if (init_) {
187 return;
188 }
189 init_ = true;
190 isThreadRunning_ = true;
191 for (auto i = 0; i < THREAD_NUM; i++) {
192 threads_.emplace_back(
193 std::thread([this, num = i]() { this->ImageWorker(num); })
194 );
195 threads_[i].detach();
196 }
197 return;
198 }
199
AddPhotoRequest(const RequestPhotoParams ¶ms, napi_env env, napi_ref callback)200 string ThumbnailManager::AddPhotoRequest(const RequestPhotoParams ¶ms, napi_env env, napi_ref callback)
201 {
202 shared_ptr<ThumbnailRequest> request = make_shared<ThumbnailRequest>(params, env, callback);
203 string requestId = GenerateRequestId();
204 request->SetUUID(requestId);
205 if (!thumbRequest_.Insert(requestId, request)) {
206 return "";
207 }
208 // judge from request option
209 if (NeedFastThumb(params.size, params.type)) {
210 AddFastPhotoRequest(request);
211 } else {
212 AddQualityPhotoRequest(request);
213 }
214 return requestId;
215 }
216
RemovePhotoRequest(const string &requestId)217 void ThumbnailManager::RemovePhotoRequest(const string &requestId)
218 {
219 RequestSharedPtr ptr;
220 if (thumbRequest_.Find(requestId, ptr)) {
221 if (ptr == nullptr) {
222 return;
223 }
224 // do not need delete from queue, just update remove status.
225 ptr->UpdateStatus(ThumbnailStatus::THUMB_REMOVE);
226 ptr->ReleaseCallbackRef();
227 }
228 thumbRequest_.Erase(requestId);
229 }
230
~ThumbnailManager()231 ThumbnailManager::~ThumbnailManager()
232 {
233 isThreadRunning_ = false;
234 queueCv_.notify_all();
235 for (auto &thread : threads_) {
236 if (thread.joinable()) {
237 thread.join();
238 }
239 }
240 }
241
SetThreadName(const string &threadName, int num)242 void SetThreadName(const string &threadName, int num)
243 {
244 string name = threadName;
245 name.append(to_string(num));
246 pthread_setname_np(pthread_self(), name.c_str());
247 }
248
AddFastPhotoRequest(const RequestSharedPtr &request)249 void ThumbnailManager::AddFastPhotoRequest(const RequestSharedPtr &request)
250 {
251 request->UpdateStatus(ThumbnailStatus::THUMB_FAST);
252 fastQueue_.Push(request);
253 queueCv_.notify_one();
254 }
255
AddQualityPhotoRequest(const RequestSharedPtr &request)256 void ThumbnailManager::AddQualityPhotoRequest(const RequestSharedPtr &request)
257 {
258 request->UpdateStatus(ThumbnailStatus::THUMB_QUALITY);
259 qualityQueue_.Push(request);
260 queueCv_.notify_one();
261 }
262
GetFastThumbNewSize(const Size &size, Size &newSize)263 static bool GetFastThumbNewSize(const Size &size, Size &newSize)
264 {
265 // if thumbnail size is YEAR SIZE, do not need to request fast thumb
266 // if thumbnail size is MTH SIZE, return YEAR SIZE
267 // if thumbnail size is THUMB SIZE, return MTH SIZE
268 // else return THUMB SIZE
269 if (size.width == DEFAULT_YEAR_SIZE && size.height == DEFAULT_YEAR_SIZE) {
270 newSize.height = DEFAULT_YEAR_SIZE;
271 newSize.width = DEFAULT_YEAR_SIZE;
272 return false;
273 } else if (size.width == DEFAULT_MTH_SIZE && size.height == DEFAULT_MTH_SIZE) {
274 newSize.height = DEFAULT_YEAR_SIZE;
275 newSize.width = DEFAULT_YEAR_SIZE;
276 return true;
277 } else if (size.width <= DEFAULT_THUMB_SIZE && size.height <= DEFAULT_THUMB_SIZE) {
278 newSize.height = DEFAULT_MTH_SIZE;
279 newSize.width = DEFAULT_MTH_SIZE;
280 return true;
281 } else {
282 newSize.height = DEFAULT_THUMB_SIZE;
283 newSize.width = DEFAULT_THUMB_SIZE;
284 return true;
285 }
286 }
287
OpenThumbnail(const string &path, ThumbnailType type)288 static int OpenThumbnail(const string &path, ThumbnailType type)
289 {
290 if (!path.empty()) {
291 string sandboxPath = GetSandboxPath(path, type);
292 int fd = -1;
293 if (!sandboxPath.empty()) {
294 fd = open(sandboxPath.c_str(), O_RDONLY);
295 }
296 if (fd > 0) {
297 return fd;
298 }
299 }
300 return E_ERR;
301 }
302
OpenKeyFrameThumbnail(const string &path, const int32_t &beginStamp, const int32_t &type)303 static int OpenKeyFrameThumbnail(const string &path, const int32_t &beginStamp, const int32_t &type)
304 {
305 if (!path.empty()) {
306 string sandboxPath = GetKeyFrameSandboxPath(path, beginStamp, type);
307 int fd = -1;
308 if (!sandboxPath.empty()) {
309 fd = open(sandboxPath.c_str(), O_RDONLY);
310 }
311 if (fd > 0) {
312 return fd;
313 }
314 NAPI_ERR_LOG("OpenKeyFrameThumbnail failed, fd: %{public}d", fd);
315 }
316 return E_ERR;
317 }
318
IfSizeEqualsRatio(const Size &imageSize, const Size &targetSize)319 static bool IfSizeEqualsRatio(const Size &imageSize, const Size &targetSize)
320 {
321 if (imageSize.height <= 0 || targetSize.height <= 0) {
322 return false;
323 }
324
325 float imageSizeScale = static_cast<float>(imageSize.width) / static_cast<float>(imageSize.height);
326 float targetSizeScale = static_cast<float>(targetSize.width) / static_cast<float>(targetSize.height);
327 if (imageSizeScale - targetSizeScale > FLOAT_EPSILON || targetSizeScale - imageSizeScale > FLOAT_EPSILON) {
328 return false;
329 } else {
330 return true;
331 }
332 }
333
CreateThumbnailByAshmem(UniqueFd &uniqueFd, const Size &size)334 static PixelMapPtr CreateThumbnailByAshmem(UniqueFd &uniqueFd, const Size &size)
335 {
336 MediaLibraryTracer tracer;
337 tracer.Start("CreateThumbnailByAshmem");
338
339 Media::InitializationOptions option = {
340 .size = size,
341 };
342 PixelMapPtr pixel = Media::PixelMap::Create(option);
343 if (pixel == nullptr) {
344 NAPI_ERR_LOG("Can not create pixel");
345 return nullptr;
346 }
347
348 UniqueFd dupFd = UniqueFd(dup(uniqueFd.Get()));
349 MMapFdPtr mmapFd(dupFd.Get(), false);
350 if (!mmapFd.IsValid()) {
351 NAPI_ERR_LOG("Can not mmap by fd");
352 return nullptr;
353 }
354 auto memSize = static_cast<int32_t>(mmapFd.GetFdSize());
355
356 void* fdPtr = new int32_t();
357 *static_cast<int32_t*>(fdPtr) = dupFd.Release();
358 pixel->SetPixelsAddr(mmapFd.GetFdPtr(), fdPtr, memSize, Media::AllocatorType::SHARE_MEM_ALLOC, nullptr);
359 return pixel;
360 }
361
DecodeThumbnail(const UniqueFd &uniqueFd, const Size &size)362 static PixelMapPtr DecodeThumbnail(const UniqueFd &uniqueFd, const Size &size)
363 {
364 MediaLibraryTracer tracer;
365 tracer.Start("ImageSource::CreateImageSource");
366 SourceOptions opts;
367 uint32_t err = 0;
368 unique_ptr<ImageSource> imageSource = ImageSource::CreateImageSource(uniqueFd.Get(), opts, err);
369 if (imageSource == nullptr) {
370 NAPI_ERR_LOG("CreateImageSource err %{public}d", err);
371 return nullptr;
372 }
373
374 ImageInfo imageInfo;
375 err = imageSource->GetImageInfo(0, imageInfo);
376 if (err != E_OK) {
377 NAPI_ERR_LOG("GetImageInfo err %{public}d", err);
378 return nullptr;
379 }
380
381 bool isEqualsRatio = IfSizeEqualsRatio(imageInfo.size, size);
382 DecodeOptions decodeOpts;
383 decodeOpts.desiredSize = isEqualsRatio ? size : imageInfo.size;
384 unique_ptr<PixelMap> pixelMap = imageSource->CreatePixelMap(decodeOpts, err);
385 if (pixelMap == nullptr) {
386 NAPI_ERR_LOG("CreatePixelMap err %{public}d", err);
387 return nullptr;
388 }
389
390 PostProc postProc;
391 if (size.width != DEFAULT_ORIGINAL && !isEqualsRatio && !postProc.CenterScale(size, *pixelMap)) {
392 NAPI_ERR_LOG("CenterScale failed, size: %{public}d * %{public}d, imageInfo size: %{public}d * %{public}d",
393 size.width, size.height, imageInfo.size.width, imageInfo.size.height);
394 return nullptr;
395 }
396
397 // Make the ashmem of pixelmap to be purgeable after the operation on ashmem.
398 // And then make the pixelmap subject to PurgeableManager's control.
399 #ifdef IMAGE_PURGEABLE_PIXELMAP
400 PurgeableBuilder::MakePixelMapToBePurgeable(pixelMap, imageSource, decodeOpts, size);
401 #endif
402 return pixelMap;
403 }
404
GetPixelMapFromServer(const string &uriStr, const Size &size, const string &path)405 static int32_t GetPixelMapFromServer(const string &uriStr, const Size &size, const string &path)
406 {
407 string openUriStr = uriStr + "?" + MEDIA_OPERN_KEYWORD + "=" + MEDIA_DATA_DB_THUMBNAIL + "&" +
408 MEDIA_DATA_DB_WIDTH + "=" + to_string(size.width) + "&" + MEDIA_DATA_DB_HEIGHT + "=" +
409 to_string(size.height);
410 if (IsAsciiString(path)) {
411 openUriStr += "&" + THUMBNAIL_PATH + "=" + path;
412 }
413 Uri openUri(openUriStr);
414 return UserFileClient::OpenFile(openUri, "R");
415 }
416
GetKeyFramePixelMapFromServer(const string &uriStr, const string &path, const int32_t &beginStamp, const int32_t &type)417 static int32_t GetKeyFramePixelMapFromServer(const string &uriStr, const string &path,
418 const int32_t &beginStamp, const int32_t &type)
419 {
420 string openUriStr = uriStr + "?" + MEDIA_OPERN_KEYWORD + "=" + MEDIA_DATA_DB_KEY_FRAME + "&" +
421 MEDIA_DATA_DB_BEGIN_STAMP + "=" + to_string(beginStamp) + "&" + MEDIA_DATA_DB_TYPE + "=" + to_string(type);
422 if (IsAsciiString(path)) {
423 openUriStr += "&" + THUMBNAIL_PATH + "=" + path;
424 }
425 Uri openUri(openUriStr);
426 return UserFileClient::OpenFile(openUri, "R");
427 }
428
QueryThumbnail(const string &uriStr, const Size &size, const string &path)429 unique_ptr<PixelMap> ThumbnailManager::QueryThumbnail(const string &uriStr, const Size &size, const string &path)
430 {
431 MediaLibraryTracer tracer;
432 tracer.Start("QueryThumbnail uri:" + uriStr);
433 tracer.Start("DataShare::OpenFile");
434 ThumbnailType thumbType = GetThumbType(size.width, size.height);
435 if (MediaFileUri::GetMediaTypeFromUri(uriStr) == MediaType::MEDIA_TYPE_AUDIO &&
436 (thumbType == ThumbnailType::MTH || thumbType == ThumbnailType::YEAR)) {
437 thumbType = ThumbnailType::THUMB;
438 }
439 UniqueFd uniqueFd(OpenThumbnail(path, thumbType));
440 if (uniqueFd.Get() == E_ERR) {
441 uniqueFd = UniqueFd(GetPixelMapFromServer(uriStr, size, path));
442 if (uniqueFd.Get() < 0) {
443 NAPI_ERR_LOG("queryThumb is null, errCode is %{public}d", uniqueFd.Get());
444 return nullptr;
445 }
446 return DecodeThumbnail(uniqueFd, size);
447 }
448 tracer.Finish();
449 if (thumbType == ThumbnailType::MTH || thumbType == ThumbnailType::YEAR) {
450 return CreateThumbnailByAshmem(uniqueFd, size);
451 } else {
452 return DecodeThumbnail(uniqueFd, size);
453 }
454 }
455
QueryKeyFrameThumbnail(const string &uriStr, const int &beginStamp, const int &type, const string &path)456 unique_ptr<PixelMap> ThumbnailManager::QueryKeyFrameThumbnail(const string &uriStr, const int &beginStamp,
457 const int &type, const string &path)
458 {
459 MediaLibraryTracer tracer;
460 tracer.Start("QueryKeyFrameThumbnail uri:" + uriStr);
461
462 UniqueFd uniqueFd(OpenKeyFrameThumbnail(path, beginStamp, type));
463 Size size;
464 size.width = DEFAULT_THUMB_SIZE;
465 size.height = DEFAULT_THUMB_SIZE;
466 if (uniqueFd.Get() == E_ERR) {
467 uniqueFd = UniqueFd(GetKeyFramePixelMapFromServer(uriStr, path, beginStamp, type));
468 if (uniqueFd.Get() < 0) {
469 NAPI_ERR_LOG("queryKeyFrameThumb is null, errCode is %{public}d", uniqueFd.Get());
470 return nullptr;
471 }
472 }
473 tracer.Finish();
474 return DecodeThumbnail(uniqueFd, size);
475 }
476
DeleteRequestIdFromMap(const string &requestId)477 void ThumbnailManager::DeleteRequestIdFromMap(const string &requestId)
478 {
479 thumbRequest_.Erase(requestId);
480 }
481
RequestFastImage(const RequestSharedPtr &request)482 bool ThumbnailManager::RequestFastImage(const RequestSharedPtr &request)
483 {
484 MediaLibraryTracer tracer;
485 tracer.Start("ThumbnailManager::RequestFastImage");
486 request->SetFd(DEFAULT_FD);
487 Size fastSize;
488 if (!GetFastThumbNewSize(request->GetRequestSize(), fastSize)) {
489 return false;
490 }
491 UniqueFd uniqueFd(OpenThumbnail(request->GetPath(), GetThumbType(fastSize.width, fastSize.height)));
492 if (uniqueFd.Get() < 0) {
493 // Can not get fast image in sandbox
494 int32_t outFd = GetPixelMapFromServer(request->GetUri(), request->GetRequestSize(), request->GetPath());
495 if (outFd <= 0) {
496 NAPI_ERR_LOG("Can not get thumbnail from server, uri=%{private}s", request->GetUri().c_str());
497 request->error = E_FAIL;
498 return false;
499 }
500 request->SetFd(outFd);
501 }
502
503 ThumbnailType thumbType = GetThumbType(fastSize.width, fastSize.height);
504 PixelMapPtr pixelMap = nullptr;
505 if (request->GetFd().Get() == DEFAULT_FD &&
506 (thumbType == ThumbnailType::MTH || thumbType == ThumbnailType::YEAR)) {
507 pixelMap = CreateThumbnailByAshmem(uniqueFd, fastSize);
508 } else {
509 pixelMap = DecodeThumbnail(request->GetFd(), fastSize);
510 }
511 if (pixelMap == nullptr) {
512 request->error = E_FAIL;
513 return false;
514 }
515 request->SetFastPixelMap(move(pixelMap));
516 return true;
517 }
518
DealWithFastRequest(const RequestSharedPtr &request)519 void ThumbnailManager::DealWithFastRequest(const RequestSharedPtr &request)
520 {
521 MediaLibraryTracer tracer;
522 tracer.Start("ThumbnailManager::DealWithFastRequest");
523
524 if (request == nullptr) {
525 return;
526 }
527
528 if (!RequestFastImage(request) && request->error != E_FAIL) {
529 // when local pixelmap not exit, must add QualityThread
530 AddQualityPhotoRequest(request);
531 return;
532 }
533
534 // callback
535 NotifyImage(request);
536 }
537
DealWithQualityRequest(const RequestSharedPtr &request)538 void ThumbnailManager::DealWithQualityRequest(const RequestSharedPtr &request)
539 {
540 MediaLibraryTracer tracer;
541 tracer.Start("ThumbnailManager::DealWithQualityRequest");
542
543 unique_ptr<PixelMap> pixelMapPtr = nullptr;
544 if (request->GetFd().Get() > 0) {
545 pixelMapPtr = DecodeThumbnail(request->GetFd(), request->GetRequestSize());
546 } else {
547 pixelMapPtr = QueryThumbnail(request->GetUri(), request->GetRequestSize(), request->GetPath());
548 }
549
550 if (pixelMapPtr == nullptr) {
551 NAPI_ERR_LOG("Can not get pixelMap");
552 request->error = E_FAIL;
553 }
554 request->SetPixelMap(move(pixelMapPtr));
555
556 // callback
557 NotifyImage(request);
558 }
559
ImageWorker(int num)560 void ThumbnailManager::ImageWorker(int num)
561 {
562 SetThreadName("ImageWorker", num);
563 while (true) {
564 if (!isThreadRunning_) {
565 return;
566 }
567 if (!fastQueue_.Empty()) {
568 RequestSharedPtr request;
569 if (fastQueue_.Pop(request) && request->NeedContinue()) {
570 DealWithFastRequest(request);
571 }
572 } else if (!qualityQueue_.Empty()) {
573 RequestSharedPtr request;
574 if (qualityQueue_.Pop(request) && request->NeedContinue()) {
575 DealWithQualityRequest(request);
576 }
577 } else {
578 std::unique_lock<std::mutex> lock(queueLock_);
579 queueCv_.wait(lock, [this]() {
580 return !isThreadRunning_ || !(qualityQueue_.Empty() && fastQueue_.Empty());
581 });
582 }
583 }
584 }
585
HandlePixelCallback(const RequestSharedPtr &request)586 static void HandlePixelCallback(const RequestSharedPtr &request)
587 {
588 napi_env env = request->callback_.env_;
589 napi_value jsCallback = nullptr;
590 napi_status status = napi_get_reference_value(env, request->callback_.callBackRef_, &jsCallback);
591 if (status != napi_ok) {
592 NAPI_ERR_LOG("Create reference fail, status: %{public}d", status);
593 return;
594 }
595
596 napi_value retVal = nullptr;
597 napi_value result[ARGS_TWO];
598 if (request->GetStatus() == ThumbnailStatus::THUMB_REMOVE) {
599 return;
600 }
601
602 if (request->error == E_FAIL) {
603 int32_t errorNum = MediaLibraryNapiUtils::TransErrorCode("requestPhoto", request->error);
604 MediaLibraryNapiUtils::CreateNapiErrorObject(env, result[PARAM0], errorNum,
605 "Failed to request Photo");
606 } else {
607 result[PARAM0] = nullptr;
608 }
609 if (request->GetStatus() == ThumbnailStatus::THUMB_FAST) {
610 result[PARAM1] = Media::PixelMapNapi::CreatePixelMap(env,
611 shared_ptr<PixelMap>(request->GetFastPixelMap()));
612 } else {
613 result[PARAM1] = Media::PixelMapNapi::CreatePixelMap(env,
614 shared_ptr<PixelMap>(request->GetPixelMap()));
615 }
616
617 status = napi_call_function(env, nullptr, jsCallback, ARGS_TWO, result, &retVal);
618 if (status != napi_ok) {
619 NAPI_ERR_LOG("CallJs napi_call_function fail, status: %{public}d", status);
620 return;
621 }
622 }
623
UvJsExecute(uv_work_t *work)624 static void UvJsExecute(uv_work_t *work)
625 {
626 // js thread
627 if (work == nullptr) {
628 return;
629 }
630
631 ThumnailUv *uvMsg = reinterpret_cast<ThumnailUv *>(work->data);
632 if (uvMsg == nullptr) {
633 delete work;
634 return;
635 }
636 if (uvMsg->request_ == nullptr) {
637 delete uvMsg;
638 delete work;
639 return;
640 }
641 do {
642 napi_env env = uvMsg->request_->callback_.env_;
643 if (!uvMsg->request_->NeedContinue()) {
644 break;
645 }
646 NapiScopeHandler scopeHandler(env);
647 if (!scopeHandler.IsValid()) {
648 break;
649 }
650 HandlePixelCallback(uvMsg->request_);
651 } while (0);
652 if (uvMsg->manager_ == nullptr) {
653 delete uvMsg;
654 delete work;
655 return;
656 }
657 if (uvMsg->request_->GetStatus() == ThumbnailStatus::THUMB_FAST &&
658 NeedQualityThumb(uvMsg->request_->GetRequestSize(), uvMsg->request_->requestPhotoType)) {
659 uvMsg->manager_->AddQualityPhotoRequest(uvMsg->request_);
660 } else {
661 uvMsg->manager_->DeleteRequestIdFromMap(uvMsg->request_->GetUUID());
662 uvMsg->request_->ReleaseCallbackRef();
663 }
664
665 delete uvMsg;
666 delete work;
667 }
668
NotifyImage(const RequestSharedPtr &request)669 void ThumbnailManager::NotifyImage(const RequestSharedPtr &request)
670 {
671 MediaLibraryTracer tracer;
672 tracer.Start("ThumbnailManager::NotifyImage");
673
674 if (!request->NeedContinue()) {
675 DeleteRequestIdFromMap(request->GetUUID());
676 return;
677 }
678
679 uv_loop_s *loop = nullptr;
680 napi_get_uv_event_loop(request->callback_.env_, &loop);
681 if (loop == nullptr) {
682 DeleteRequestIdFromMap(request->GetUUID());
683 return;
684 }
685
686 uv_work_t *work = new (nothrow) uv_work_t;
687 if (work == nullptr) {
688 DeleteRequestIdFromMap(request->GetUUID());
689 return;
690 }
691
692 ThumnailUv *msg = new (nothrow) ThumnailUv(request, this);
693 if (msg == nullptr) {
694 delete work;
695 DeleteRequestIdFromMap(request->GetUUID());
696 return;
697 }
698
699 work->data = reinterpret_cast<void *>(msg);
700 int ret = uv_queue_work(loop, work, [](uv_work_t *w) {}, [](uv_work_t *w, int s) {
701 UvJsExecute(w);
702 });
703 if (ret != 0) {
704 NAPI_ERR_LOG("Failed to execute libuv work queue, ret: %{public}d", ret);
705 delete msg;
706 delete work;
707 return;
708 }
709 return;
710 }
711 }
712 }
713