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