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