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