1 /*
2  * Copyright (C) 2024 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 "MediaAssetManagerImpl"
17 
18 #include "media_asset_manager_impl.h"
19 
20 #include <safe_map.h>
21 #include <securec.h>
22 #include <sys/sendfile.h>
23 #include <sys/stat.h>
24 #include <uuid.h>
25 
26 #include "directory_ex.h"
27 #include "file_uri.h"
28 #include "iservice_registry.h"
29 #include "media_file_uri.h"
30 #include "media_file_utils.h"
31 #include "media_log.h"
32 #include "multistages_capture_manager.h"
33 #include "medialibrary_errno.h"
34 #include "medialibrary_bundle_manager.h"
35 #include "medialibrary_tracer.h"
36 #include "file_asset.h"
37 #include "oh_media_asset.h"
38 #include "oh_moving_photo.h"
39 #include "moving_photo.h"
40 #include "image_source_native.h"
41 #include "media_userfile_client.h"
42 
43 namespace OHOS {
44 namespace Media {
45 namespace {
46 constexpr int STORAGE_MANAGER_MANAGER_ID = 5003;
47 } // namespace
48 
49 using Uri = OHOS::Uri;
50 
51 static const std::string MEDIA_ASSET_MANAGER_CLASS = "MediaAssetManagerImpl";
52 const std::string API_VERSION = "api_version";
53 static std::mutex multiStagesCaptureLock;
54 
55 const int32_t LOW_QUALITY_IMAGE = 1;
56 const int32_t HIGH_QUALITY_IMAGE = 0;
57 
58 const uint32_t MAX_URI_SIZE = 384;
59 const std::string ERROR_REQUEST_ID = "00000000-0000-0000-0000-000000000000";
60 
61 static std::map<std::string, std::shared_ptr<MultiStagesTaskObserver>> multiStagesObserverMap;
62 static std::map<std::string, std::map<std::string, AssetHandler*>> inProcessUriMap;
63 static SafeMap<std::string, AssetHandler*> inProcessFastRequests;
64 
65 static std::shared_ptr<DataShare::DataShareHelper> sDataShareHelper_ = nullptr;
66 
67 MediaLibraryManager* MediaAssetManagerImpl::mediaLibraryManager_ = nullptr;
68 
CreateMediaAssetManager()69 std::shared_ptr<MediaAssetManager> MediaAssetManagerFactory::CreateMediaAssetManager()
70 {
71     std::shared_ptr<MediaAssetManager> impl = std::make_shared<MediaAssetManagerImpl>();
72     CHECK_AND_PRINT_LOG(impl != nullptr, "Failed to create MediaAssetManagerImpl instance.");
73 
74     return impl;
75 }
76 
MediaAssetManagerImpl()77 MediaAssetManagerImpl::MediaAssetManagerImpl()
78 {
79     MediaAssetManagerImpl::mediaLibraryManager_ = MediaLibraryManager::GetMediaLibraryManager();
80     CreateDataHelper(STORAGE_MANAGER_MANAGER_ID);
81 }
82 
~MediaAssetManagerImpl()83 MediaAssetManagerImpl::~MediaAssetManagerImpl()
84 {
85 }
86 
DeleteInProcessMapRecord(const std::string & requestUri,const std::string & requestId)87 static void DeleteInProcessMapRecord(const std::string &requestUri, const std::string &requestId)
88 {
89     MEDIA_INFO_LOG("DeleteInProcessMapRecord lock multiStagesCaptureLock");
90     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
91     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
92     if (inProcessUriMap.find(uriLocal) == inProcessUriMap.end()) {
93         return;
94     }
95 
96     std::map<std::string, AssetHandler*> assetHandlers = inProcessUriMap[uriLocal];
97     if (assetHandlers.find(requestId) == assetHandlers.end()) {
98         return;
99     }
100 
101     assetHandlers.erase(requestId);
102     if (!assetHandlers.empty()) {
103         inProcessUriMap[uriLocal] = assetHandlers;
104         return;
105     }
106 
107     inProcessUriMap.erase(uriLocal);
108 
109     if (multiStagesObserverMap.find(uriLocal) != multiStagesObserverMap.end()) {
110         sDataShareHelper_->UnregisterObserverExt(Uri(uriLocal),
111             static_cast<std::shared_ptr<DataShare::DataShareObserver>>(multiStagesObserverMap[uriLocal]));
112     }
113     multiStagesObserverMap.erase(uriLocal);
114     MEDIA_INFO_LOG("DeleteInProcessMapRecord unlock multiStagesCaptureLock");
115 }
116 
CreateAssetHandler(const std::string & photoId,const std::string & requestId,const std::string & uri,const std::string & destUri,const MediaAssetDataHandlerPtr & handler)117 static AssetHandler* CreateAssetHandler(const std::string &photoId, const std::string &requestId,
118     const std::string &uri, const std::string &destUri, const MediaAssetDataHandlerPtr &handler)
119 {
120     AssetHandler *assetHandler = new AssetHandler(photoId, requestId, uri, destUri, handler);
121     MEDIA_DEBUG_LOG("[AssetHandler create] photoId: %{public}s, requestId: %{public}s, uri: %{public}s, %{public}p.",
122         photoId.c_str(), requestId.c_str(), uri.c_str(), assetHandler);
123     return assetHandler;
124 }
125 
DeleteAssetHandlerSafe(AssetHandler * handler)126 static void DeleteAssetHandlerSafe(AssetHandler *handler)
127 {
128     if (handler != nullptr) {
129         MEDIA_DEBUG_LOG("[AssetHandler delete] %{public}p.", handler);
130         delete handler;
131         handler = nullptr;
132     }
133 }
134 
IsInProcessInMapRecord(const std::string & requestId,AssetHandler * & handler)135 static int32_t IsInProcessInMapRecord(const std::string &requestId, AssetHandler* &handler)
136 {
137     MEDIA_INFO_LOG("IsInProcessInMapRecord lock multiStagesCaptureLock");
138     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
139     for (auto record : inProcessUriMap) {
140         if (record.second.find(requestId) != record.second.end()) {
141             handler = record.second[requestId];
142             MEDIA_INFO_LOG("IsInProcessInMapRecord unlock multiStagesCaptureLock");
143             return true;
144         }
145     }
146     MEDIA_INFO_LOG("IsInProcessInMapRecord unlock multiStagesCaptureLock");
147     return false;
148 }
149 
IsFastRequestCanceled(const std::string & requestId,std::string & photoId)150 static bool IsFastRequestCanceled(const std::string &requestId, std::string &photoId)
151 {
152     AssetHandler *assetHandler = nullptr;
153     if (!inProcessFastRequests.Find(requestId, assetHandler)) {
154         MEDIA_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
155         return false;
156     }
157 
158     if (assetHandler == nullptr) {
159         MEDIA_ERR_LOG("assetHandler is nullptr.");
160         return false;
161     }
162     photoId = assetHandler->photoId;
163     inProcessFastRequests.Erase(requestId);
164     return true;
165 }
166 
IsMapRecordCanceled(const std::string & requestId,std::string & photoId)167 static bool IsMapRecordCanceled(const std::string &requestId, std::string &photoId)
168 {
169     AssetHandler *assetHandler = nullptr;
170     if (!IsInProcessInMapRecord(requestId, assetHandler)) {
171         MEDIA_ERR_LOG("requestId(%{public}s) not in progress.", requestId.c_str());
172         return false;
173     }
174 
175     if (assetHandler == nullptr) {
176         MEDIA_ERR_LOG("assetHandler is nullptr.");
177         return false;
178     }
179     photoId = assetHandler->photoId;
180     DeleteInProcessMapRecord(assetHandler->requestUri, assetHandler->requestId);
181     DeleteAssetHandlerSafe(assetHandler);
182     return true;
183 }
184 
DeleteDataHandler(NativeNotifyMode notifyMode,const std::string & requestUri,const std::string & requestId)185 static void DeleteDataHandler(NativeNotifyMode notifyMode, const std::string &requestUri, const std::string &requestId)
186 {
187     MEDIA_INFO_LOG("Rmv %{public}d, %{public}s, %{public}s", notifyMode, requestUri.c_str(), requestId.c_str());
188     if (notifyMode == NativeNotifyMode::WAIT_FOR_HIGH_QUALITY) {
189         DeleteInProcessMapRecord(requestUri, requestId);
190     }
191     inProcessFastRequests.Erase(requestId);
192 }
193 
InsertInProcessMapRecord(const std::string & requestUri,const std::string & requestId,AssetHandler * handler)194 static void InsertInProcessMapRecord(const std::string &requestUri, const std::string &requestId,
195     AssetHandler *handler)
196 {
197     MEDIA_INFO_LOG("InsertInProcessMapRecord lock multiStagesCaptureLock");
198     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
199     std::map<std::string, AssetHandler*> assetHandler;
200     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(requestUri);
201     if (inProcessUriMap.find(uriLocal) != inProcessUriMap.end()) {
202         assetHandler = inProcessUriMap[uriLocal];
203         assetHandler[requestId] = handler;
204         inProcessUriMap[uriLocal] = assetHandler;
205     } else {
206         assetHandler[requestId] = handler;
207         inProcessUriMap[uriLocal] = assetHandler;
208     }
209     MEDIA_INFO_LOG("InsertInProcessMapRecord unlock multiStagesCaptureLock");
210 }
211 
GenerateRequestId()212 static std::string GenerateRequestId()
213 {
214     uuid_t uuid;
215     uuid_generate(uuid);
216     char str[UUID_STR_LENGTH] = {};
217     uuid_unparse(uuid, str);
218     return str;
219 }
220 
InsertDataHandler(NativeNotifyMode notifyMode,const unique_ptr<RequestSourceAsyncContext> & asyncContext)221 static AssetHandler* InsertDataHandler(NativeNotifyMode notifyMode,
222     const unique_ptr<RequestSourceAsyncContext> &asyncContext)
223 {
224     std::shared_ptr<CapiMediaAssetDataHandler> mediaAssetDataHandler;
225     if (asyncContext->returnDataType == ReturnDataType::TYPE_IMAGE_SOURCE) {
226         mediaAssetDataHandler = make_shared<CapiMediaAssetDataHandler>(
227             asyncContext->onRequestImageDataPreparedHandler, asyncContext->returnDataType, asyncContext->requestUri,
228             asyncContext->destUri, asyncContext->requestOptions.sourceMode);
229         mediaAssetDataHandler->SetPhotoQuality(static_cast<int32_t>(asyncContext->photoQuality));
230     } else if (asyncContext->returnDataType == ReturnDataType::TYPE_MOVING_PHOTO) {
231         mediaAssetDataHandler = make_shared<CapiMediaAssetDataHandler>(
232             asyncContext->onRequestMovingPhotoDataPreparedHandler, asyncContext->returnDataType,
233             asyncContext->requestUri, asyncContext->destUri, asyncContext->requestOptions.sourceMode);
234         mediaAssetDataHandler->SetPhotoQuality(static_cast<int32_t>(asyncContext->photoQuality));
235     } else {
236         mediaAssetDataHandler = make_shared<CapiMediaAssetDataHandler>(
237         asyncContext->onDataPreparedHandler, asyncContext->returnDataType, asyncContext->requestUri,
238         asyncContext->destUri, asyncContext->requestOptions.sourceMode);
239     }
240 
241     mediaAssetDataHandler->SetNotifyMode(notifyMode);
242     AssetHandler *assetHandler = CreateAssetHandler(asyncContext->photoId, asyncContext->requestId,
243         asyncContext->requestUri, asyncContext->destUri, mediaAssetDataHandler);
244     MEDIA_INFO_LOG("Add %{public}d, %{private}s, %{private}s", notifyMode,
245         asyncContext->requestUri.c_str(), asyncContext->requestId.c_str());
246 
247     switch (notifyMode) {
248         case NativeNotifyMode::FAST_NOTIFY: {
249             inProcessFastRequests.EnsureInsert(asyncContext->requestId, assetHandler);
250             break;
251         }
252         case NativeNotifyMode::WAIT_FOR_HIGH_QUALITY: {
253             InsertInProcessMapRecord(asyncContext->requestUri, asyncContext->requestId, assetHandler);
254             break;
255         }
256         default:
257             break;
258     }
259 
260     return assetHandler;
261 }
262 
QueryPhotoStatus(int32_t fileId,std::string & photoId)263 MultiStagesCapturePhotoStatus MediaAssetManagerImpl::QueryPhotoStatus(int32_t fileId, std::string &photoId)
264 {
265     photoId = "";
266     if (sDataShareHelper_ == nullptr) {
267         MEDIA_ERR_LOG("Get sDataShareHelper_ failed");
268         return MultiStagesCapturePhotoStatus::QUERY_INNER_FAIL;
269     }
270     DataShare::DataSharePredicates predicates;
271     predicates.EqualTo(MediaColumn::MEDIA_ID, fileId);
272     std::vector<std::string> fetchColumn { PhotoColumn::PHOTO_QUALITY, PhotoColumn::PHOTO_ID };
273     Uri uri(PAH_QUERY_PHOTO);
274     DataShare::DatashareBusinessError errCode;
275     auto resultSet = sDataShareHelper_->Query(uri, predicates, fetchColumn, &errCode);
276     if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
277         MEDIA_ERR_LOG("Query resultSet is nullptr");
278         return MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
279     }
280 
281     int indexOfPhotoId = -1;
282     resultSet->GetColumnIndex(PhotoColumn::PHOTO_ID, indexOfPhotoId);
283     resultSet->GetString(indexOfPhotoId, photoId);
284 
285     int columnIndexQuality = -1;
286     resultSet->GetColumnIndex(PhotoColumn::PHOTO_QUALITY, columnIndexQuality);
287     int currentPhotoQuality = HIGH_QUALITY_IMAGE;
288     resultSet->GetInt(columnIndexQuality, currentPhotoQuality);
289     if (currentPhotoQuality == LOW_QUALITY_IMAGE) {
290         MEDIA_ERR_LOG("Query photo status : lowQuality");
291         return MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS;
292     }
293     MEDIA_ERR_LOG("Query photo status quality: %{public}d", currentPhotoQuality);
294     return MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
295 }
296 
NotifyImageDataPrepared(AssetHandler * assetHandler)297 bool MediaAssetManagerImpl::NotifyImageDataPrepared(AssetHandler *assetHandler)
298 {
299     CHECK_AND_RETURN_RET_LOG(assetHandler != nullptr, false, "assetHandler is nullptr");
300 
301     std::lock_guard<std::mutex> lock(assetHandler->mutex_);
302     auto dataHandler = assetHandler->dataHandler;
303     if (dataHandler == nullptr) {
304         MEDIA_ERR_LOG("Data handler is nullptr");
305         DeleteAssetHandlerSafe(assetHandler);
306         return false;
307     }
308 
309     NativeNotifyMode notifyMode = dataHandler->GetNotifyMode();
310     if (notifyMode == NativeNotifyMode::FAST_NOTIFY) {
311         AssetHandler *tmp;
312         if (!inProcessFastRequests.Find(assetHandler->requestId, tmp)) {
313             MEDIA_ERR_LOG("The request has been canceled");
314             DeleteAssetHandlerSafe(assetHandler);
315             return false;
316         }
317     }
318 
319     int32_t writeResult = E_OK;
320     if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_TARGET_FILE) {
321         writeResult = MediaAssetManagerImpl::WriteFileToPath(dataHandler->GetRequestUri(), dataHandler->GetDestUri(),
322             dataHandler->GetSourceMode() == NativeSourceMode::ORIGINAL_MODE);
323         Native_RequestId requestId;
324         strncpy_s(requestId.requestId, UUID_STR_LENGTH, assetHandler->requestId.c_str(), UUID_STR_LENGTH);
325         if (dataHandler->onDataPreparedHandler_ != nullptr) {
326             dataHandler->onDataPreparedHandler_(writeResult, requestId);
327         }
328     } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_IMAGE_SOURCE) {
329         MediaLibrary_RequestId requestId;
330         strncpy_s(requestId.requestId, UUID_STR_LENGTH, assetHandler->requestId.c_str(), UUID_STR_LENGTH);
331         if (dataHandler->onRequestImageDataPreparedHandler_ != nullptr) {
332             int32_t photoQuality = static_cast<int32_t>(MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS);
333             MediaLibrary_MediaQuality quality = (dataHandler->GetPhotoQuality() == photoQuality)
334                 ? MEDIA_LIBRARY_QUALITY_FULL
335                 : MEDIA_LIBRARY_QUALITY_FAST;
336             auto imageSource = CreateImageSource(assetHandler->requestId, dataHandler->GetRequestUri());
337             auto status = imageSource != nullptr ? MEDIA_LIBRARY_OK : MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR;
338             dataHandler->onRequestImageDataPreparedHandler_(status, requestId, quality,
339                 MEDIA_LIBRARY_COMPRESSED, imageSource);
340         }
341     } else if (dataHandler->GetReturnDataType() == ReturnDataType::TYPE_MOVING_PHOTO) {
342         MediaLibrary_RequestId requestId;
343         strncpy_s(requestId.requestId, UUID_STR_LENGTH, assetHandler->requestId.c_str(), UUID_STR_LENGTH);
344         if (dataHandler->onRequestMovingPhotoDataPreparedHandler_ != nullptr) {
345             int32_t photoQuality = static_cast<int32_t>(MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS);
346             MediaLibrary_MediaQuality quality = (dataHandler->GetPhotoQuality() == photoQuality)
347                 ? MEDIA_LIBRARY_QUALITY_FULL
348                 : MEDIA_LIBRARY_QUALITY_FAST;
349             auto movingPhotoImpl = MovingPhotoFactory::CreateMovingPhoto(assetHandler->requestUri);
350             auto movingPhoto = new OH_MovingPhoto(movingPhotoImpl);
351             auto status = movingPhoto != nullptr ? MEDIA_LIBRARY_OK : MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR;
352             dataHandler->onRequestMovingPhotoDataPreparedHandler_(status, requestId, quality,
353                 MEDIA_LIBRARY_COMPRESSED, movingPhoto);
354         }
355     } else {
356         MEDIA_ERR_LOG("Return mode type invalid %{public}d", dataHandler->GetReturnDataType());
357         return false;
358     }
359     DeleteDataHandler(notifyMode, assetHandler->requestUri, assetHandler->requestId);
360     MEDIA_DEBUG_LOG("Delete assetHandler");
361     DeleteAssetHandlerSafe(assetHandler);
362     return true;
363 }
364 
CreateDataHelper(int32_t systemAbilityId)365 void MediaAssetManagerImpl::CreateDataHelper(int32_t systemAbilityId)
366 {
367     auto saManager = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
368     if (saManager == nullptr) {
369         MEDIA_ERR_LOG("Get system ability mgr failed.");
370         return;
371     }
372     auto remoteObj = saManager->GetSystemAbility(systemAbilityId);
373     if (remoteObj == nullptr) {
374         MEDIA_ERR_LOG("GetSystemAbility Service Failed.");
375         return;
376     }
377     if (sDataShareHelper_ == nullptr) {
378         const sptr<IRemoteObject> &token = remoteObj;
379         sDataShareHelper_ = DataShare::DataShareHelper::Creator(token, MEDIALIBRARY_DATA_URI);
380         if (sDataShareHelper_ == nullptr) {
381             MEDIA_ERR_LOG("Create DataShareHelper failed.");
382             return;
383         }
384     }
385     MediaAssetManagerImpl::mediaLibraryManager_->InitMediaLibraryManager(remoteObj);
386     UserFileClient::Init(remoteObj);
387     MEDIA_INFO_LOG("InitMediaLibraryManager success!");
388 }
389 
NativeRequestImage(const char * photoUri,const NativeRequestOptions & requestOptions,const char * destUri,const NativeOnDataPrepared & callback)390 std::string MediaAssetManagerImpl::NativeRequestImage(const char* photoUri,
391     const NativeRequestOptions &requestOptions, const char* destUri, const NativeOnDataPrepared &callback)
392 {
393     if (photoUri == nullptr || destUri == nullptr || callback == nullptr) {
394         MEDIA_ERR_LOG("Request image input params are invalid.");
395         return ERROR_REQUEST_ID;
396     }
397 
398     MediaLibraryTracer tracer;
399     tracer.Start("NativeRequestImage");
400 
401     std::unique_ptr<RequestSourceAsyncContext> asyncContext = std::make_unique<RequestSourceAsyncContext>();
402     asyncContext->callingPkgName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
403     asyncContext->destUri = std::string(destUri);
404     asyncContext->requestUri = std::string(photoUri);
405     asyncContext->displayName = MediaFileUtils::GetFileName(asyncContext->requestUri);
406     asyncContext->fileId = std::stoi(MediaFileUtils::GetIdFromUri(asyncContext->requestUri));
407     asyncContext->requestOptions.deliveryMode = requestOptions.deliveryMode;
408     asyncContext->requestOptions.sourceMode = NativeSourceMode::EDITED_MODE;
409     asyncContext->returnDataType = ReturnDataType::TYPE_TARGET_FILE;
410     asyncContext->onDataPreparedHandler = callback;
411 
412     if (asyncContext->requestUri.length() > MAX_URI_SIZE || asyncContext->destUri.length() > MAX_URI_SIZE) {
413         MEDIA_ERR_LOG("Request image uri lens out of limit requestUri lens: %{public}zu, destUri lens: %{public}zu",
414             asyncContext->requestUri.length(), asyncContext->destUri.length());
415         return ERROR_REQUEST_ID;
416     }
417     if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_IMAGE ||
418         MediaFileUtils::GetMediaType(MediaFileUtils::GetFileName(asyncContext->destUri)) != MEDIA_TYPE_IMAGE) {
419         MEDIA_ERR_LOG("Request image file type invalid");
420         return ERROR_REQUEST_ID;
421     }
422     bool isSuccess = false;
423     asyncContext->requestId = GenerateRequestId();
424     isSuccess = OnHandleRequestImage(asyncContext);
425     if (isSuccess) {
426         MEDIA_INFO_LOG("Request image success return requestId: %{public}s", asyncContext->requestId.c_str());
427         return asyncContext->requestId;
428     } else {
429         return ERROR_REQUEST_ID;
430     }
431 }
432 
NativeRequestVideo(const char * videoUri,const NativeRequestOptions & requestOptions,const char * destUri,const NativeOnDataPrepared & callback)433 std::string MediaAssetManagerImpl::NativeRequestVideo(const char* videoUri,
434     const NativeRequestOptions &requestOptions, const char* destUri, const NativeOnDataPrepared &callback)
435 {
436     if (videoUri == nullptr || destUri == nullptr || callback == nullptr) {
437         MEDIA_ERR_LOG("Request video input params are invalid.");
438         return ERROR_REQUEST_ID;
439     }
440     MediaLibraryTracer tracer;
441     tracer.Start("NativeRequestVideo");
442 
443     std::unique_ptr<RequestSourceAsyncContext> asyncContext = std::make_unique<RequestSourceAsyncContext>();
444     asyncContext->callingPkgName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
445     asyncContext->destUri = std::string(destUri);
446     asyncContext->requestUri = std::string(videoUri);
447     asyncContext->displayName = MediaFileUtils::GetFileName(asyncContext->requestUri);
448     asyncContext->fileId = std::stoi(MediaFileUtils::GetIdFromUri(asyncContext->requestUri));
449     asyncContext->requestOptions.deliveryMode = requestOptions.deliveryMode;
450     asyncContext->requestOptions.sourceMode = NativeSourceMode::EDITED_MODE;
451     asyncContext->returnDataType = ReturnDataType::TYPE_TARGET_FILE;
452     asyncContext->onDataPreparedHandler = callback;
453 
454     if (asyncContext->requestUri.length() > MAX_URI_SIZE || asyncContext->destUri.length() > MAX_URI_SIZE) {
455         MEDIA_ERR_LOG("Request video uri lens out of limit requestUri lens: %{public}zu, destUri lens: %{public}zu",
456             asyncContext->requestUri.length(), asyncContext->destUri.length());
457         return ERROR_REQUEST_ID;
458     }
459     if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_VIDEO ||
460         MediaFileUtils::GetMediaType(MediaFileUtils::GetFileName(asyncContext->destUri)) != MEDIA_TYPE_VIDEO) {
461         MEDIA_ERR_LOG("Request video file type invalid");
462         return ERROR_REQUEST_ID;
463     }
464     bool isSuccess = false;
465     asyncContext->requestId = GenerateRequestId();
466     isSuccess = OnHandleRequestVideo(asyncContext);
467     if (isSuccess) {
468         MEDIA_ERR_LOG("Request video success return requestId: %{public}s", asyncContext->requestId.c_str());
469         return asyncContext->requestId;
470     } else {
471         return ERROR_REQUEST_ID;
472     }
473 }
474 
NativeCancelRequest(const std::string & requestId)475 bool MediaAssetManagerImpl::NativeCancelRequest(const std::string &requestId)
476 {
477     if (requestId.empty()) {
478         MEDIA_ERR_LOG("NativeCancel request id is empty.");
479         return false;
480     }
481 
482     std::string photoId = "";
483     bool hasFastRequestInProcess = IsFastRequestCanceled(requestId, photoId);
484     bool hasMapRecordInProcess = IsMapRecordCanceled(requestId, photoId);
485     if (hasFastRequestInProcess || hasMapRecordInProcess) {
486         MultiStagesPhotoCaptureManager::GetInstance().CancelProcessRequest(photoId);
487     } else {
488         MEDIA_ERR_LOG("NativeCancel requestId(%{public}s) not in progress.", requestId.c_str());
489         return false;
490     }
491     return true;
492 }
493 
NativeRequestImageSource(OH_MediaAsset * mediaAsset,NativeRequestOptions requestOptions,MediaLibrary_RequestId * requestId,OH_MediaLibrary_OnImageDataPrepared callback)494 MediaLibrary_ErrorCode MediaAssetManagerImpl::NativeRequestImageSource(OH_MediaAsset* mediaAsset,
495     NativeRequestOptions requestOptions, MediaLibrary_RequestId* requestId,
496     OH_MediaLibrary_OnImageDataPrepared callback)
497 {
498     MEDIA_INFO_LOG("MediaAssetManagerImpl::NativeRequestImageSource Called");
499     std::shared_ptr<FileAsset> fileAsset_ = mediaAsset->mediaAsset_->GetFileAssetInstance();
500     MediaLibraryTracer tracer;
501     tracer.Start("NativeRequestImageSource");
502 
503     std::unique_ptr<RequestSourceAsyncContext> asyncContext = std::make_unique<RequestSourceAsyncContext>();
504     asyncContext->callingPkgName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
505     asyncContext->requestUri = fileAsset_->GetUri();
506     asyncContext->displayName = fileAsset_->GetDisplayName();
507     asyncContext->fileId = fileAsset_->GetId();
508     asyncContext->requestOptions.deliveryMode = requestOptions.deliveryMode;
509     asyncContext->requestOptions.sourceMode = NativeSourceMode::EDITED_MODE;
510     asyncContext->returnDataType = ReturnDataType::TYPE_IMAGE_SOURCE;
511     asyncContext->needsExtraInfo = true;
512     asyncContext->onRequestImageDataPreparedHandler = callback;
513 
514     if (sDataShareHelper_ == nullptr) {
515         CreateDataHelper(STORAGE_MANAGER_MANAGER_ID);
516         CHECK_AND_RETURN_RET_LOG(sDataShareHelper_ == nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
517             "sDataShareHelper_ is null");
518     }
519 
520     if (asyncContext->requestUri.length() > MAX_URI_SIZE) {
521         MEDIA_ERR_LOG("Request image uri lens out of limit requestUri lens: %{public}zu",
522             asyncContext->requestUri.length());
523         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (ERROR_REQUEST_ID.c_str()), UUID_STR_LENGTH);
524         return MEDIA_LIBRARY_PARAMETER_ERROR;
525     }
526 
527     if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_IMAGE) {
528         MEDIA_ERR_LOG("Request image file type invalid");
529         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (ERROR_REQUEST_ID.c_str()), UUID_STR_LENGTH);
530         return MEDIA_LIBRARY_PARAMETER_ERROR;
531     }
532 
533     bool isSuccess = false;
534     asyncContext->requestId = GenerateRequestId();
535     isSuccess = OnHandleRequestImage(asyncContext);
536     if (isSuccess) {
537         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (asyncContext->requestId.c_str()), UUID_STR_LENGTH);
538         return MEDIA_LIBRARY_OK;
539     } else {
540         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (ERROR_REQUEST_ID.c_str()), UUID_STR_LENGTH);
541         return MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED;
542     }
543 }
544 
NativeRequestMovingPhoto(OH_MediaAsset * mediaAsset,NativeRequestOptions requestOptions,MediaLibrary_RequestId * requestId,OH_MediaLibrary_OnMovingPhotoDataPrepared callback)545 MediaLibrary_ErrorCode MediaAssetManagerImpl::NativeRequestMovingPhoto(OH_MediaAsset* mediaAsset,
546     NativeRequestOptions requestOptions, MediaLibrary_RequestId* requestId,
547     OH_MediaLibrary_OnMovingPhotoDataPrepared callback)
548 {
549     std::shared_ptr<FileAsset> fileAsset_ = mediaAsset->mediaAsset_->GetFileAssetInstance();
550     MediaLibraryTracer tracer;
551     tracer.Start("NativeRequestMovingPhoto");
552 
553     std::unique_ptr<RequestSourceAsyncContext> asyncContext = std::make_unique<RequestSourceAsyncContext>();
554     asyncContext->callingPkgName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
555     asyncContext->requestUri = fileAsset_->GetUri();
556     asyncContext->fileId = fileAsset_->GetId();
557     asyncContext->displayName = fileAsset_->GetDisplayName();
558     asyncContext->requestOptions.deliveryMode = requestOptions.deliveryMode;
559     asyncContext->requestOptions.sourceMode = NativeSourceMode::EDITED_MODE;
560     asyncContext->returnDataType = ReturnDataType::TYPE_MOVING_PHOTO;
561     asyncContext->onRequestMovingPhotoDataPreparedHandler = callback;
562 
563     if (sDataShareHelper_ == nullptr) {
564         CreateDataHelper(STORAGE_MANAGER_MANAGER_ID);
565         CHECK_AND_RETURN_RET_LOG(sDataShareHelper_ == nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
566             "sDataShareHelper_ is null");
567     }
568 
569     if (asyncContext->requestUri.length() > MAX_URI_SIZE) {
570         MEDIA_ERR_LOG("Request image uri lens out of limit requestUri lens: %{public}zu",
571             asyncContext->requestUri.length());
572         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (ERROR_REQUEST_ID.c_str()), UUID_STR_LENGTH);
573         return MEDIA_LIBRARY_PARAMETER_ERROR;
574     }
575 
576     if (MediaFileUtils::GetMediaType(asyncContext->displayName) != MEDIA_TYPE_IMAGE) {
577         MEDIA_ERR_LOG("Request image file type invalid");
578         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (ERROR_REQUEST_ID.c_str()), UUID_STR_LENGTH);
579         return MEDIA_LIBRARY_PARAMETER_ERROR;
580     }
581 
582     bool isSuccess = false;
583     asyncContext->requestId = GenerateRequestId();
584     isSuccess = OnHandleRequestImage(asyncContext);
585     string uri = LOG_MOVING_PHOTO;
586     Uri logMovingPhotoUri(uri);
587     DataShare::DataShareValuesBucket valuesBucket;
588     string result;
589     valuesBucket.Put("package_name", asyncContext->callingPkgName);
590     valuesBucket.Put("adapted", asyncContext->returnDataType == ReturnDataType::TYPE_MOVING_PHOTO);
591     UserFileClient::InsertExt(logMovingPhotoUri, valuesBucket, result);
592     if (isSuccess) {
593         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (asyncContext->requestId.c_str()), UUID_STR_LENGTH);
594         return MEDIA_LIBRARY_OK;
595     } else {
596         strncpy_s(requestId->requestId, UUID_STR_LENGTH, (ERROR_REQUEST_ID.c_str()), UUID_STR_LENGTH);
597         return MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED;
598     }
599 }
600 
CreateImageSource(const std::string requestId,const std::string requestUri)601 OH_ImageSourceNative* MediaAssetManagerImpl::CreateImageSource(const std::string requestId,
602     const std::string requestUri)
603 {
604     MEDIA_INFO_LOG("Request image success requestId: %{public}s, uri: %{public}s",
605         requestId.c_str(), requestUri.c_str());
606 
607     std::string tmpUri = requestUri;
608     MediaFileUtils::UriAppendKeyValue(tmpUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
609     Uri uri(tmpUri);
610     int fd = UserFileClient::OpenFile(uri, "r");
611     CHECK_AND_RETURN_RET_LOG(fd >= 0, nullptr, "get image fd failed");
612 
613     struct OH_ImageSourceNative *imageSource;
614     OH_ImageSourceNative_CreateFromFd(fd, &imageSource);
615     close(fd);
616     CHECK_AND_RETURN_RET_LOG(imageSource != nullptr, nullptr, "new OH_ImageSourceNative failed");
617 
618     return imageSource;
619 }
620 
OnHandleRequestImage(const std::unique_ptr<RequestSourceAsyncContext> & asyncContext)621 bool MediaAssetManagerImpl::OnHandleRequestImage(
622     const std::unique_ptr<RequestSourceAsyncContext> &asyncContext)
623 {
624     MultiStagesCapturePhotoStatus status = MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS;
625     bool result = false;
626     switch (asyncContext->requestOptions.deliveryMode) {
627         case NativeDeliveryMode::FAST_MODE:
628             if (asyncContext->needsExtraInfo) {
629                 asyncContext->photoQuality = QueryPhotoStatus(asyncContext->fileId, asyncContext->photoId);
630                 MEDIA_DEBUG_LOG("OnHandleRequestImage photoQuality: %{public}d", asyncContext->photoQuality);
631             }
632             result = NotifyDataPreparedWithoutRegister(asyncContext);
633             break;
634         case NativeDeliveryMode::HIGH_QUALITY_MODE:
635             status = QueryPhotoStatus(asyncContext->fileId, asyncContext->photoId);
636             asyncContext->photoQuality = status;
637             MEDIA_DEBUG_LOG("OnHandleRequestImage photoQuality: %{public}d", asyncContext->photoQuality);
638             if (status == MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
639                 result = NotifyDataPreparedWithoutRegister(asyncContext);
640             } else {
641                 RegisterTaskObserver(asyncContext);
642                 result = true;
643             }
644             break;
645         case NativeDeliveryMode::BALANCED_MODE:
646             status = QueryPhotoStatus(asyncContext->fileId, asyncContext->photoId);
647             asyncContext->photoQuality = status;
648             MEDIA_DEBUG_LOG("OnHandleRequestImage photoQuality: %{public}d", asyncContext->photoQuality);
649             result = NotifyDataPreparedWithoutRegister(asyncContext);
650             if (status == MultiStagesCapturePhotoStatus::LOW_QUALITY_STATUS) {
651                 RegisterTaskObserver(asyncContext);
652             }
653             break;
654         default: {
655             MEDIA_ERR_LOG("Invalid delivery mode %{public}d", asyncContext->requestOptions.deliveryMode);
656             return result;
657         }
658     }
659     return result;
660 }
661 
OnHandleRequestVideo(const std::unique_ptr<RequestSourceAsyncContext> & asyncContext)662 bool MediaAssetManagerImpl::OnHandleRequestVideo(
663     const std::unique_ptr<RequestSourceAsyncContext> &asyncContext)
664 {
665     bool result = false;
666     switch (asyncContext->requestOptions.deliveryMode) {
667         case NativeDeliveryMode::FAST_MODE:
668             result = NotifyDataPreparedWithoutRegister(asyncContext);
669             break;
670         case NativeDeliveryMode::HIGH_QUALITY_MODE:
671             result = NotifyDataPreparedWithoutRegister(asyncContext);
672             break;
673         case NativeDeliveryMode::BALANCED_MODE:
674             result = NotifyDataPreparedWithoutRegister(asyncContext);
675             break;
676         default: {
677             MEDIA_ERR_LOG("Invalid delivery mode %{public}d", asyncContext->requestOptions.deliveryMode);
678             return result;
679         }
680     }
681     return result;
682 }
683 
NotifyDataPreparedWithoutRegister(const std::unique_ptr<RequestSourceAsyncContext> & asyncContext)684 bool MediaAssetManagerImpl::NotifyDataPreparedWithoutRegister(
685     const std::unique_ptr<RequestSourceAsyncContext> &asyncContext)
686 {
687     AssetHandler *assetHandler = InsertDataHandler(NativeNotifyMode::FAST_NOTIFY, asyncContext);
688     if (assetHandler == nullptr) {
689         MEDIA_ERR_LOG("assetHandler is nullptr");
690         return false;
691     }
692 
693     return NotifyImageDataPrepared(assetHandler);
694 }
695 
RegisterTaskObserver(const unique_ptr<RequestSourceAsyncContext> & asyncContext)696 void MediaAssetManagerImpl::RegisterTaskObserver(const unique_ptr<RequestSourceAsyncContext> &asyncContext)
697 {
698     auto dataObserver = std::make_shared<MultiStagesTaskObserver>(asyncContext->fileId);
699     auto uriLocal = MediaFileUtils::GetUriWithoutDisplayname(asyncContext->requestUri);
700     if (multiStagesObserverMap.find(uriLocal) == multiStagesObserverMap.end()) {
701         sDataShareHelper_->RegisterObserverExt(Uri(uriLocal),
702             static_cast<std::shared_ptr<DataShare::DataShareObserver>>(dataObserver), false);
703         multiStagesObserverMap.insert(std::make_pair(uriLocal, dataObserver));
704     }
705 
706     InsertDataHandler(NativeNotifyMode::WAIT_FOR_HIGH_QUALITY, asyncContext);
707 
708     ProcessImage(asyncContext->fileId, static_cast<int32_t>(asyncContext->requestOptions.deliveryMode),
709         asyncContext->callingPkgName);
710 }
711 
ProcessImage(const int fileId,const int deliveryMode,const std::string & packageName)712 void MediaAssetManagerImpl::ProcessImage(const int fileId, const int deliveryMode, const std::string &packageName)
713 {
714     if (sDataShareHelper_ == nullptr) {
715         MEDIA_ERR_LOG("Get sDataShareHelper_ failed");
716         return;
717     }
718     std::string uriStr = PAH_PROCESS_IMAGE;
719     MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, std::to_string(MEDIA_API_VERSION_V10));
720     Uri uri(uriStr);
721     DataShare::DataSharePredicates predicates;
722     DataShare::DatashareBusinessError errCode;
723     std::vector<std::string> columns { std::to_string(fileId), std::to_string(deliveryMode), packageName };
724     sDataShareHelper_->Query(uri, predicates, columns, &errCode);
725     MEDIA_INFO_LOG("MediaAssetManagerImpl::ProcessImage Called");
726 }
727 
OnChange(const ChangeInfo & changeInfo)728 void MultiStagesTaskObserver::OnChange(const ChangeInfo &changeInfo)
729 {
730     if (changeInfo.changeType_ != static_cast<int32_t>(NotifyType::NOTIFY_UPDATE)) {
731         MEDIA_DEBUG_LOG("Ignore notify change, type: %{public}d", changeInfo.changeType_);
732         return;
733     }
734     std::string photoId = "";
735     if (MediaAssetManagerImpl::QueryPhotoStatus(fileId_, photoId) !=
736         MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS) {
737         MEDIA_ERR_LOG("Requested data not prepared");
738         return;
739     }
740 
741     MEDIA_INFO_LOG("MultiStagesTaskObserver::OnChange Called");
742     for (auto &uri : changeInfo.uris_) {
743         string uriString = uri.ToString();
744         std::map<std::string, AssetHandler *> assetHandlers = GetAssetHandlers(uriString);
745         for (auto handler : assetHandlers) {
746             auto assetHandler = handler.second;
747             auto dataHandler = assetHandler->dataHandler;
748             if (dataHandler != nullptr) {
749                 int32_t quality = static_cast<int32_t>(MultiStagesCapturePhotoStatus::HIGH_QUALITY_STATUS);
750                 dataHandler->SetPhotoQuality(quality);
751             }
752             MediaAssetManagerImpl::NotifyImageDataPrepared(assetHandler);
753         }
754     }
755 }
756 
GetAssetHandlers(const std::string uriString)757 std::map<std::string, AssetHandler *> MultiStagesTaskObserver::GetAssetHandlers(const std::string uriString)
758 {
759     MEDIA_INFO_LOG("GetAssetHandlers lock multiStagesCaptureLock");
760     std::lock_guard<std::mutex> lock(multiStagesCaptureLock);
761     if (inProcessUriMap.find(uriString) == inProcessUriMap.end()) {
762         MEDIA_INFO_LOG("current uri does not in process, uri: %{public}s", uriString.c_str());
763         MEDIA_INFO_LOG("GetAssetHandlers unlock multiStagesCaptureLock");
764         return std::map<std::string, AssetHandler*>();
765     }
766     MEDIA_INFO_LOG("GetAssetHandlers unlock multiStagesCaptureLock");
767     return inProcessUriMap[uriString];
768 }
769 
WriteFileToPath(const std::string & srcUri,const std::string & destUri,bool isSource)770 int32_t MediaAssetManagerImpl::WriteFileToPath(const std::string &srcUri, const std::string &destUri,
771     bool isSource)
772 {
773     if (srcUri.empty() || destUri.empty()) {
774         MEDIA_ERR_LOG("srcUri or destUri is empty");
775         return E_INVALID_URI;
776     }
777     std::string tmpSrcUri = srcUri;
778     if (isSource) {
779         MediaFileUtils::UriAppendKeyValue(tmpSrcUri, MEDIA_OPERN_KEYWORD, SOURCE_REQUEST);
780     }
781     int srcFd = MediaAssetManagerImpl::mediaLibraryManager_->OpenAsset(tmpSrcUri, MEDIA_FILEMODE_READONLY);
782     if (srcFd < 0) {
783         MEDIA_ERR_LOG("Get source %{public}s fd error: %{public}d", tmpSrcUri.c_str(), srcFd);
784         return srcFd;
785     }
786     struct stat statSrc;
787     if (fstat(srcFd, &statSrc) != E_SUCCESS) {
788         MediaAssetManagerImpl::mediaLibraryManager_->CloseAsset(tmpSrcUri, srcFd);
789         MEDIA_ERR_LOG("File get stat failed, %{public}d", errno);
790         return E_FILE_OPER_FAIL;
791     }
792     int destFd = GetFdFromSandBoxUri(destUri);
793     if (destFd < 0) {
794         MEDIA_ERR_LOG("Get destination %{public}s fd error: %{public}d", destUri.c_str(), destFd);
795         MediaAssetManagerImpl::mediaLibraryManager_->CloseAsset(tmpSrcUri, srcFd);
796         return destFd;
797     }
798     if (sendfile(destFd, srcFd, nullptr, statSrc.st_size) == -1) {
799         MediaAssetManagerImpl::mediaLibraryManager_->CloseAsset(tmpSrcUri, srcFd);
800         close(destFd);
801         MEDIA_ERR_LOG("Sendfile failed, %{public}d", errno);
802         return E_FILE_OPER_FAIL;
803     }
804     MediaAssetManagerImpl::mediaLibraryManager_->CloseAsset(tmpSrcUri, srcFd);
805     close(destFd);
806     return E_SUCCESS;
807 }
808 
GetFdFromSandBoxUri(const std::string & sandBoxUri)809 int32_t MediaAssetManagerImpl::GetFdFromSandBoxUri(const std::string &sandBoxUri)
810 {
811     AppFileService::ModuleFileUri::FileUri destUri(sandBoxUri);
812     string destPath = destUri.GetRealPath();
813     if (!MediaFileUtils::IsFileExists(destPath) && !MediaFileUtils::CreateFile(destPath)) {
814         MEDIA_ERR_LOG("Create empty dest file in sandbox failed, path:%{private}s", destPath.c_str());
815         return E_FILE_OPER_FAIL;
816     }
817     string absDestPath;
818     if (!PathToRealPath(destPath, absDestPath)) {
819         MEDIA_ERR_LOG("PathToRealPath failed, path:%{private}s", destPath.c_str());
820         return E_FILE_OPER_FAIL;
821     }
822     return MediaFileUtils::OpenFile(absDestPath, MEDIA_FILEMODE_WRITETRUNCATE);
823 }
824 } // namespace Media
825 } // namespace OHOS