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