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