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