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