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", ¶mCountNapi);
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, ¶mCount);
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", ¶mCountNapi);
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, ¶mCount);
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