• 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 #define MLOG_TAG "MediaAssetManagerNapi"
17 
18 #include "media_asset_manager_napi.h"
19 
20 #include <fcntl.h>
21 #include <string>
22 #include <sys/sendfile.h>
23 #include <unordered_map>
24 #include <uuid/uuid.h>
25 
26 #include "access_token.h"
27 #include "accesstoken_kit.h"
28 #include "dataobs_mgr_client.h"
29 #include "directory_ex.h"
30 #include "file_asset_napi.h"
31 #include "file_uri.h"
32 #include "image_source.h"
33 #include "image_source_napi.h"
34 #include "ipc_skeleton.h"
35 #include "media_column.h"
36 #include "media_file_utils.h"
37 #include "media_file_uri.h"
38 #include "medialibrary_client_errno.h"
39 #include "media_library_napi.h"
40 #include "medialibrary_errno.h"
41 #include "medialibrary_napi_log.h"
42 #include "medialibrary_napi_utils.h"
43 #include "medialibrary_napi_utils_ext.h"
44 #include "medialibrary_tracer.h"
45 #include "moving_photo_napi.h"
46 #include "permission_utils.h"
47 #include "picture_handle_client.h"
48 #include "ui_extension_context.h"
49 #include "userfile_client.h"
50 #include "media_call_transcode.h"
51 
52 using namespace OHOS::Security::AccessToken;
53 
54 namespace OHOS {
55 namespace Media {
56 static const std::string MEDIA_ASSET_MANAGER_CLASS = "MediaAssetManager";
57 static std::mutex multiStagesCaptureLock;
58 static std::mutex registerTaskLock;
59 
60 const int32_t LOW_QUALITY_IMAGE = 1;
61 const int32_t HIGH_QUALITY_IMAGE = 0;
62 
63 const int32_t UUID_STR_LENGTH = 37;
64 const int32_t MAX_URI_SIZE = 384; // 256 for display name and 128 for relative path
65 const int32_t REQUEST_ID_MAX_LEN = 64;
66 
67 const std::string HIGH_TEMPERATURE = "high_temperature";
68 
69 thread_local unique_ptr<ChangeListenerNapi> g_multiStagesRequestListObj = nullptr;
70 thread_local napi_ref constructor_ = nullptr;
71 
72 static std::map<std::string, std::shared_ptr<MultiStagesTaskObserver>> multiStagesObserverMap;
73 static std::map<std::string, std::map<std::string, AssetHandler*>> inProcessUriMap;
74 static SafeMap<std::string, AssetHandler*> inProcessFastRequests;
75 static SafeMap<std::string, AssetHandler*> onPreparedResult_;
76 static SafeMap<std::string, napi_value> onPreparedResultValue_;
77 static SafeMap<std::string, bool> isTranscoderMap_;
78 
Init(napi_env env,napi_value exports)79 napi_value MediaAssetManagerNapi::Init(napi_env env, napi_value exports)
80 {
81     NapiClassInfo info = {.name = MEDIA_ASSET_MANAGER_CLASS,
82         .ref = &constructor_,
83         .constructor = Constructor,
84         .props = {
85             DECLARE_NAPI_STATIC_FUNCTION("requestImage", JSRequestImage),
86             DECLARE_NAPI_STATIC_FUNCTION("requestImageData", JSRequestImageData),
87             DECLARE_NAPI_STATIC_FUNCTION("requestMovingPhoto", JSRequestMovingPhoto),
88             DECLARE_NAPI_STATIC_FUNCTION("requestVideoFile", JSRequestVideoFile),
89             DECLARE_NAPI_STATIC_FUNCTION("cancelRequest", JSCancelRequest),
90             DECLARE_NAPI_STATIC_FUNCTION("loadMovingPhoto", JSLoadMovingPhoto),
91             DECLARE_NAPI_STATIC_FUNCTION("quickRequestImage", JSRequestEfficientIImage)
92         }};
93         MediaLibraryNapiUtils::NapiDefineClass(env, exports, info);
94         return exports;
95 }
96 
Constructor(napi_env env,napi_callback_info info)97 napi_value MediaAssetManagerNapi::Constructor(napi_env env, napi_callback_info info)
98 {
99     napi_value newTarget = nullptr;
100     CHECK_ARGS(env, napi_get_new_target(env, info, &newTarget), JS_INNER_FAIL);
101     bool isConstructor = newTarget != nullptr;
102     if (isConstructor) {
103         napi_value thisVar = nullptr;
104         unique_ptr<MediaAssetManagerNapi> obj = make_unique<MediaAssetManagerNapi>();
105         CHECK_COND_WITH_MESSAGE(env, obj != nullptr, "Create MediaAssetManagerNapi failed");
106         CHECK_ARGS(env,
107             napi_wrap(env, thisVar, reinterpret_cast<void*>(obj.get()), MediaAssetManagerNapi::Destructor,
108                 nullptr, nullptr),
109             JS_INNER_FAIL);
110         obj.release();
111         return thisVar;
112     }
113     napi_value constructor = nullptr;
114     napi_value result = nullptr;
115     NAPI_CALL(env, napi_get_reference_value(env, constructor_, &constructor));
116     NAPI_CALL(env, napi_new_instance(env, constructor, 0, nullptr, &result));
117     return result;
118 }
119 
Destructor(napi_env env,void * nativeObject,void * finalizeHint)120 void MediaAssetManagerNapi::Destructor(napi_env env, void *nativeObject, void *finalizeHint)
121 {
122     auto* mediaAssetManager = reinterpret_cast<MediaAssetManagerNapi*>(nativeObject);
123     if (mediaAssetManager != nullptr) {
124         delete mediaAssetManager;
125         mediaAssetManager = nullptr;
126     }
127 }
128 
HasReadPermission()129 static bool HasReadPermission()
130 {
131     AccessTokenID tokenCaller = IPCSkeleton::GetSelfTokenID();
132     int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_READ_IMAGEVIDEO);
133     return result == PermissionState::PERMISSION_GRANTED;
134 }
135 
CreateAssetHandler(const std::string & photoId,const std::string & requestId,const std::string & uri,const MediaAssetDataHandlerPtr & handler,napi_threadsafe_function func)136 static AssetHandler* CreateAssetHandler(const std::string &photoId, const std::string &requestId,
137     const std::string &uri, const MediaAssetDataHandlerPtr &handler, napi_threadsafe_function func)
138 {
139     AssetHandler *assetHandler = new AssetHandler(photoId, requestId, uri, handler, func);
140     NAPI_DEBUG_LOG("[AssetHandler create] photoId: %{public}s, requestId: %{public}s, uri: %{public}s",
141         photoId.c_str(), requestId.c_str(), uri.c_str());
142     return assetHandler;
143 }
144 
DeleteAssetHandlerSafe(AssetHandler * handler,napi_env env)145 static void DeleteAssetHandlerSafe(AssetHandler *handler, napi_env env)
146 {
147     if (handler != nullptr) {
148         if (handler->dataHandler != nullptr) {
149             handler->dataHandler->DeleteNapiReference(env);
150         }
151         if (handler->threadSafeFunc != nullptr) {
152             napi_release_threadsafe_function(handler->threadSafeFunc, napi_tsfn_release);
153             handler->threadSafeFunc = nullptr;
154         }
155         delete handler;
156         handler = nullptr;
157     }
158 }
159 
DeleteProcessHandlerSafe(ProgressHandler * handler,napi_env env)160 static void DeleteProcessHandlerSafe(ProgressHandler *handler, napi_env env)
161 {
162     if (handler == nullptr) {
163         return;
164     }
165     if (handler->progressRef != nullptr && env != nullptr) {
166         napi_delete_reference(env, handler->progressRef);
167         handler->progressRef = nullptr;
168     }
169     delete handler;
170     handler = nullptr;
171 }
172 
InsertInProcessMapRecord(const std::string & requestUri,const std::string & requestId,AssetHandler * handler)173 static void InsertInProcessMapRecord(const std::string &requestUri, const std::string &requestId,
174     AssetHandler *handler)
175 {
176     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
177     std::map<std::string, AssetHandler*> assetHandler;
178     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
179     if (inProcessUriMap.find(uriLocal) != inProcessUriMap.end()) {
180         assetHandler = inProcessUriMap[uriLocal];
181         assetHandler[requestId] = handler;
182         inProcessUriMap[uriLocal] = assetHandler;
183     } else {
184         assetHandler[requestId] = handler;
185         inProcessUriMap[uriLocal] = assetHandler;
186     }
187 }
188 
189 // Do not use directly
DeleteRecordNoLock(const std::string & requestUri,const std::string & requestId)190 static void DeleteRecordNoLock(const std::string &requestUri, const std::string &requestId)
191 {
192     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
193     auto uriHightemp = uriLocal + HIGH_TEMPERATURE;
194     if (inProcessUriMap.find(uriLocal) == inProcessUriMap.end()) {
195         return;
196     }
197 
198     std::map<std::string, AssetHandler*> assetHandlers = inProcessUriMap[uriLocal];
199     if (assetHandlers.find(requestId) == assetHandlers.end()) {
200         return;
201     }
202 
203     assetHandlers.erase(requestId);
204     if (!assetHandlers.empty()) {
205         inProcessUriMap[uriLocal] = assetHandlers;
206         return;
207     }
208 
209     inProcessUriMap.erase(uriLocal);
210 
211     if (multiStagesObserverMap.find(uriLocal) != multiStagesObserverMap.end()) {
212         UserFileClient::UnregisterObserverExt(Uri(uriLocal),
213             static_cast<std::shared_ptr<DataShare::DataShareObserver>>(multiStagesObserverMap[uriLocal]));
214     }
215     if (multiStagesObserverMap.find(uriHightemp) != multiStagesObserverMap.end()) {
216         UserFileClient::UnregisterObserverExt(Uri(uriHightemp),
217             static_cast<std::shared_ptr<DataShare::DataShareObserver>>(multiStagesObserverMap[uriHightemp]));
218     }
219     multiStagesObserverMap.erase(uriLocal);
220     multiStagesObserverMap.erase(uriHightemp);
221 }
222 
DeleteInProcessMapRecord(const std::string & requestUri,const std::string & requestId)223 static void DeleteInProcessMapRecord(const std::string &requestUri, const std::string &requestId)
224 {
225     DeleteRecordNoLock(requestUri, requestId);
226 }
227 
IsInProcessInMapRecord(const std::string & requestId,AssetHandler * & handler)228 static int32_t IsInProcessInMapRecord(const std::string &requestId, AssetHandler* &handler)
229 {
230     for (auto record : inProcessUriMap) {
231         if (record.second.find(requestId) != record.second.end()) {
232             handler = record.second[requestId];
233             return true;
234         }
235     }
236 
237     return false;
238 }
239 
InsertDataHandler(NotifyMode notifyMode,napi_env env,MediaAssetManagerAsyncContext * asyncContext)240 static AssetHandler* InsertDataHandler(NotifyMode notifyMode, napi_env env,
241     MediaAssetManagerAsyncContext *asyncContext)
242 {
243     napi_ref dataHandlerRef;
244     napi_threadsafe_function threadSafeFunc;
245     if (notifyMode == NotifyMode::FAST_NOTIFY) {
246         dataHandlerRef = asyncContext->dataHandlerRef;
247         asyncContext->dataHandlerRef = nullptr;
248         threadSafeFunc = asyncContext->onDataPreparedPtr;
249     } else {
250         dataHandlerRef = asyncContext->dataHandlerRef2;
251         asyncContext->dataHandlerRef2 = nullptr;
252         threadSafeFunc = asyncContext->onDataPreparedPtr2;
253     }
254     std::shared_ptr<NapiMediaAssetDataHandler> mediaAssetDataHandler = make_shared<NapiMediaAssetDataHandler>(
255         env, dataHandlerRef, asyncContext->returnDataType, asyncContext->photoUri, asyncContext->destUri,
256         asyncContext->sourceMode);
257     mediaAssetDataHandler->SetCompatibleMode(asyncContext->compatibleMode);
258     mediaAssetDataHandler->SetNotifyMode(notifyMode);
259     mediaAssetDataHandler->SetRequestId(asyncContext->requestId);
260 
261     AssetHandler *assetHandler = CreateAssetHandler(asyncContext->photoId, asyncContext->requestId,
262         asyncContext->photoUri, mediaAssetDataHandler, threadSafeFunc);
263     assetHandler->photoQuality = asyncContext->photoQuality;
264     assetHandler->needsExtraInfo = asyncContext->needsExtraInfo;
265     NAPI_INFO_LOG("Add %{public}d, %{public}s, %{public}s", notifyMode, asyncContext->photoUri.c_str(),
266         asyncContext->requestId.c_str());
267 
268     switch (notifyMode) {
269         case NotifyMode::FAST_NOTIFY: {
270             inProcessFastRequests.EnsureInsert(asyncContext->requestId, assetHandler);
271             break;
272         }
273         case NotifyMode::WAIT_FOR_HIGH_QUALITY: {
274             InsertInProcessMapRecord(asyncContext->photoUri, asyncContext->requestId, assetHandler);
275             break;
276         }
277         default:
278             break;
279     }
280 
281     return assetHandler;
282 }
283 
InsertProgressHandler(napi_env env,MediaAssetManagerAsyncContext * asyncContext)284 static ProgressHandler* InsertProgressHandler(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
285 {
286     napi_ref dataHandlerRef;
287     napi_threadsafe_function threadSafeFunc;
288     dataHandlerRef = asyncContext->progressHandlerRef;
289     threadSafeFunc = asyncContext->onProgressPtr;
290     ProgressHandler *progressHandler = new ProgressHandler(env, threadSafeFunc, asyncContext->requestId,
291         dataHandlerRef);
292     MediaAssetManagerNapi::progressHandlerMap_.EnsureInsert(asyncContext->requestId, progressHandler);
293     NAPI_DEBUG_LOG("InsertProgressHandler");
294     return  progressHandler;
295 }
296 
DeleteDataHandler(NotifyMode notifyMode,const std::string & requestUri,const std::string & requestId)297 static void DeleteDataHandler(NotifyMode notifyMode, const std::string &requestUri, const std::string &requestId)
298 {
299     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
300     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
301     NAPI_INFO_LOG("Rmv %{public}d, %{public}s, %{public}s", notifyMode, requestUri.c_str(), requestId.c_str());
302     if (notifyMode == NotifyMode::WAIT_FOR_HIGH_QUALITY) {
303         DeleteInProcessMapRecord(uriLocal, requestId);
304     }
305     inProcessFastRequests.Erase(requestId);
306 }
307 
QueryPhotoStatus(int fileId,const string & photoUri,std::string & photoId,bool hasReadPermission,int32_t userId)308 MultiStagesCapturePhotoStatus MediaAssetManagerNapi::QueryPhotoStatus(int fileId,
309     const string& photoUri, std::string &photoId, bool hasReadPermission, int32_t userId)
310 {
311     photoId = "";
312     DataShare::DataSharePredicates predicates;
313     predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
314     std::vector<std::string> fetchColumn { PhotoColumn::PHOTO_QUALITY, PhotoColumn::PHOTO_ID};
315     string queryUri;
316     if (hasReadPermission) {
317         queryUri = PAH_QUERY_PHOTO;
318     } else {
319         queryUri = photoUri;
320         MediaFileUri::RemoveAllFragment(queryUri);
321     }
322     Uri uri(queryUri);
323     int errCode = 0;
324     auto resultSet = UserFileClient::Query(uri, predicates, fetchColumn, errCode, userId);
325     if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
326         NAPI_ERR_LOG("query resultSet is nullptr");
327         return MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
328     }
329     int indexOfPhotoId = -1;
330     resultSet->GetColumnIndex(PhotoColumn::PHOTO_ID, indexOfPhotoId);
331     resultSet->GetString(indexOfPhotoId, photoId);
332 
333     int columnIndexQuality = -1;
334     resultSet->GetColumnIndex(PhotoColumn::PHOTO_QUALITY, columnIndexQuality);
335     int currentPhotoQuality = HIGH_QUALITY_IMAGE;
336     resultSet->GetInt(columnIndexQuality, currentPhotoQuality);
337     if (currentPhotoQuality == LOW_QUALITY_IMAGE) {
338         NAPI_INFO_LOG("query photo status : lowQuality");
339         return MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS;
340     }
341     NAPI_INFO_LOG("query photo status quality: %{public}d", currentPhotoQuality);
342     return MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
343 }
344 
ProcessImage(const int fileId,const int deliveryMode)345 void MediaAssetManagerNapi::ProcessImage(const int fileId, const int deliveryMode)
346 {
347     std::string uriStr = PAH_PROCESS_IMAGE;
348     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
349     Uri uri(uriStr);
350     DataShare::DataSharePredicates predicates;
351     int errCode = 0;
352     std::vector<std::string> columns { std::to_string(fileId), std::to_string(deliveryMode) };
353     UserFileClient::Query(uri, predicates, columns, errCode);
354 }
355 
CancelProcessImage(const std::string & photoId)356 void MediaAssetManagerNapi::CancelProcessImage(const std::string &photoId)
357 {
358     std::string uriStr = PAH_CANCEL_PROCESS_IMAGE;
359     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
360     Uri uri(uriStr);
361     DataShare::DataSharePredicates predicates;
362     int errCode = 0;
363     std::vector<std::string> columns { photoId };
364     UserFileClient::Query(uri, predicates, columns, errCode);
365 }
366 
AddImage(const int fileId,DeliveryMode deliveryMode)367 void MediaAssetManagerNapi::AddImage(const int fileId, DeliveryMode deliveryMode)
368 {
369     Uri updateAssetUri(PAH_ADD_IMAGE);
370     DataShare::DataSharePredicates predicates;
371     DataShare::DataShareValuesBucket valuesBucket;
372     valuesBucket.Put(MediaColumn::MEDIA_ID, fileId);
373     valuesBucket.Put("deliveryMode", static_cast<int>(deliveryMode));
374     UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
375 }
376 
GetDeliveryMode(napi_env env,const napi_value arg,const string & propName,DeliveryMode & deliveryMode)377 napi_status GetDeliveryMode(napi_env env, const napi_value arg, const string &propName,
378     DeliveryMode& deliveryMode)
379 {
380     bool present = false;
381     napi_value property = nullptr;
382     int mode = -1;
383     CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present),
384         "Failed to check property name");
385     if (!present) {
386         NAPI_ERR_LOG("No delivery mode specified");
387         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "No delivery mode specified");
388         return napi_invalid_arg;
389     }
390     CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
391     CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse deliveryMode argument value");
392 
393     // delivery mode's valid range is 0 - 2
394     if (mode < 0 || mode > 2) {
395         NAPI_ERR_LOG("delivery mode invalid argument ");
396         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid delivery mode value");
397         return napi_invalid_arg;
398     }
399     deliveryMode = static_cast<DeliveryMode>(mode);
400     return napi_ok;
401 }
402 
GetSourceMode(napi_env env,const napi_value arg,const string & propName,SourceMode & sourceMode)403 napi_status GetSourceMode(napi_env env, const napi_value arg, const string &propName,
404     SourceMode& sourceMode)
405 {
406     bool present = false;
407     napi_value property = nullptr;
408     int mode = -1;
409     CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
410     if (!present) {
411         // use default source mode
412         sourceMode = SourceMode::EDITED_MODE;
413         return napi_ok;
414     } else if (!MediaLibraryNapiUtils::IsSystemApp()) {
415         NAPI_ERR_LOG("Source mode is only available to system apps");
416         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "Source mode is only available to system apps");
417         return napi_invalid_arg;
418     }
419     CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
420     CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse sourceMode argument value");
421 
422     // source mode's valid range is 0 - 1
423     if (mode < 0 || mode > 1) {
424         NAPI_ERR_LOG("source mode invalid");
425         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid source mode value");
426         return napi_invalid_arg;
427     }
428     sourceMode = static_cast<SourceMode>(mode);
429     return napi_ok;
430 }
431 
ParseArgGetRequestOption(napi_env env,napi_value arg,DeliveryMode & deliveryMode,SourceMode & sourceMode)432 napi_status ParseArgGetRequestOption(napi_env env, napi_value arg, DeliveryMode &deliveryMode, SourceMode &sourceMode)
433 {
434     CHECK_STATUS_RET(GetDeliveryMode(env, arg, "deliveryMode", deliveryMode), "Failed to parse deliveryMode");
435     CHECK_STATUS_RET(GetSourceMode(env, arg, "sourceMode", sourceMode), "Failed to parse sourceMode");
436     return napi_ok;
437 }
438 
GetCompatibleMode(napi_env env,const napi_value arg,const string & propName,CompatibleMode & compatibleMode)439 napi_status GetCompatibleMode(napi_env env, const napi_value arg, const string &propName,
440     CompatibleMode& compatibleMode)
441 {
442     bool present = false;
443     napi_value property = nullptr;
444     int mode = static_cast<int>(CompatibleMode::ORIGINAL_FORMAT_MODE);
445     CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
446     if (!present) {
447         NAPI_INFO_LOG("compatible mode is null");
448         compatibleMode = CompatibleMode::ORIGINAL_FORMAT_MODE;
449         return napi_ok;
450     }
451     CHECK_STATUS_RET(napi_get_named_property(env, arg, propName.c_str(), &property), "Failed to get property");
452     CHECK_STATUS_RET(napi_get_value_int32(env, property, &mode), "Failed to parse compatiblemode argument value");
453 
454     if (static_cast<CompatibleMode>(mode) < CompatibleMode::ORIGINAL_FORMAT_MODE ||
455         static_cast<CompatibleMode>(mode) > CompatibleMode::COMPATIBLE_FORMAT_MODE) {
456         NAPI_ERR_LOG("delivery mode invalid argument ");
457         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "invalid compatible mode value");
458         return napi_invalid_arg;
459     }
460 #ifndef USE_VIDEO_PROCESSING_ENGINE
461     if (static_cast<CompatibleMode>(mode) == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
462         NAPI_ERR_LOG("current environment not support transcoder");
463         NapiError::ThrowError(env, OHOS_NOT_SUPPORT_TRANSCODER_CODE, "not support transcoder");
464         return napi_invalid_arg;
465     }
466 #endif
467     compatibleMode = static_cast<CompatibleMode>(mode);
468     return napi_ok;
469 }
470 
GetMediaAssetProgressHandler(napi_env env,const napi_value arg,napi_value & mediaAssetProgressHandler,const string & propName)471 napi_status GetMediaAssetProgressHandler(napi_env env, const napi_value arg, napi_value& mediaAssetProgressHandler,
472     const string &propName)
473 {
474     CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE,
475         "MediaAssetProgressHandler invalid argument", napi_invalid_arg, "MediaAssetProgressHandler  is nullptr");
476     bool present = false;
477     CHECK_STATUS_RET(napi_has_named_property(env, arg, propName.c_str(), &present), "Failed to check property name");
478     if (!present) {
479         NAPI_INFO_LOG("MediaAssetProgressHandler is null");
480         mediaAssetProgressHandler = nullptr;
481         return napi_ok;
482     }
483     napi_value progressHandler;
484     napi_status status = napi_get_named_property(env, arg, "mediaAssetProgressHandler", &progressHandler);
485     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
486         "failed to get mediaAssetProgressHandler ", napi_invalid_arg,
487         "failed to get mediaAssetProgressHandler, napi status: %{public}d", static_cast<int>(status));
488     napi_valuetype valueType;
489     status = napi_typeof(env, progressHandler, &valueType);
490     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid progress handler",
491         napi_invalid_arg, "failed to get type of progress handler, napi status: %{public}d", static_cast<int>(status));
492     CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
493         "progress handler not an object", napi_invalid_arg, "progress handler not an object");
494 
495     napi_value onProgress;
496     status = napi_get_named_property(env, progressHandler, ON_PROGRESS_FUNC, &onProgress);
497     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
498         "unable to get onProgress function", napi_invalid_arg,
499         "failed to get onProgress function, napi status: %{public}d", static_cast<int>(status));
500 
501     status = napi_typeof(env, onProgress, &valueType);
502     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onProgress",
503         napi_invalid_arg, "failed to get type of onProgress, napi status: %{public}d", static_cast<int>(status));
504     CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
505         "onProgress not a function", napi_invalid_arg, "onProgress not a function");
506     mediaAssetProgressHandler = progressHandler;
507     return napi_ok;
508 }
509 
ParseArgGetRequestOptionMore(napi_env env,napi_value arg,CompatibleMode & compatibleMode,napi_value & mediaAssetProgressHandler)510 napi_status ParseArgGetRequestOptionMore(napi_env env, napi_value arg, CompatibleMode &compatibleMode,
511     napi_value &mediaAssetProgressHandler)
512 {
513     NAPI_INFO_LOG("ParseArgGetRequestOptionMore start");
514     CHECK_STATUS_RET(GetCompatibleMode(env, arg, "compatibleMode", compatibleMode), "Failed to parse compatibleMode");
515     if (GetMediaAssetProgressHandler(env, arg, mediaAssetProgressHandler, "mediaAssetProgressHandler") != napi_ok) {
516         NAPI_ERR_LOG("requestMedia GetMediaAssetProgressHandler error");
517         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia GetMediaAssetProgressHandler error");
518         return napi_invalid_arg;
519     }
520     return napi_ok;
521 }
522 
ParseArgGetPhotoAsset(napi_env env,napi_value arg,int & fileId,std::string & uri,std::string & displayName)523 napi_status ParseArgGetPhotoAsset(napi_env env, napi_value arg, int &fileId, std::string &uri,
524     std::string &displayName)
525 {
526     if (arg == nullptr) {
527         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "ParseArgGetPhotoAsset failed to get photoAsset");
528         return napi_invalid_arg;
529     }
530     FileAssetNapi *obj = nullptr;
531     napi_unwrap(env, arg, reinterpret_cast<void**>(&obj));
532     if (obj == nullptr) {
533         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get asset napi object");
534         return napi_invalid_arg;
535     }
536     fileId = obj->GetFileId();
537     uri = obj->GetFileUri();
538     displayName = obj->GetFileDisplayName();
539     return napi_ok;
540 }
541 
ParseArgGetPhotoAsset(napi_env env,napi_value arg,unique_ptr<MediaAssetManagerAsyncContext> & asyncContext)542 napi_status ParseArgGetPhotoAsset(napi_env env, napi_value arg, unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
543 {
544     if (arg == nullptr) {
545         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "ParseArgGetPhotoAsset failed to get photoAsset");
546         return napi_invalid_arg;
547     }
548     FileAssetNapi *obj = nullptr;
549     napi_unwrap(env, arg, reinterpret_cast<void**>(&obj));
550     if (obj == nullptr) {
551         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get asset napi object");
552         return napi_invalid_arg;
553     }
554     asyncContext->fileId = obj->GetFileId();
555     asyncContext->photoUri = obj->GetFileUri();
556     asyncContext->displayName = obj->GetFileDisplayName();
557     asyncContext->userId = obj->GetFileAssetInstance()->GetUserId();
558     return napi_ok;
559 }
560 
ParseArgGetDestPath(napi_env env,napi_value arg,std::string & destPath)561 napi_status ParseArgGetDestPath(napi_env env, napi_value arg, std::string &destPath)
562 {
563     if (arg == nullptr) {
564         NAPI_ERR_LOG("destPath arg is invalid");
565         return napi_invalid_arg;
566     }
567     napi_get_print_string(env, arg, destPath);
568     if (destPath.empty()) {
569         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to get destPath napi object");
570         return napi_invalid_arg;
571     }
572     return napi_ok;
573 }
574 
ParseArgGetEfficientImageDataHandler(napi_env env,napi_value arg,napi_value & dataHandler,bool & needsExtraInfo)575 napi_status ParseArgGetEfficientImageDataHandler(napi_env env, napi_value arg, napi_value& dataHandler,
576     bool& needsExtraInfo)
577 {
578     CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE, "efficient handler invalid argument",
579         napi_invalid_arg, "efficient data handler is nullptr");
580 
581     napi_valuetype valueType;
582     napi_status status = napi_typeof(env, arg, &valueType);
583     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid efficient data handler",
584         napi_invalid_arg, "failed to get type of efficient data handler, napi status: %{public}d",
585         static_cast<int>(status));
586     CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
587         "efficient data handler not a object", napi_invalid_arg, "efficient data handler not a object");
588 
589     dataHandler = arg;
590 
591     napi_value onDataPrepared;
592     status = napi_get_named_property(env, arg, ON_DATA_PREPARED_FUNC, &onDataPrepared);
593     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
594         "unable to get onDataPrepared function", napi_invalid_arg,
595         "failed to get type of efficient data handler, napi status: %{public}d", static_cast<int>(status));
596     status = napi_typeof(env, onDataPrepared, &valueType);
597     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
598         napi_invalid_arg, "failed to get type of onDataPrepared, napi status: %{public}d", static_cast<int>(status));
599     CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
600         "onDataPrepared not a function", napi_invalid_arg, "onDataPrepared not a function");
601 
602     napi_value paramCountNapi;
603     status = napi_get_named_property(env, onDataPrepared, "length", &paramCountNapi);
604     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
605         napi_invalid_arg, "get onDataPrepared arg count fail, napi status: %{public}d", static_cast<int>(status));
606     int32_t paramCount = -1;
607     constexpr int paramCountMin = 2;
608     constexpr int paramCountMax = 3;
609     status = napi_get_value_int32(env, paramCountNapi, &paramCount);
610     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
611         napi_invalid_arg, "get onDataPrepared arg count value fail, napi status: %{public}d", static_cast<int>(status));
612     CHECK_COND_LOG_THROW_RETURN_RET(env, (paramCount >= paramCountMin && paramCount <= paramCountMax),
613         OHOS_INVALID_PARAM_CODE, "onDataPrepared has wrong number of parameters",
614         napi_invalid_arg, "onDataPrepared has wrong number of parameters");
615 
616     if (paramCount == ARGS_THREE) {
617         needsExtraInfo = true;
618     }
619     return napi_ok;
620 }
621 
ParseArgGetDataHandler(napi_env env,napi_value arg,napi_value & dataHandler,bool & needsExtraInfo)622 napi_status ParseArgGetDataHandler(napi_env env, napi_value arg, napi_value& dataHandler, bool& needsExtraInfo)
623 {
624     CHECK_COND_LOG_THROW_RETURN_RET(env, arg != nullptr, OHOS_INVALID_PARAM_CODE, "data handler invalid argument",
625         napi_invalid_arg, "data handler is nullptr");
626 
627     napi_valuetype valueType;
628     napi_status status = napi_typeof(env, arg, &valueType);
629     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid data handler",
630         napi_invalid_arg, "failed to get type of data handler, napi status: %{public}d", static_cast<int>(status));
631     CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_object, OHOS_INVALID_PARAM_CODE,
632         "data handler not a object", napi_invalid_arg, "data handler not a object");
633 
634     dataHandler = arg;
635 
636     napi_value onDataPrepared;
637     status = napi_get_named_property(env, arg, ON_DATA_PREPARED_FUNC, &onDataPrepared);
638     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE,
639         "unable to get onDataPrepared function", napi_invalid_arg,
640         "failed to get type of data handler, napi status: %{public}d", static_cast<int>(status));
641     status = napi_typeof(env, onDataPrepared, &valueType);
642     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
643         napi_invalid_arg, "failed to get type of onDataPrepared, napi status: %{public}d", static_cast<int>(status));
644     CHECK_COND_LOG_THROW_RETURN_RET(env, valueType == napi_function, OHOS_INVALID_PARAM_CODE,
645         "onDataPrepared not a function", napi_invalid_arg, "onDataPrepared not a function");
646 
647     napi_value paramCountNapi;
648     status = napi_get_named_property(env, onDataPrepared, "length", &paramCountNapi);
649     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
650         napi_invalid_arg, "get onDataPrepared arg count fail, napi status: %{public}d", static_cast<int>(status));
651     int32_t paramCount = -1;
652     constexpr int paramCountMin = 1;
653     constexpr int paramCountMax = 2;
654     status = napi_get_value_int32(env, paramCountNapi, &paramCount);
655     CHECK_COND_LOG_THROW_RETURN_RET(env, status == napi_ok, OHOS_INVALID_PARAM_CODE, "invalid onDataPrepared",
656         napi_invalid_arg, "get onDataPrepared arg count value fail, napi status: %{public}d", static_cast<int>(status));
657     CHECK_COND_LOG_THROW_RETURN_RET(env, (paramCount >= paramCountMin && paramCount <= paramCountMax),
658         OHOS_INVALID_PARAM_CODE, "onDataPrepared has wrong number of parameters",
659         napi_invalid_arg, "onDataPrepared has wrong number of parameters");
660 
661     if (paramCount == ARGS_TWO) {
662         needsExtraInfo = true;
663     }
664     return napi_ok;
665 }
666 
GenerateRequestId()667 static std::string GenerateRequestId()
668 {
669     uuid_t uuid;
670     uuid_generate(uuid);
671     char str[UUID_STR_LENGTH] = {};
672     uuid_unparse(uuid, str);
673     return str;
674 }
675 
RegisterTaskObserver(napi_env env,MediaAssetManagerAsyncContext * asyncContext)676 void MediaAssetManagerNapi::RegisterTaskObserver(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
677 {
678     auto dataObserver = std::make_shared<MultiStagesTaskObserver>(asyncContext->fileId);
679     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(asyncContext->photoUri);
680     auto uriHightemp = uriLocal + HIGH_TEMPERATURE;
681     NAPI_INFO_LOG("MultistagesCapture, uri: %{public}s, %{public}s, uriHighTemp: %{public}s.",
682         asyncContext->photoUri.c_str(), uriLocal.c_str(), uriHightemp.c_str());
683     Uri uri(asyncContext->photoUri);
684     std::unique_lock<std::mutex> registerLock(registerTaskLock);
685     if (multiStagesObserverMap.find(uriLocal) == multiStagesObserverMap.end()) {
686         UserFileClient::RegisterObserverExt(Uri(uriLocal),
687             static_cast<std::shared_ptr<DataShare::DataShareObserver>>(dataObserver), false);
688         multiStagesObserverMap.insert(std::make_pair(uriLocal, dataObserver));
689     }
690     if (multiStagesObserverMap.find(uriHightemp) == multiStagesObserverMap.end()) {
691         UserFileClient::RegisterObserverExt(Uri(uriHightemp),
692             static_cast<std::shared_ptr<DataShare::DataShareObserver>>(dataObserver), false);
693         multiStagesObserverMap.insert(std::make_pair(uriHightemp, dataObserver));
694     }
695     registerLock.unlock();
696 
697     InsertDataHandler(NotifyMode::WAIT_FOR_HIGH_QUALITY, env, asyncContext);
698 
699     MediaAssetManagerNapi::ProcessImage(asyncContext->fileId, static_cast<int32_t>(asyncContext->deliveryMode));
700 }
701 
ParseRequestMediaArgs(napi_env env,napi_callback_info info,unique_ptr<MediaAssetManagerAsyncContext> & asyncContext)702 napi_status MediaAssetManagerNapi::ParseRequestMediaArgs(napi_env env, napi_callback_info info,
703     unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
704 {
705     napi_value thisVar = nullptr;
706     GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
707     if (asyncContext->argc != ARGS_FOUR && asyncContext->argc != ARGS_FIVE) {
708         NAPI_ERR_LOG("requestMedia argc error");
709         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
710         return napi_invalid_arg;
711     }
712     if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext) != napi_ok) {
713         NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
714         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
715         return napi_invalid_arg;
716     }
717     if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
718         asyncContext->sourceMode) != napi_ok) {
719         NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
720         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
721         return napi_invalid_arg;
722     }
723     if (ParseArgGetRequestOptionMore(env, asyncContext->argv[PARAM2], asyncContext->compatibleMode,
724         asyncContext->mediaAssetProgressHandler) != napi_ok) {
725         NAPI_ERR_LOG("requestMedia ParseArgGetRequestOptionMore error");
726         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOptionMore error");
727         return napi_invalid_arg;
728     }
729     if (asyncContext->argc == ARGS_FOUR) {
730         if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
731             asyncContext->needsExtraInfo) != napi_ok) {
732             NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
733             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
734             return napi_invalid_arg;
735         }
736     } else if (asyncContext->argc == ARGS_FIVE) {
737         if (ParseArgGetDestPath(env, asyncContext->argv[PARAM3], asyncContext->destUri) != napi_ok) {
738             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDestPath error");
739             return napi_invalid_arg;
740         }
741         if (ParseArgGetDataHandler(env, asyncContext->argv[PARAM4], asyncContext->dataHandler,
742             asyncContext->needsExtraInfo) != napi_ok) {
743             NAPI_ERR_LOG("requestMedia ParseArgGetDataHandler error");
744             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDataHandler error");
745             return napi_invalid_arg;
746         }
747     }
748     asyncContext->hasReadPermission = HasReadPermission();
749     return napi_ok;
750 }
751 
ParseEfficentRequestMediaArgs(napi_env env,napi_callback_info info,unique_ptr<MediaAssetManagerAsyncContext> & asyncContext)752 napi_status MediaAssetManagerNapi::ParseEfficentRequestMediaArgs(napi_env env, napi_callback_info info,
753     unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
754 {
755     napi_value thisVar = nullptr;
756     GET_JS_ARGS(env, info, asyncContext->argc, asyncContext->argv, thisVar);
757     if (asyncContext->argc != ARGS_FOUR && asyncContext->argc != ARGS_FIVE) {
758         NAPI_ERR_LOG("requestMedia argc error");
759         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia argc invalid");
760         return napi_invalid_arg;
761     }
762 
763     if (ParseArgGetPhotoAsset(env, asyncContext->argv[PARAM1], asyncContext) != napi_ok) {
764         NAPI_ERR_LOG("requestMedia ParseArgGetPhotoAsset error");
765         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetPhotoAsset error");
766         return napi_invalid_arg;
767     }
768     if (ParseArgGetRequestOption(env, asyncContext->argv[PARAM2], asyncContext->deliveryMode,
769         asyncContext->sourceMode) != napi_ok) {
770         NAPI_ERR_LOG("requestMedia ParseArgGetRequestOption error");
771         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetRequestOption error");
772         return napi_invalid_arg;
773     }
774     if (asyncContext->argc == ARGS_FOUR) {
775         if (ParseArgGetEfficientImageDataHandler(env, asyncContext->argv[PARAM3], asyncContext->dataHandler,
776             asyncContext->needsExtraInfo) != napi_ok) {
777             NAPI_ERR_LOG("requestMedia ParseArgGetEfficientImageDataHandler error");
778             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE,
779                 "requestMedia ParseArgGetEfficientImageDataHandler error");
780             return napi_invalid_arg;
781         }
782     } else if (asyncContext->argc == ARGS_FIVE) {
783         if (ParseArgGetDestPath(env, asyncContext->argv[PARAM3], asyncContext->destUri) != napi_ok) {
784             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMedia ParseArgGetDestPath error");
785             return napi_invalid_arg;
786         }
787         if (ParseArgGetEfficientImageDataHandler(env, asyncContext->argv[PARAM4], asyncContext->dataHandler,
788             asyncContext->needsExtraInfo) != napi_ok) {
789             NAPI_ERR_LOG("requestMedia ParseArgGetEfficientImageDataHandler error");
790             NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE,
791                 "requestMedia ParseArgGetEfficientImageDataHandler error");
792             return napi_invalid_arg;
793         }
794     }
795     asyncContext->hasReadPermission = HasReadPermission();
796     return napi_ok;
797 }
798 
InitUserFileClient(napi_env env,napi_callback_info info,const int32_t userId)799 bool MediaAssetManagerNapi::InitUserFileClient(napi_env env, napi_callback_info info, const int32_t userId)
800 {
801     if (UserFileClient::IsValid(userId)) {
802         return true;
803     }
804 
805     std::unique_lock<std::mutex> helperLock(MediaLibraryNapi::sUserFileClientMutex_);
806     if (!UserFileClient::IsValid(userId)) {
807         UserFileClient::Init(env, info, userId);
808     }
809     helperLock.unlock();
810     return UserFileClient::IsValid(userId);
811 }
812 
GetPhotoSubtype(napi_env env,napi_value photoAssetArg)813 static int32_t GetPhotoSubtype(napi_env env, napi_value photoAssetArg)
814 {
815     if (photoAssetArg == nullptr) {
816         NAPI_ERR_LOG(
817             "Dfx adaptation to moving photo collector error: failed to get photo subtype, photo asset is null");
818         return -1;
819     }
820     FileAssetNapi *obj = nullptr;
821     napi_unwrap(env, photoAssetArg, reinterpret_cast<void**>(&obj));
822     if (obj == nullptr) {
823         NAPI_ERR_LOG("Dfx adaptation to moving photo collector error: failed to unwrap file asset");
824         return -1;
825     }
826     return obj->GetFileAssetInstance()->GetPhotoSubType();
827 }
828 
JSRequestImageData(napi_env env,napi_callback_info info)829 napi_value MediaAssetManagerNapi::JSRequestImageData(napi_env env, napi_callback_info info)
830 {
831     NAPI_INFO_LOG("Begin JSRequestImageData");
832     if (env == nullptr || info == nullptr) {
833         NAPI_ERR_LOG("JSRequestImageData js arg invalid");
834         NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestImageData js arg invalid");
835         return nullptr;
836     }
837 
838     MediaLibraryTracer tracer;
839     tracer.Start("JSRequestImageData");
840     unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
841     asyncContext->returnDataType = ReturnDataType::TYPE_ARRAY_BUFFER;
842     if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
843         NAPI_ERR_LOG("failed to parse requestImagedata args");
844         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestImagedata args");
845         return nullptr;
846     }
847     if (!InitUserFileClient(env, info, asyncContext->userId)) {
848         NAPI_ERR_LOG("JSRequestEfficientIImage init user file client failed");
849         NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
850         return nullptr;
851     }
852     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
853             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
854         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
855         return nullptr;
856     }
857     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
858             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
859         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
860         return nullptr;
861     }
862 
863     asyncContext->requestId = GenerateRequestId();
864     asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
865 
866     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestImageData", JSRequestExecute,
867         JSRequestComplete);
868 }
869 
JSRequestImage(napi_env env,napi_callback_info info)870 napi_value MediaAssetManagerNapi::JSRequestImage(napi_env env, napi_callback_info info)
871 {
872     NAPI_INFO_LOG("Begin JSRequestImage");
873     if (env == nullptr || info == nullptr) {
874         NAPI_ERR_LOG("JSRequestImage js arg invalid");
875         NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestImage js arg invalid");
876         return nullptr;
877     }
878 
879     MediaLibraryTracer tracer;
880     tracer.Start("JSRequestImage");
881 
882     unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
883     asyncContext->returnDataType = ReturnDataType::TYPE_IMAGE_SOURCE;
884     if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
885         NAPI_ERR_LOG("failed to parse requestImage args");
886         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestImage args");
887         return nullptr;
888     }
889     if (!InitUserFileClient(env, info, asyncContext->userId)) {
890         NAPI_ERR_LOG("JSRequestImage init user file client failed");
891         NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
892         return nullptr;
893     }
894     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
895             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
896         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
897         return nullptr;
898     }
899     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
900             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
901         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
902         return nullptr;
903     }
904 
905     asyncContext->requestId = GenerateRequestId();
906     asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
907 
908     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestImage", JSRequestExecute,
909         JSRequestComplete);
910 }
911 
JSRequestEfficientIImage(napi_env env,napi_callback_info info)912 napi_value MediaAssetManagerNapi::JSRequestEfficientIImage(napi_env env, napi_callback_info info)
913 {
914     NAPI_DEBUG_LOG("JSRequestEfficientIImage");
915     if (env == nullptr || info == nullptr) {
916         NAPI_ERR_LOG("JSRequestEfficientIImage js arg invalid");
917         NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestEfficientIImage js arg invalid");
918         return nullptr;
919     }
920 
921     MediaLibraryTracer tracer;
922     tracer.Start("JSRequestEfficientIImage");
923 
924     unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
925     asyncContext->returnDataType = ReturnDataType::TYPE_PICTURE;
926     if (ParseEfficentRequestMediaArgs(env, info, asyncContext) != napi_ok) {
927         NAPI_ERR_LOG("failed to parse JSRequestEfficientIImage args");
928         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse JSRequestEfficientIImage args");
929         return nullptr;
930     }
931     if (!InitUserFileClient(env, info, asyncContext->userId)) {
932         NAPI_ERR_LOG("JSRequestEfficientIImage init user file client failed");
933         NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
934         return nullptr;
935     }
936     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
937             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
938         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
939         return nullptr;
940     }
941     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
942             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
943         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
944         return nullptr;
945     }
946 
947     asyncContext->requestId = GenerateRequestId();
948     asyncContext->subType = static_cast<PhotoSubType>(GetPhotoSubtype(env, asyncContext->argv[PARAM1]));
949 
950     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestEfficientIImage", JSRequestExecute,
951         JSRequestComplete);
952 }
953 
ReleaseSafeFunc(napi_threadsafe_function & threadSafeFunc)954 void MediaAssetManagerNapi::ReleaseSafeFunc(napi_threadsafe_function &threadSafeFunc)
955 {
956     if (threadSafeFunc == nullptr) {
957         return;
958     }
959     napi_release_threadsafe_function(threadSafeFunc, napi_tsfn_release);
960     threadSafeFunc = nullptr;
961 }
962 
CreateOnProgressHandlerInfo(napi_env env,unique_ptr<MediaAssetManagerAsyncContext> & asyncContext)963 bool MediaAssetManagerNapi::CreateOnProgressHandlerInfo(napi_env env,
964     unique_ptr<MediaAssetManagerAsyncContext> &asyncContext)
965 {
966     if (asyncContext->compatibleMode != CompatibleMode::COMPATIBLE_FORMAT_MODE) {
967         return true;
968     }
969     if (asyncContext->mediaAssetProgressHandler == nullptr) {
970         if (CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
971             NAPI_ERR_LOG("CreateOnProgressThreadSafeFunc failed");
972             return false;
973         }
974         return true;
975     }
976     if (CreateProgressHandlerRef(env, asyncContext, asyncContext->progressHandlerRef) != napi_ok ||
977         CreateOnProgressThreadSafeFunc(env, asyncContext, asyncContext->onProgressPtr) != napi_ok) {
978         NAPI_ERR_LOG("CreateProgressHandlerRef or CreateOnProgressThreadSafeFunc failed");
979         return false;
980     }
981     return true;
982 }
983 
JSRequestVideoFile(napi_env env,napi_callback_info info)984 napi_value MediaAssetManagerNapi::JSRequestVideoFile(napi_env env, napi_callback_info info)
985 {
986     if (env == nullptr || info == nullptr) {
987         NAPI_ERR_LOG("JSRequestVideoFile js arg invalid");
988         NapiError::ThrowError(env, JS_INNER_FAIL, "JSRequestVideoFile js arg invalid");
989         return nullptr;
990     }
991     MediaLibraryTracer tracer;
992     tracer.Start("JSRequestVideoFile");
993 
994     unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
995     asyncContext->returnDataType = ReturnDataType::TYPE_TARGET_PATH;
996     if (ParseRequestMediaArgs(env, info, asyncContext) != napi_ok) {
997         NAPI_ERR_LOG("failed to parse requestVideo args");
998         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "failed to parse requestVideo args");
999         return nullptr;
1000     }
1001     if (!InitUserFileClient(env, info, asyncContext->userId)) {
1002         NAPI_ERR_LOG("JSRequestEfficientIImage init user file client failed");
1003         NapiError::ThrowError(env, JS_INNER_FAIL, "handler is invalid");
1004         return nullptr;
1005     }
1006     if (asyncContext->photoUri.length() > MAX_URI_SIZE || asyncContext->destUri.length() > MAX_URI_SIZE) {
1007         NAPI_ERR_LOG("request video file uri lens out of limit photoUri lens: %{public}zu, destUri lens: %{public}zu",
1008             asyncContext->photoUri.length(), asyncContext->destUri.length());
1009         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file uri lens out of limit");
1010         return nullptr;
1011     }
1012     if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_VIDEO ||
1013         MediaFileUtils::GetMediaType(MediaFileUtils::GetFileName(asyncContext->destUri)) != MEDIA_TYPE_VIDEO) {
1014         NAPI_ERR_LOG("request video file type invalid");
1015         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "request video file type invalid");
1016         return nullptr;
1017     }
1018     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
1019             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
1020         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
1021         return nullptr;
1022     }
1023     if (!CreateOnProgressHandlerInfo(env, asyncContext)) {
1024         NAPI_ERR_LOG("CreateOnProgressHandlerInfo failed");
1025         return nullptr;
1026     }
1027 
1028     asyncContext->requestId = GenerateRequestId();
1029     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestVideoFile",
1030         JSRequestVideoFileExecute, JSRequestComplete);
1031 }
1032 
OnHandleRequestImage(napi_env env,MediaAssetManagerAsyncContext * asyncContext)1033 void MediaAssetManagerNapi::OnHandleRequestImage(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
1034 {
1035     CHECK_NULL_PTR_RETURN_VOID(asyncContext, "asyncContext is nullptr");
1036     NAPI_INFO_LOG("OnHandleRequestImage mode: %{public}d.", static_cast<int32_t>(asyncContext->deliveryMode));
1037     MultiStagesCapturePhotoStatus status = MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
1038     switch (asyncContext->deliveryMode) {
1039         case DeliveryMode::FAST:
1040             if (asyncContext->needsExtraInfo) {
1041                 asyncContext->photoQuality =
1042                     MediaAssetManagerNapi::QueryPhotoStatus(asyncContext->fileId, asyncContext->photoUri,
1043                     asyncContext->photoId, asyncContext->hasReadPermission, asyncContext->userId);
1044             }
1045             MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1046             ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
1047             break;
1048         case DeliveryMode::HIGH_QUALITY:
1049             status = MediaAssetManagerNapi::QueryPhotoStatus(asyncContext->fileId,
1050                 asyncContext->photoUri, asyncContext->photoId, asyncContext->hasReadPermission, asyncContext->userId);
1051             asyncContext->photoQuality = status;
1052             if (status == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
1053                 MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1054                 ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
1055             } else {
1056                 RegisterTaskObserver(env, asyncContext);
1057                 ReleaseSafeFunc(asyncContext->onDataPreparedPtr);
1058             }
1059             break;
1060         case DeliveryMode::BALANCED_MODE:
1061             status = MediaAssetManagerNapi::QueryPhotoStatus(asyncContext->fileId,
1062                 asyncContext->photoUri, asyncContext->photoId, asyncContext->hasReadPermission, asyncContext->userId);
1063             asyncContext->photoQuality = status;
1064             MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1065             if (status == MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
1066                 RegisterTaskObserver(env, asyncContext);
1067             } else {
1068                 ReleaseSafeFunc(asyncContext->onDataPreparedPtr2);
1069             }
1070             break;
1071         default: {
1072             NAPI_ERR_LOG("invalid delivery mode");
1073             return;
1074         }
1075     }
1076 }
1077 
OnHandleRequestVideo(napi_env env,MediaAssetManagerAsyncContext * asyncContext)1078 void MediaAssetManagerNapi::OnHandleRequestVideo(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
1079 {
1080     switch (asyncContext->deliveryMode) {
1081         case DeliveryMode::FAST:
1082             MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1083             break;
1084         case DeliveryMode::HIGH_QUALITY:
1085             MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1086             break;
1087         case DeliveryMode::BALANCED_MODE:
1088             MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(env, asyncContext);
1089             break;
1090         default: {
1091             NAPI_ERR_LOG("invalid delivery mode");
1092             return;
1093         }
1094     }
1095 }
1096 
NotifyDataPreparedWithoutRegister(napi_env env,MediaAssetManagerAsyncContext * asyncContext)1097 void MediaAssetManagerNapi::NotifyDataPreparedWithoutRegister(napi_env env,
1098     MediaAssetManagerAsyncContext *asyncContext)
1099 {
1100     AssetHandler *assetHandler = InsertDataHandler(NotifyMode::FAST_NOTIFY, env, asyncContext);
1101     if (assetHandler == nullptr) {
1102         NAPI_ERR_LOG("assetHandler is nullptr");
1103         return;
1104     }
1105     asyncContext->assetHandler = assetHandler;
1106 }
1107 
OnHandleProgress(napi_env env,MediaAssetManagerAsyncContext * asyncContext)1108 void MediaAssetManagerNapi::OnHandleProgress(napi_env env, MediaAssetManagerAsyncContext *asyncContext)
1109 {
1110     ProgressHandler *progressHandler = InsertProgressHandler(env, asyncContext);
1111     if (progressHandler == nullptr) {
1112         NAPI_ERR_LOG("progressHandler is nullptr");
1113         return;
1114     }
1115     asyncContext->progressHandler = progressHandler;
1116 }
1117 
PhotoQualityToString(MultiStagesCapturePhotoStatus photoQuality)1118 static string PhotoQualityToString(MultiStagesCapturePhotoStatus photoQuality)
1119 {
1120     static const string HIGH_QUALITY_STRING = "high";
1121     static const string LOW_QUALITY_STRING = "low";
1122     if (photoQuality != MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS &&
1123         photoQuality != MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
1124         NAPI_ERR_LOG("Invalid photo quality: %{public}d", static_cast<int>(photoQuality));
1125         return HIGH_QUALITY_STRING;
1126     }
1127 
1128     return (photoQuality == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) ? HIGH_QUALITY_STRING :
1129         LOW_QUALITY_STRING;
1130 }
1131 
GetInfoMapNapiValue(napi_env env,AssetHandler * assetHandler)1132 static napi_value GetInfoMapNapiValue(napi_env env, AssetHandler* assetHandler)
1133 {
1134     napi_status status;
1135     napi_value mapNapiValue {nullptr};
1136     status = napi_create_map(env, &mapNapiValue);
1137     CHECK_COND_RET(status == napi_ok && mapNapiValue != nullptr, nullptr,
1138         "Failed to create map napi value, napi status: %{public}d", static_cast<int>(status));
1139 
1140     napi_value qualityInfo {nullptr};
1141     status = napi_create_string_utf8(env, PhotoQualityToString(assetHandler->photoQuality).c_str(),
1142         NAPI_AUTO_LENGTH, &qualityInfo);
1143     CHECK_COND_RET(status == napi_ok && qualityInfo != nullptr, nullptr,
1144         "Failed to create quality string, napi status: %{public}d", static_cast<int>(status));
1145 
1146     status = napi_set_named_property(env, mapNapiValue, "quality", qualityInfo);
1147     CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set quality property, napi status: %{public}d",
1148         static_cast<int>(status));
1149 
1150     status = napi_map_set_named_property(env, mapNapiValue, "quality", qualityInfo);
1151     CHECK_COND_RET(status == napi_ok, nullptr, "Failed to set quality map key-value, napi status: %{public}d",
1152         static_cast<int>(status));
1153 
1154     return mapNapiValue;
1155 }
1156 
GetNapiValueOfMedia(napi_env env,const std::shared_ptr<NapiMediaAssetDataHandler> & dataHandler,bool & isPicture)1157 static napi_value GetNapiValueOfMedia(napi_env env, const std::shared_ptr<NapiMediaAssetDataHandler>& dataHandler,
1158     bool& isPicture)
1159 {
1160     NAPI_DEBUG_LOG("GetNapiValueOfMedia");
1161     napi_value napiValueOfMedia = nullptr;
1162     if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_ARRAY_BUFFER) {
1163         MediaAssetManagerNapi::GetByteArrayNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
1164             dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env);
1165     } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_IMAGE_SOURCE) {
1166         MediaAssetManagerNapi::GetImageSourceNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
1167             dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env);
1168     } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_TARGET_PATH) {
1169         WriteData param;
1170         param.compatibleMode = dataHandler->GetCompatibleMode();
1171         param.destUri = dataHandler->GetDestUri();
1172         param.requestUri = dataHandler->GetRequestUri();
1173         param.env = env;
1174         param.isSource = dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE;
1175         MediaAssetManagerNapi::WriteDataToDestPath(param, napiValueOfMedia, dataHandler->GetRequestId());
1176     } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_MOVING_PHOTO) {
1177         napiValueOfMedia = MovingPhotoNapi::NewMovingPhotoNapi(
1178             env, dataHandler->GetRequestUri(), dataHandler->GetSourceMode());
1179     } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_PICTURE) {
1180         MediaAssetManagerNapi::GetPictureNapiObject(dataHandler->GetRequestUri(), napiValueOfMedia,
1181             dataHandler->GetSourceMode() == SourceMode::ORIGINAL_MODE, env, isPicture);
1182     } else {
1183         NAPI_ERR_LOG("source mode type invalid");
1184     }
1185     return napiValueOfMedia;
1186 }
1187 
IsSaveCallbackInfoByTranscoder(napi_value napiValueOfMedia,napi_env env,AssetHandler * assetHandler,napi_value napiValueOfInfoMap)1188 bool IsSaveCallbackInfoByTranscoder(napi_value napiValueOfMedia, napi_env env, AssetHandler *assetHandler,
1189     napi_value napiValueOfInfoMap)
1190 {
1191     auto dataHandler = assetHandler->dataHandler;
1192     if (dataHandler == nullptr) {
1193         NAPI_ERR_LOG("data handler is nullptr");
1194         return false;
1195     }
1196     if (napiValueOfMedia == nullptr) {
1197         napi_get_undefined(env, &napiValueOfMedia);
1198     }
1199     bool isTranscoder;
1200     if (!isTranscoderMap_.Find(assetHandler->requestId, isTranscoder)) {
1201         NAPI_INFO_LOG("not find key from map");
1202         isTranscoder = false;
1203     }
1204     NAPI_INFO_LOG("IsSaveCallbackInfoByTranscoder isTranscoder_ %{public}d", isTranscoder);
1205     if (isTranscoder) {
1206         onPreparedResult_.EnsureInsert(assetHandler->requestId, assetHandler);
1207         onPreparedResultValue_.EnsureInsert(assetHandler->requestId, napiValueOfMedia);
1208         return true;
1209     }
1210     dataHandler->JsOnDataPrepared(env, napiValueOfMedia, napiValueOfInfoMap);
1211     return false;
1212 }
1213 
SavePicture(std::string & fileUri)1214 static void SavePicture(std::string &fileUri)
1215 {
1216     std::string uriStr = PATH_SAVE_PICTURE;
1217     std::string tempStr = fileUri.substr(PhotoColumn::PHOTO_URI_PREFIX.length());
1218     std::size_t index = tempStr.find("/");
1219     std::string fileId = tempStr.substr(0, index);
1220     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
1221     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, fileId);
1222     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, IMAGE_FILE_TYPE, "1");
1223     MediaLibraryNapiUtils::UriAppendKeyValue(uriStr, "uri", fileUri);
1224     Uri uri(uriStr);
1225     DataShare::DataShareValuesBucket valuesBucket;
1226     valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
1227     DataShare::DataSharePredicates predicate;
1228     UserFileClient::Update(uri, predicate, valuesBucket);
1229 }
1230 
OnDataPrepared(napi_env env,napi_value cb,void * context,void * data)1231 void MediaAssetManagerNapi::OnDataPrepared(napi_env env, napi_value cb, void *context, void *data)
1232 {
1233     NAPI_INFO_LOG("Begin OnDataPrepared.");
1234     AssetHandler *assetHandler = reinterpret_cast<AssetHandler *>(data);
1235     CHECK_NULL_PTR_RETURN_VOID(assetHandler, "assetHandler is nullptr");
1236     auto dataHandler = assetHandler->dataHandler;
1237     if (dataHandler == nullptr) {
1238         NAPI_ERR_LOG("data handler is nullptr");
1239         DeleteAssetHandlerSafe(assetHandler, env);
1240         return;
1241     }
1242 
1243     NotifyMode notifyMode = dataHandler->GetNotifyMode();
1244     if (notifyMode == NotifyMode::FAST_NOTIFY) {
1245         AssetHandler *tmp;
1246         if (!inProcessFastRequests.Find(assetHandler->requestId, tmp)) {
1247             NAPI_ERR_LOG("The request has been canceled");
1248             DeleteAssetHandlerSafe(assetHandler, env);
1249             return;
1250         }
1251     }
1252 
1253     napi_value napiValueOfInfoMap = nullptr;
1254     if (assetHandler->needsExtraInfo) {
1255         napiValueOfInfoMap = GetInfoMapNapiValue(env, assetHandler);
1256         if (napiValueOfInfoMap == nullptr) {
1257             NAPI_ERR_LOG("Failed to get info map");
1258             napi_get_undefined(env, &napiValueOfInfoMap);
1259         }
1260     }
1261     bool isPicture = true;
1262     if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_ARRAY_BUFFER ||
1263         dataHandler->GetReturnDataType() == ReturnDataType::TYPE_IMAGE_SOURCE) {
1264         string uri = dataHandler->GetRequestUri();
1265         SavePicture(uri);
1266     }
1267     napi_value napiValueOfMedia = assetHandler->isError ? nullptr : GetNapiValueOfMedia(env, dataHandler, isPicture);
1268     if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_PICTURE) {
1269         if (isPicture) {
1270             dataHandler->JsOnDataPrepared(env, napiValueOfMedia, nullptr, napiValueOfInfoMap);
1271         } else {
1272             if (napiValueOfMedia == nullptr) {
1273                 napi_get_undefined(env, &napiValueOfMedia);
1274             }
1275             dataHandler->JsOnDataPrepared(env, nullptr, napiValueOfMedia, napiValueOfInfoMap);
1276         }
1277     } else {
1278         if (IsSaveCallbackInfoByTranscoder(napiValueOfMedia, env, assetHandler, napiValueOfInfoMap)) {
1279             return;
1280         }
1281     }
1282     DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
1283     NAPI_DEBUG_LOG("delete assetHandler");
1284     DeleteAssetHandlerSafe(assetHandler, env);
1285 }
1286 
CallPreparedCallbackAfterProgress(napi_env env,ProgressHandler * progressHandler,napi_value napiValueOfMedia)1287 void CallPreparedCallbackAfterProgress(napi_env env, ProgressHandler *progressHandler, napi_value napiValueOfMedia)
1288 {
1289     MediaCallTranscode::CallTranscodeRelease(progressHandler->requestId);
1290     MediaAssetManagerNapi::progressHandlerMap_.Erase(progressHandler->requestId);
1291     AssetHandler *assetHandler = nullptr;
1292     if (!onPreparedResult_.Find(progressHandler->requestId, assetHandler)) {
1293         NAPI_ERR_LOG("not find key from map");
1294         return;
1295     }
1296     onPreparedResult_.Erase(progressHandler->requestId);
1297     auto dataHandler = assetHandler->dataHandler;
1298     if (dataHandler == nullptr) {
1299         NAPI_ERR_LOG("data handler is nullptr");
1300         DeleteAssetHandlerSafe(assetHandler, env);
1301         return;
1302     }
1303 
1304     NotifyMode notifyMode = dataHandler->GetNotifyMode();
1305     napi_value napiValueOfInfoMap = nullptr;
1306     if (assetHandler->needsExtraInfo) {
1307         napiValueOfInfoMap = GetInfoMapNapiValue(env, assetHandler);
1308         if (napiValueOfInfoMap == nullptr) {
1309             NAPI_ERR_LOG("Failed to get info map");
1310             napi_get_undefined(env, &napiValueOfInfoMap);
1311         }
1312     }
1313     dataHandler->JsOnDataPrepared(env, napiValueOfMedia, napiValueOfInfoMap);
1314     NAPI_INFO_LOG("delete assetHandler");
1315     DeleteProcessHandlerSafe(progressHandler, env);
1316     DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
1317     DeleteAssetHandlerSafe(assetHandler, env);
1318 }
1319 
CallProgressCallback(napi_env env,ProgressHandler & progressHandler,int32_t process)1320 void CallProgressCallback(napi_env env, ProgressHandler &progressHandler, int32_t process)
1321 {
1322     napi_value result;
1323     napi_status status = napi_create_int32(env, process, &result);
1324     if (status != napi_ok) {
1325         NAPI_ERR_LOG("OnProgress napi_create_int32 fail");
1326     }
1327     napi_value callback;
1328     status = napi_get_reference_value(env, progressHandler.progressRef, &callback);
1329     if (status != napi_ok) {
1330         NAPI_ERR_LOG("OnProgress napi_get_reference_value fail, napi status: %{public}d",
1331             static_cast<int>(status));
1332         DeleteProcessHandlerSafe(&progressHandler, env);
1333         return;
1334     }
1335     napi_value jsOnProgress;
1336     status = napi_get_named_property(env, callback, ON_PROGRESS_FUNC, &jsOnProgress);
1337     if (status != napi_ok) {
1338         NAPI_ERR_LOG("jsOnProgress napi_get_named_property fail, napi status: %{public}d",
1339             static_cast<int>(status));
1340         DeleteProcessHandlerSafe(&progressHandler, env);
1341         return;
1342     }
1343     constexpr size_t maxArgs = 1;
1344     napi_value argv[maxArgs];
1345     size_t argc = ARGS_ONE;
1346     argv[PARAM0] = result;
1347     argc = ARGS_ONE;
1348     napi_value promise;
1349     status = napi_call_function(env, nullptr, jsOnProgress, argc, argv, &promise);
1350     if (status != napi_ok) {
1351         NAPI_ERR_LOG("call js function failed %{public}d", static_cast<int32_t>(status));
1352         NapiError::ThrowError(env, JS_INNER_FAIL, "calling onDataPrepared failed");
1353     }
1354     NAPI_INFO_LOG("CallProgressCallback process %{public}d", process);
1355 }
1356 
OnProgress(napi_env env,napi_value cb,void * context,void * data)1357 void MediaAssetManagerNapi::OnProgress(napi_env env, napi_value cb, void *context, void *data)
1358 {
1359     ProgressHandler *progressHandler = reinterpret_cast<ProgressHandler *>(data);
1360     if (progressHandler == nullptr) {
1361         NAPI_ERR_LOG("progressHandler handler is nullptr");
1362         DeleteProcessHandlerSafe(progressHandler, env);
1363         return;
1364     }
1365     int32_t process = progressHandler->retProgressValue.progress;
1366     int32_t type = progressHandler->retProgressValue.type;
1367 
1368     if (type == INFO_TYPE_TRANSCODER_COMPLETED || type == INFO_TYPE_ERROR) {
1369         bool isTranscoder;
1370         if (isTranscoderMap_.Find(progressHandler->requestId, isTranscoder)) {
1371             isTranscoderMap_.Erase(progressHandler->requestId);
1372         }
1373 
1374         napi_value napiValueOfMedia;
1375         if (onPreparedResultValue_.Find(progressHandler->requestId, napiValueOfMedia)) {
1376             onPreparedResultValue_.Erase(progressHandler->requestId);
1377         }
1378         if (type == INFO_TYPE_ERROR) {
1379             napi_get_boolean(env, false, &napiValueOfMedia);
1380         }
1381         NAPI_INFO_LOG("CallPreparedCallbackAfterProgress type %{public}d", type);
1382         CallPreparedCallbackAfterProgress(env, progressHandler, napiValueOfMedia);
1383         return;
1384     }
1385     if (progressHandler->progressRef == nullptr) {
1386         NAPI_INFO_LOG("progressHandler->progressRef == nullptr");
1387         return;
1388     }
1389     CallProgressCallback(env, *progressHandler, process);
1390 }
1391 
NotifyMediaDataPrepared(AssetHandler * assetHandler)1392 void MediaAssetManagerNapi::NotifyMediaDataPrepared(AssetHandler *assetHandler)
1393 {
1394     napi_status status = napi_call_threadsafe_function(assetHandler->threadSafeFunc, (void *)assetHandler,
1395         napi_tsfn_blocking);
1396     if (status != napi_ok) {
1397         NAPI_ERR_LOG("napi_call_threadsafe_function fail, %{public}d", static_cast<int32_t>(status));
1398         napi_release_threadsafe_function(assetHandler->threadSafeFunc, napi_tsfn_release);
1399         DeleteAssetHandlerSafe(assetHandler, nullptr);
1400     }
1401 }
1402 
OnChange(const ChangeInfo & changeInfo)1403 void MultiStagesTaskObserver::OnChange(const ChangeInfo &changeInfo)
1404 {
1405     if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_UPDATE)) {
1406         NAPI_DEBUG_LOG("ignore notify change, type: %{public}d", changeInfo.changeType_);
1407         return;
1408     }
1409     for (auto &uri : changeInfo.uris_) {
1410         string uriString = uri.ToString();
1411         NAPI_INFO_LOG("Onchange, before onDataPrepared, uri: %{public}s", uriString.c_str());
1412         std::string photoId = "";
1413         if (uriString.find(HIGH_TEMPERATURE) == std::string::npos &&
1414             MediaAssetManagerNapi::QueryPhotoStatus(fileId_, uriString, photoId, true, -1) !=
1415             MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
1416             NAPI_ERR_LOG("requested data not prepared");
1417             continue;
1418         }
1419         std::string uriHightemp = uriString;
1420         auto index = uriString.find(HIGH_TEMPERATURE);
1421         uriString = uriString.substr(0, index);
1422 
1423         std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
1424         if (inProcessUriMap.find(uriString) == inProcessUriMap.end()) {
1425             NAPI_INFO_LOG("current uri does not in process, uri: %{public}s", uriString.c_str());
1426             return;
1427         }
1428         std::map<std::string, AssetHandler *> assetHandlers = inProcessUriMap[uriString];
1429         for (auto handler : assetHandlers) {
1430             DeleteRecordNoLock(handler.second->requestUri, handler.second->requestId);
1431         }
1432         for (auto handler : assetHandlers) {
1433             auto assetHandler = handler.second;
1434             if (uriHightemp.find(HIGH_TEMPERATURE) != std::string::npos) {
1435                 NAPI_INFO_LOG("OnChange receive high_temperature");
1436                 assetHandler->isError = true;
1437             }
1438             assetHandler->photoQuality = MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
1439             MediaAssetManagerNapi::NotifyMediaDataPrepared(assetHandler);
1440         }
1441     }
1442 }
1443 
NotifyOnProgress(int32_t type,int32_t progress,std::string requestId)1444 void MediaAssetManagerNapi::NotifyOnProgress(int32_t type, int32_t progress, std::string requestId)
1445 {
1446     NAPI_DEBUG_LOG("NotifyOnProgress start %{public}d,type %{public}d", progress, type);
1447     ProgressHandler *progressHandler = nullptr;
1448     if (!MediaAssetManagerNapi::progressHandlerMap_.Find(requestId, progressHandler)) {
1449         NAPI_ERR_LOG("not find key from map");
1450         return;
1451     }
1452     if (progressHandler == nullptr) {
1453         NAPI_ERR_LOG("ProgressHandler is nullptr.");
1454         return;
1455     }
1456     progressHandler->retProgressValue.progress = progress;
1457     progressHandler->retProgressValue.type = type;
1458 
1459     napi_status status = napi_acquire_threadsafe_function(progressHandler->progressFunc);
1460     if (status != napi_ok) {
1461         NAPI_ERR_LOG("napi_acquire_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
1462         return;
1463     }
1464     status = napi_call_threadsafe_function(progressHandler->progressFunc, (void *)progressHandler, napi_tsfn_blocking);
1465     if (status != napi_ok) {
1466         NAPI_ERR_LOG("napi_call_threadsafe_function fail, status: %{public}d", static_cast<int32_t>(status));
1467         DeleteProcessHandlerSafe(progressHandler, progressHandler->env);
1468         return;
1469     }
1470 }
1471 
GetImageSourceNapiObject(const std::string & fileUri,napi_value & imageSourceNapiObj,bool isSource,napi_env env)1472 void MediaAssetManagerNapi::GetImageSourceNapiObject(const std::string &fileUri, napi_value &imageSourceNapiObj,
1473     bool isSource, napi_env env)
1474 {
1475     if (env == nullptr) {
1476         NAPI_ERR_LOG(" create image source object failed, need to initialize js env");
1477         return;
1478     }
1479     napi_value tempImageSourceNapi;
1480     ImageSourceNapi::CreateImageSourceNapi(env, &tempImageSourceNapi);
1481     ImageSourceNapi* imageSourceNapi = nullptr;
1482     napi_unwrap(env, tempImageSourceNapi, reinterpret_cast<void**>(&imageSourceNapi));
1483     if (imageSourceNapi == nullptr) {
1484         NAPI_ERR_LOG("unwrap image napi object failed");
1485         return;
1486     }
1487     std::string tmpUri = fileUri;
1488     if (isSource) {
1489         MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
1490         NAPI_INFO_LOG("request source image's imageSource");
1491     }
1492     Uri uri(tmpUri);
1493     int fd = UserFileClient::OpenFile(uri, "r");
1494     if (fd < 0) {
1495         NAPI_ERR_LOG("get image fd failed, errno: %{public}d", errno);
1496         return;
1497     }
1498 
1499     SourceOptions opts;
1500     uint32_t errCode = 0;
1501     auto nativeImageSourcePtr = ImageSource::CreateImageSource(fd, opts, errCode);
1502     close(fd);
1503     if (nativeImageSourcePtr == nullptr) {
1504         NAPI_ERR_LOG("get ImageSource::CreateImageSource failed nullptr, errCode:%{public}d", errCode);
1505         return;
1506     }
1507     imageSourceNapi->SetNativeImageSource(std::move(nativeImageSourcePtr));
1508     imageSourceNapiObj = tempImageSourceNapi;
1509 }
1510 
GetPictureNapiObject(const std::string & fileUri,napi_value & pictureNapiObj,bool isSource,napi_env env,bool & isPicture)1511 void MediaAssetManagerNapi::GetPictureNapiObject(const std::string &fileUri, napi_value &pictureNapiObj,
1512     bool isSource, napi_env env,  bool& isPicture)
1513 {
1514     if (env == nullptr) {
1515         NAPI_ERR_LOG(" create image source object failed, need to initialize js env");
1516         return;
1517     }
1518     NAPI_DEBUG_LOG("GetPictureNapiObject");
1519 
1520     std::string tempStr = fileUri.substr(PhotoColumn::PHOTO_URI_PREFIX.length());
1521     std::size_t index = tempStr.find("/");
1522     std::string fileId = tempStr.substr(0, index);
1523     auto pic = PictureHandlerClient::RequestPicture(std::atoi(fileId.c_str()));
1524     if (pic == nullptr) {
1525         NAPI_ERR_LOG("picture is null");
1526         isPicture = false;
1527         GetImageSourceNapiObject(fileUri, pictureNapiObj, isSource, env);
1528         return;
1529     }
1530     NAPI_ERR_LOG("picture is not null");
1531     napi_value tempPictureNapi;
1532     PictureNapi::CreatePictureNapi(env, &tempPictureNapi);
1533     PictureNapi* pictureNapi = nullptr;
1534     napi_unwrap(env, tempPictureNapi, reinterpret_cast<void**>(&pictureNapi));
1535     if (pictureNapi == nullptr) {
1536         NAPI_ERR_LOG("GetPictureNapiObject unwrap image napi object failed");
1537         return;
1538     }
1539     pictureNapi->SetNativePicture(pic);
1540     pictureNapiObj = tempPictureNapi;
1541 }
1542 
1543 
GetByteArrayNapiObject(const std::string & requestUri,napi_value & arrayBuffer,bool isSource,napi_env env)1544 void MediaAssetManagerNapi::GetByteArrayNapiObject(const std::string &requestUri, napi_value &arrayBuffer,
1545     bool isSource, napi_env env)
1546 {
1547     if (env == nullptr) {
1548         NAPI_ERR_LOG("create byte array object failed, need to initialize js env");
1549         return;
1550     }
1551 
1552     std::string tmpUri = requestUri;
1553     if (isSource) {
1554         MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
1555     }
1556     Uri uri(tmpUri);
1557     int imageFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_READONLY);
1558     if (imageFd < 0) {
1559         NAPI_ERR_LOG("get image fd failed, %{public}d", errno);
1560         return;
1561     }
1562     ssize_t imgLen = lseek(imageFd, 0, SEEK_END);
1563     void* buffer = nullptr;
1564     if (napi_create_arraybuffer(env, imgLen, &buffer, &arrayBuffer) != napi_ok) {
1565         NAPI_ERR_LOG("create napi arraybuffer failed");
1566         close(imageFd);
1567         return;
1568     }
1569     lseek(imageFd, 0, SEEK_SET);
1570     ssize_t readRet = read(imageFd, buffer, imgLen);
1571     close(imageFd);
1572     if (readRet != imgLen) {
1573         NAPI_ERR_LOG("read image failed");
1574         return;
1575     }
1576 }
1577 
IsMovingPhoto(int32_t photoSubType,int32_t effectMode,int32_t sourceMode)1578 bool IsMovingPhoto(int32_t photoSubType, int32_t effectMode, int32_t sourceMode)
1579 {
1580     return photoSubType == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO) ||
1581         (MediaLibraryNapiUtils::IsSystemApp() && sourceMode == static_cast<int32_t>(SourceMode::ORIGINAL_MODE) &&
1582         effectMode == static_cast<int32_t>(MovingPhotoEffectMode::IMAGE_ONLY));
1583 }
1584 
ParseArgsForRequestMovingPhoto(napi_env env,size_t argc,const napi_value argv[],unique_ptr<MediaAssetManagerAsyncContext> & context)1585 static napi_value ParseArgsForRequestMovingPhoto(napi_env env, size_t argc, const napi_value argv[],
1586     unique_ptr<MediaAssetManagerAsyncContext> &context)
1587 {
1588     CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_FOUR), "Invalid number of arguments");
1589 
1590     FileAssetNapi *fileAssetNapi = nullptr;
1591     CHECK_COND_WITH_MESSAGE(env,
1592         (napi_unwrap(env, argv[PARAM1], reinterpret_cast<void**>(&fileAssetNapi)) == napi_ok),
1593         "Failed to parse photo asset");
1594     CHECK_COND_WITH_MESSAGE(env, fileAssetNapi != nullptr, "Failed to parse photo asset");
1595     auto fileAssetPtr = fileAssetNapi->GetFileAssetInstance();
1596     CHECK_COND_WITH_MESSAGE(env, fileAssetPtr != nullptr, "fileAsset is null");
1597     context->photoUri = fileAssetPtr->GetUri();
1598     context->fileId = fileAssetPtr->GetId();
1599     context->returnDataType = ReturnDataType::TYPE_MOVING_PHOTO;
1600     context->hasReadPermission = HasReadPermission();
1601     context->subType = PhotoSubType::MOVING_PHOTO;
1602     context->userId = fileAssetPtr->GetUserId();
1603 
1604     CHECK_COND_WITH_MESSAGE(env,
1605         ParseArgGetRequestOption(env, argv[PARAM2], context->deliveryMode, context->sourceMode) == napi_ok,
1606         "Failed to parse request option");
1607     CHECK_COND_WITH_MESSAGE(env, IsMovingPhoto(fileAssetPtr->GetPhotoSubType(),
1608         fileAssetPtr->GetMovingPhotoEffectMode(), static_cast<int32_t>(context->sourceMode)),
1609         "Asset is not a moving photo");
1610     if (fileAssetPtr->GetUserId() != -1) {
1611         MediaFileUtils::UriAppendKeyValue(context->photoUri, "user", to_string(fileAssetPtr->GetUserId()));
1612     }
1613     if (ParseArgGetDataHandler(env, argv[PARAM3], context->dataHandler, context->needsExtraInfo) != napi_ok) {
1614         NAPI_ERR_LOG("requestMovingPhoto ParseArgGetDataHandler error");
1615         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "requestMovingPhoto ParseArgGetDataHandler error");
1616         return nullptr;
1617     }
1618 
1619     RETURN_NAPI_TRUE(env);
1620 }
1621 
JSRequestMovingPhoto(napi_env env,napi_callback_info info)1622 napi_value MediaAssetManagerNapi::JSRequestMovingPhoto(napi_env env, napi_callback_info info)
1623 {
1624     MediaLibraryTracer tracer;
1625     tracer.Start("JSRequestMovingPhoto");
1626 
1627     unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
1628     CHECK_ARGS(env, napi_get_cb_info(env, info, &(asyncContext->argc), asyncContext->argv, nullptr, nullptr),
1629         JS_INNER_FAIL);
1630     CHECK_NULLPTR_RET(ParseArgsForRequestMovingPhoto(env, asyncContext->argc, asyncContext->argv, asyncContext));
1631     CHECK_COND(env, InitUserFileClient(env, info, asyncContext->userId), JS_INNER_FAIL);
1632     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef) != napi_ok
1633             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr) != napi_ok) {
1634         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
1635         return nullptr;
1636     }
1637     if (CreateDataHandlerRef(env, asyncContext, asyncContext->dataHandlerRef2) != napi_ok
1638             || CreateOnDataPreparedThreadSafeFunc(env, asyncContext, asyncContext->onDataPreparedPtr2) != napi_ok) {
1639         NAPI_ERR_LOG("CreateDataHandlerRef or CreateOnDataPreparedThreadSafeFunc failed");
1640         return nullptr;
1641     }
1642     asyncContext->requestId = GenerateRequestId();
1643 
1644     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSRequestMovingPhoto", JSRequestExecute,
1645         JSRequestComplete);
1646 }
1647 
WriteDataToDestPath(WriteData & writeData,napi_value & resultNapiValue,std::string requestId)1648 void MediaAssetManagerNapi::WriteDataToDestPath(WriteData &writeData, napi_value &resultNapiValue,
1649     std::string requestId)
1650 {
1651     if (writeData.env == nullptr) {
1652         NAPI_ERR_LOG("create byte array object failed, need to initialize js env");
1653         return;
1654     }
1655     if (writeData.requestUri.empty() || writeData.destUri.empty()) {
1656         napi_get_boolean(writeData.env, false, &resultNapiValue);
1657         NAPI_ERR_LOG("requestUri or responseUri is nullptr");
1658         return;
1659     }
1660     std::string tmpUri = writeData.requestUri;
1661     if (writeData.isSource) {
1662         MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
1663     }
1664     Uri srcUri(tmpUri);
1665     int srcFd = UserFileClient::OpenFile(srcUri, MEDIA_FILEMODE_READONLY);
1666     if (srcFd < 0) {
1667         napi_get_boolean(writeData.env, false, &resultNapiValue);
1668         NAPI_ERR_LOG("get source file fd failed %{public}d", srcFd);
1669         return;
1670     }
1671     struct stat statSrc;
1672     if (fstat(srcFd, &statSrc) == -1) {
1673         close(srcFd);
1674         napi_get_boolean(writeData.env, false, &resultNapiValue);
1675         NAPI_DEBUG_LOG("File get stat failed, %{public}d", errno);
1676         return;
1677     }
1678     int destFd = GetFdFromSandBoxUri(writeData.destUri);
1679     if (destFd < 0) {
1680         close(srcFd);
1681         napi_get_boolean(writeData.env, false, &resultNapiValue);
1682         NAPI_ERR_LOG("get dest fd failed %{public}d", destFd);
1683         return;
1684     }
1685     NAPI_INFO_LOG("WriteDataToDestPath compatibleMode %{public}d", writeData.compatibleMode);
1686     if (writeData.compatibleMode == CompatibleMode::COMPATIBLE_FORMAT_MODE) {
1687         isTranscoderMap_.Insert(requestId, true);
1688         MediaCallTranscode::RegisterCallback(NotifyOnProgress);
1689         MediaCallTranscode::CallTranscodeHandle(writeData.env, srcFd, destFd, resultNapiValue,
1690             statSrc.st_size, requestId);
1691     } else {
1692         SendFile(writeData.env, srcFd, destFd, resultNapiValue, statSrc.st_size);
1693     }
1694     close(srcFd);
1695     close(destFd);
1696     return;
1697 }
1698 
SendFile(napi_env env,int srcFd,int destFd,napi_value & result,off_t fileSize)1699 void MediaAssetManagerNapi::SendFile(napi_env env, int srcFd, int destFd, napi_value &result, off_t fileSize)
1700 {
1701     if (srcFd < 0 || destFd < 0) {
1702         NAPI_ERR_LOG("srcFd or destFd is invalid");
1703         napi_get_boolean(env, false, &result);
1704         return;
1705     }
1706     if (sendfile(destFd, srcFd, nullptr, fileSize) == -1) {
1707         close(srcFd);
1708         close(destFd);
1709         napi_get_boolean(env, false, &result);
1710         NAPI_ERR_LOG("send file failed, %{public}d", errno);
1711         return;
1712     }
1713     napi_get_boolean(env, true, &result);
1714 }
1715 
IsFastRequestCanceled(const std::string & requestId,std::string & photoId)1716 static bool IsFastRequestCanceled(const std::string &requestId, std::string &photoId)
1717 {
1718     AssetHandler *assetHandler = nullptr;
1719     if (!inProcessFastRequests.Find(requestId, assetHandler)) {
1720         NAPI_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
1721         return false;
1722     }
1723 
1724     if (assetHandler == nullptr) {
1725         NAPI_ERR_LOG("assetHandler is nullptr.");
1726         return false;
1727     }
1728     photoId = assetHandler->photoId;
1729     inProcessFastRequests.Erase(requestId);
1730     return true;
1731 }
1732 
IsMapRecordCanceled(const std::string & requestId,std::string & photoId,napi_env env)1733 static bool IsMapRecordCanceled(const std::string &requestId, std::string &photoId, napi_env env)
1734 {
1735     AssetHandler *assetHandler = nullptr;
1736     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
1737     if (!IsInProcessInMapRecord(requestId, assetHandler)) {
1738         NAPI_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
1739         return false;
1740     }
1741 
1742     if (assetHandler == nullptr) {
1743         NAPI_ERR_LOG("assetHandler is nullptr.");
1744         return false;
1745     }
1746     photoId = assetHandler->photoId;
1747     DeleteInProcessMapRecord(assetHandler->requestUri, assetHandler->requestId);
1748     DeleteAssetHandlerSafe(assetHandler, env);
1749     return true;
1750 }
1751 
JSCancelRequest(napi_env env,napi_callback_info info)1752 napi_value MediaAssetManagerNapi::JSCancelRequest(napi_env env, napi_callback_info info)
1753 {
1754     size_t argc = ARGS_TWO;
1755     napi_value argv[ARGS_TWO];
1756     napi_value thisVar = nullptr;
1757 
1758     GET_JS_ARGS(env, info, argc, argv, thisVar);
1759     NAPI_ASSERT(env, (argc == ARGS_TWO), "requires 2 paramters");
1760 
1761     string requestId;
1762     CHECK_ARGS_THROW_INVALID_PARAM(env,
1763         MediaLibraryNapiUtils::GetParamStringWithLength(env, argv[ARGS_ONE], REQUEST_ID_MAX_LEN, requestId));
1764     std::string photoId = "";
1765     bool hasFastRequestInProcess = IsFastRequestCanceled(requestId, photoId);
1766     bool hasMapRecordInProcess = IsMapRecordCanceled(requestId, photoId, env);
1767     if (hasFastRequestInProcess || hasMapRecordInProcess) {
1768         unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
1769         asyncContext->photoId = photoId;
1770         return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSCancelRequest", JSCancelRequestExecute,
1771             JSCancelRequestComplete);
1772     }
1773     RETURN_NAPI_UNDEFINED(env);
1774 }
1775 
ParseArgsForLoadMovingPhoto(napi_env env,size_t argc,const napi_value argv[],unique_ptr<MediaAssetManagerAsyncContext> & context)1776 static napi_value ParseArgsForLoadMovingPhoto(napi_env env, size_t argc, const napi_value argv[],
1777     unique_ptr<MediaAssetManagerAsyncContext> &context)
1778 {
1779     CHECK_COND_WITH_MESSAGE(env, (argc == ARGS_THREE), "Invalid number of arguments");
1780 
1781     std::string imageFileUri;
1782     CHECK_COND_WITH_MESSAGE(env,
1783         MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[PARAM1], imageFileUri) == napi_ok,
1784         "Failed to parse image file uri");
1785     std::string videoFileUri;
1786     CHECK_COND_WITH_MESSAGE(env,
1787         MediaLibraryNapiUtils::GetParamStringPathMax(env, argv[PARAM2], videoFileUri) == napi_ok,
1788         "Failed to parse video file uri");
1789     std::string uri(imageFileUri + MOVING_PHOTO_URI_SPLIT + videoFileUri);
1790     context->photoUri = uri;
1791     RETURN_NAPI_TRUE(env);
1792 }
1793 
JSLoadMovingPhotoComplete(napi_env env,napi_status status,void * data)1794 static void JSLoadMovingPhotoComplete(napi_env env, napi_status status, void *data)
1795 {
1796     MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1797     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1798 
1799     MediaLibraryTracer tracer;
1800     tracer.Start("JSLoadMovingPhotoComplete");
1801 
1802     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1803     jsContext->status = false;
1804 
1805     if (context->error == ERR_DEFAULT) {
1806         napi_value movingPhoto = MovingPhotoNapi::NewMovingPhotoNapi(env, context->photoUri,
1807             SourceMode::EDITED_MODE);
1808         jsContext->data = movingPhoto;
1809         napi_get_undefined(env, &jsContext->error);
1810         jsContext->status = true;
1811     } else {
1812         context->HandleError(env, jsContext->error);
1813         napi_get_undefined(env, &jsContext->data);
1814     }
1815 
1816     tracer.Finish();
1817     if (context->work != nullptr) {
1818         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1819             context->work, *jsContext);
1820     }
1821     delete context;
1822 }
1823 
JSLoadMovingPhotoExecute(napi_env env,void * data)1824 static void JSLoadMovingPhotoExecute(napi_env env, void *data)
1825 {
1826 }
1827 
JSLoadMovingPhoto(napi_env env,napi_callback_info info)1828 napi_value MediaAssetManagerNapi::JSLoadMovingPhoto(napi_env env, napi_callback_info info)
1829 {
1830     unique_ptr<MediaAssetManagerAsyncContext> asyncContext = make_unique<MediaAssetManagerAsyncContext>();
1831     CHECK_ARGS(env, napi_get_cb_info(env, info, &(asyncContext->argc), asyncContext->argv, nullptr, nullptr),
1832         JS_INNER_FAIL);
1833     CHECK_NULLPTR_RET(ParseArgsForLoadMovingPhoto(env, asyncContext->argc, asyncContext->argv, asyncContext));
1834     return MediaLibraryNapiUtils::NapiCreateAsyncWork(env, asyncContext, "JSLoadMovingPhoto", JSLoadMovingPhotoExecute,
1835         JSLoadMovingPhotoComplete);
1836 }
1837 
GetFdFromSandBoxUri(const std::string & sandBoxUri)1838 int32_t MediaAssetManagerNapi::GetFdFromSandBoxUri(const std::string &sandBoxUri)
1839 {
1840     AppFileService::ModuleFileUri::FileUri destUri(sandBoxUri);
1841     string destPath = destUri.GetRealPath();
1842     if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
1843         NAPI_DEBUG_LOG("Create empty dest file in sandbox failed, path:%{private}s", destPath.c_str());
1844         return E_ERR;
1845     }
1846     string absDestPath;
1847     if (!PathToRealPath(destPath, absDestPath)) {
1848         NAPI_DEBUG_LOG("PathToRealPath failed, path:%{private}s", destPath.c_str());
1849         return E_ERR;
1850     }
1851     return MediaFileUtils::OpenFile(absDestPath, MEDIA_FILEMODE_WRITETRUNCATE);
1852 }
1853 
CreateDataHandlerRef(napi_env env,const unique_ptr<MediaAssetManagerAsyncContext> & context,napi_ref & dataHandlerRef)1854 napi_status MediaAssetManagerNapi::CreateDataHandlerRef(napi_env env,
1855     const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)
1856 {
1857     napi_status status = napi_create_reference(env, context->dataHandler, PARAM1, &dataHandlerRef);
1858     if (status != napi_ok) {
1859         dataHandlerRef = nullptr;
1860         NAPI_ERR_LOG("napi_create_reference failed");
1861         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "napi_create_reference fail");
1862     }
1863     return status;
1864 }
1865 
CreateProgressHandlerRef(napi_env env,const unique_ptr<MediaAssetManagerAsyncContext> & context,napi_ref & dataHandlerRef)1866 napi_status MediaAssetManagerNapi::CreateProgressHandlerRef(napi_env env,
1867     const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_ref &dataHandlerRef)
1868 {
1869     napi_status status = napi_create_reference(env, context->mediaAssetProgressHandler, PARAM1, &dataHandlerRef);
1870     if (status != napi_ok) {
1871         dataHandlerRef = nullptr;
1872         NAPI_ERR_LOG("napi_create_reference failed");
1873         NapiError::ThrowError(env, OHOS_INVALID_PARAM_CODE, "napi_create_reference fail");
1874     }
1875     return status;
1876 }
1877 
CreateOnDataPreparedThreadSafeFunc(napi_env env,const unique_ptr<MediaAssetManagerAsyncContext> & context,napi_threadsafe_function & threadSafeFunc)1878 napi_status MediaAssetManagerNapi::CreateOnDataPreparedThreadSafeFunc(napi_env env,
1879     const unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &threadSafeFunc)
1880 {
1881     NAPI_DEBUG_LOG("CreateOnDataPreparedThreadSafeFunc");
1882     napi_value workName = nullptr;
1883     napi_create_string_utf8(env, "Data Prepared", NAPI_AUTO_LENGTH, &workName);
1884     napi_status status = napi_create_threadsafe_function(env, context->dataHandler, NULL, workName, 0, 1,
1885         NULL, NULL, NULL, MediaAssetManagerNapi::OnDataPrepared, &threadSafeFunc);
1886     if (status != napi_ok) {
1887         NAPI_ERR_LOG("napi_create_threadsafe_function fail");
1888         threadSafeFunc = nullptr;
1889         NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
1890     }
1891     return status;
1892 }
1893 
CreateOnProgressThreadSafeFunc(napi_env env,unique_ptr<MediaAssetManagerAsyncContext> & context,napi_threadsafe_function & progressFunc)1894 napi_status MediaAssetManagerNapi::CreateOnProgressThreadSafeFunc(napi_env env,
1895     unique_ptr<MediaAssetManagerAsyncContext> &context, napi_threadsafe_function &progressFunc)
1896 {
1897     napi_value workName = nullptr;
1898     napi_create_string_utf8(env, "ProgressThread", NAPI_AUTO_LENGTH, &workName);
1899     napi_status status = napi_create_threadsafe_function(env, context->mediaAssetProgressHandler, NULL, workName, 0, 1,
1900         NULL, NULL, NULL, MediaAssetManagerNapi::OnProgress, &progressFunc);
1901     if (status != napi_ok) {
1902         NAPI_ERR_LOG("napi_create_threadsafe_function fail");
1903         progressFunc = nullptr;
1904         NapiError::ThrowError(env, JS_INNER_FAIL, "napi_create_threadsafe_function fail");
1905     }
1906     return status;
1907 }
1908 
JSRequestExecute(napi_env env,void * data)1909 void MediaAssetManagerNapi::JSRequestExecute(napi_env env, void *data)
1910 {
1911     MediaLibraryTracer tracer;
1912     tracer.Start("JSRequestExecute");
1913     MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1914     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1915     OnHandleRequestImage(env, context);
1916     if (context->subType == PhotoSubType::MOVING_PHOTO) {
1917         string uri = LOG_MOVING_PHOTO;
1918         Uri logMovingPhotoUri(uri);
1919         DataShare::DataShareValuesBucket valuesBucket;
1920         string result;
1921         valuesBucket.Put("adapted", context->returnDataType == ReturnDataType::TYPE_MOVING_PHOTO);
1922         UserFileClient::InsertExt(logMovingPhotoUri, valuesBucket, result, context->userId);
1923     }
1924 }
1925 
JSRequestVideoFileExecute(napi_env env,void * data)1926 void MediaAssetManagerNapi::JSRequestVideoFileExecute(napi_env env, void *data)
1927 {
1928     MediaLibraryTracer tracer;
1929     tracer.Start("JSRequestVideoFileExecute");
1930     MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1931     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1932     OnHandleRequestVideo(env, context);
1933     OnHandleProgress(env, context);
1934 }
1935 
JSRequestComplete(napi_env env,napi_status,void * data)1936 void MediaAssetManagerNapi::JSRequestComplete(napi_env env, napi_status, void *data)
1937 {
1938     MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1939     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1940     if (context->dataHandlerRef != nullptr) {
1941         napi_delete_reference(env, context->dataHandlerRef);
1942         context->dataHandlerRef = nullptr;
1943     }
1944     if (context->dataHandlerRef2 != nullptr) {
1945         napi_delete_reference(env, context->dataHandlerRef2);
1946         context->dataHandlerRef2 = nullptr;
1947     }
1948 
1949     MediaLibraryTracer tracer;
1950     tracer.Start("JSRequestComplete");
1951 
1952     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1953     jsContext->status = false;
1954     if (context->assetHandler) {
1955         NotifyMediaDataPrepared(context->assetHandler);
1956         context->assetHandler = nullptr;
1957     }
1958     if (context->error == ERR_DEFAULT) {
1959         napi_value requestId;
1960         napi_create_string_utf8(env, context->requestId.c_str(), NAPI_AUTO_LENGTH, &requestId);
1961         jsContext->data = requestId;
1962         napi_get_undefined(env, &jsContext->error);
1963         jsContext->status = true;
1964     } else {
1965         context->HandleError(env, jsContext->error);
1966         napi_get_undefined(env, &jsContext->data);
1967     }
1968 
1969     if (context->work != nullptr) {
1970         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
1971             context->work, *jsContext);
1972     }
1973     delete context;
1974 }
1975 
JSCancelRequestExecute(napi_env env,void * data)1976 void MediaAssetManagerNapi::JSCancelRequestExecute(napi_env env, void *data)
1977 {
1978     MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1979     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1980     MediaAssetManagerNapi::CancelProcessImage(context->photoId);
1981 }
1982 
JSCancelRequestComplete(napi_env env,napi_status,void * data)1983 void MediaAssetManagerNapi::JSCancelRequestComplete(napi_env env, napi_status, void *data)
1984 {
1985     MediaAssetManagerAsyncContext *context = static_cast<MediaAssetManagerAsyncContext*>(data);
1986     CHECK_NULL_PTR_RETURN_VOID(context, "Async context is null");
1987 
1988     MediaLibraryTracer tracer;
1989     tracer.Start("JSCancelRequestComplete");
1990 
1991     unique_ptr<JSAsyncContextOutput> jsContext = make_unique<JSAsyncContextOutput>();
1992     jsContext->status = false;
1993 
1994     if (context->error == ERR_DEFAULT) {
1995         napi_get_undefined(env, &jsContext->error);
1996         jsContext->status = true;
1997     } else {
1998         context->HandleError(env, jsContext->error);
1999     }
2000     napi_get_undefined(env, &jsContext->data);
2001 
2002     if (context->work != nullptr) {
2003         MediaLibraryNapiUtils::InvokeJSAsyncMethod(env, context->deferred, context->callbackRef,
2004             context->work, *jsContext);
2005     }
2006     delete context;
2007 }
2008 } // namespace Media
2009 } // namespace OHOS