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