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 #include "media_asset_change_request_impl.h"
17
18 #include <fcntl.h>
19 #include <sys/sendfile.h>
20 #include "securec.h"
21
22 #include "oh_media_asset.h"
23 #include "media_log.h"
24 #include "medialibrary_errno.h"
25 #include "media_file_utils.h"
26 #include "media_column.h"
27 #include "file_uri.h"
28 #include "directory_ex.h"
29 #include "medialibrary_db_const.h"
30 #include "access_token.h"
31 #include "accesstoken_kit.h"
32 #include "ipc_skeleton.h"
33 #include "image_packer.h"
34 #include "permission_utils.h"
35 #include "media_userfile_client.h"
36 #include "userfilemgr_uri.h"
37
38 using namespace std;
39 using namespace OHOS::Media;
40 using namespace OHOS::Security::AccessToken;
41
42 atomic<uint32_t> MediaAssetChangeRequestImpl::cacheFileId_(0);
43 const string MOVING_PHOTO_VIDEO_EXTENSION = "mp4";
44 const string API_VERSION = "api_version";
45
CreateMediaAssetChangeRequest(std::shared_ptr<MediaAsset> mediaAsset)46 std::shared_ptr<MediaAssetChangeRequest> MediaAssetChangeRequestFactory::CreateMediaAssetChangeRequest(
47 std::shared_ptr<MediaAsset> mediaAsset)
48 {
49 std::shared_ptr<MediaAssetChangeRequestImpl> impl = std::make_shared<MediaAssetChangeRequestImpl>(mediaAsset);
50 CHECK_AND_PRINT_LOG(impl != nullptr, "Failed to create MediaAssetChangeRequestImpl instance.");
51
52 return impl;
53 }
54
MediaAssetChangeRequestImpl(std::shared_ptr<MediaAsset> mediaAsset)55 MediaAssetChangeRequestImpl::MediaAssetChangeRequestImpl(std::shared_ptr<MediaAsset> mediaAsset)
56 {
57 mediaAsset_ = mediaAsset;
58 movingPhotoVideoDataBuffer_ = nullptr;
59 dataBuffer_ = nullptr;
60 movingPhotoVideoResourceMode_ = AddResourceMode::DEFAULT;
61 addResourceMode_ = AddResourceMode::DEFAULT;
62 movingPhotoVideoBufferSize_ = 0;
63 dataBufferSize_ = 0;
64 }
65
~MediaAssetChangeRequestImpl()66 MediaAssetChangeRequestImpl::~MediaAssetChangeRequestImpl()
67 {
68 mediaAsset_ = nullptr;
69 if (movingPhotoVideoDataBuffer_ != nullptr) {
70 delete[] movingPhotoVideoDataBuffer_;
71 movingPhotoVideoDataBuffer_ = nullptr;
72 }
73
74 if (dataBuffer_ != nullptr) {
75 delete[] dataBuffer_;
76 dataBuffer_ = nullptr;
77 }
78
79 if (editData_ != nullptr) {
80 editData_ = nullptr;
81 }
82
83 addResourceTypes_.clear();
84 assetChangeOperations_.clear();
85 }
86
GetWriteCacheHandler(int32_t * fd)87 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::GetWriteCacheHandler(int32_t* fd)
88 {
89 unique_lock<mutex> ulock(mutex_);
90 auto fileAsset = mediaAsset_->GetFileAssetInstance();
91 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR, "fileAsset get failed!");
92 CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "cann't be moving photo!");
93 CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE),
94 MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "Not supported!");
95
96 int32_t ret = OpenWriteCacheHandler();
97 if (ret < 0) {
98 MEDIA_ERR_LOG("Failed to open write cache handler,ret: %{public}d", ret);
99 return MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED;
100 }
101 *fd = ret;
102 RecordChangeOperation(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
103 return MEDIA_LIBRARY_OK;
104 }
105
SaveCameraPhoto(MediaLibrary_ImageFileType imageFileType)106 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::SaveCameraPhoto(MediaLibrary_ImageFileType imageFileType)
107 {
108 CHECK_AND_RETURN_RET_LOG(imageFileType == MEDIA_LIBRARY_IMAGE_JPEG, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
109 "imageFileType not support");
110
111 unique_lock<mutex> ulock(mutex_);
112 auto fileAsset = mediaAsset_->GetFileAssetInstance();
113 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
114
115 RecordChangeOperation(AssetChangeOperation::SAVE_CAMERA_PHOTO);
116 return MEDIA_LIBRARY_OK;
117 }
118
DiscardCameraPhoto()119 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::DiscardCameraPhoto()
120 {
121 unique_lock<mutex> ulock(mutex_);
122 auto fileAsset = mediaAsset_->GetFileAssetInstance();
123 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
124
125 RecordChangeOperation(AssetChangeOperation::DISCARD_CAMERA_PHOTO);
126 return MEDIA_LIBRARY_OK;
127 }
128
AddResourceWithUri(MediaLibrary_ResourceType resourceType,char * fileUri)129 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::AddResourceWithUri(MediaLibrary_ResourceType resourceType,
130 char* fileUri)
131 {
132 unique_lock<mutex> ulock(mutex_);
133 CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(resourceType), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
134 "operation not support");
135
136 string realPath;
137 OHOS::AppFileService::ModuleFileUri::FileUri fileUriStr(fileUri);
138 string path = fileUriStr.GetRealPath();
139 bool result = OHOS::PathToRealPath(path, realPath);
140 CHECK_AND_RETURN_RET_LOG(result, MEDIA_LIBRARY_NO_SUCH_FILE, "File real path isn't existed");
141
142 auto fileAsset = mediaAsset_->GetFileAssetInstance();
143 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
144
145 if ((fileAsset->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO)) &&
146 resourceType == static_cast<int32_t>(MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE)) {
147 if ((MediaType::MEDIA_TYPE_VIDEO) != MediaFileUtils::GetMediaType(realPath)) {
148 MEDIA_ERR_LOG("Invalid file type");
149 return MEDIA_LIBRARY_PARAMETER_ERROR;
150 }
151 if (!(MediaFileUtils::CheckMovingPhotoVideo(realPath))) {
152 MEDIA_ERR_LOG("invalid param code");
153 return MEDIA_LIBRARY_NO_SUCH_FILE;
154 }
155
156 movingPhotoVideoRealPath_ = realPath;
157 movingPhotoVideoResourceMode_ = AddResourceMode::FILE_URI;
158 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
159 addResourceTypes_.push_back(MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE);
160 return MEDIA_LIBRARY_OK;
161 }
162
163 if (fileAsset->GetMediaType() != MediaFileUtils::GetMediaType(realPath)) {
164 MEDIA_ERR_LOG("Invalid file type");
165 return MEDIA_LIBRARY_PARAMETER_ERROR;
166 }
167 realPath_ = realPath;
168 addResourceMode_ = AddResourceMode::FILE_URI;
169 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
170 addResourceTypes_.push_back(resourceType);
171 return MEDIA_LIBRARY_OK;
172 }
173
AddResourceWithBuffer(MediaLibrary_ResourceType resourceType,uint8_t * buffer,uint32_t length)174 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::AddResourceWithBuffer(MediaLibrary_ResourceType resourceType,
175 uint8_t* buffer, uint32_t length)
176 {
177 unique_lock<mutex> ulock(mutex_);
178 CHECK_AND_RETURN_RET_LOG(CheckWriteOperation(resourceType), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
179 "operation not support");
180
181 auto fileAsset = mediaAsset_->GetFileAssetInstance();
182 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED, "fileAsset get failed!");
183 CHECK_AND_RETURN_RET_LOG(!IsMovingPhoto(), MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED,
184 "not support edit moving photo with buffer");
185
186 if (dataBuffer_ != nullptr) {
187 delete[] dataBuffer_;
188 }
189 dataBuffer_ = new uint8_t[length + 1];
190 CHECK_AND_RETURN_RET_LOG(dataBuffer_ != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
191 "create dataBuffer_ failed!");
192
193 dataBufferSize_ = length;
194 if (length > 0) {
195 int ret = memcpy_s(dataBuffer_, length + 1, buffer, length);
196 CHECK_AND_RETURN_RET_LOG(ret == E_OK, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR,
197 "memcpy buffer failed!");
198 }
199 addResourceMode_ = AddResourceMode::DATA_BUFFER;
200 RecordChangeOperation(AssetChangeOperation::ADD_RESOURCE);
201 addResourceTypes_.push_back(resourceType);
202 return MEDIA_LIBRARY_OK;
203 }
204
ApplyChanges()205 MediaLibrary_ErrorCode MediaAssetChangeRequestImpl::ApplyChanges()
206 {
207 unique_lock<mutex> ulock(mutex_);
208 bool result = CheckChangeOperations();
209 CHECK_AND_RETURN_RET_LOG(result, MEDIA_LIBRARY_PARAMETER_ERROR, "Failed to check asset change request operations");
210
211 auto fileAsset = mediaAsset_->GetFileAssetInstance();
212 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, MEDIA_LIBRARY_INTERNAL_SYSTEM_ERROR, "fileAsset is nullptr");
213
214 unordered_set<AssetChangeOperation> appliedOperations;
215 for (const auto& changeOperation : assetChangeOperations_) {
216 if (appliedOperations.find(changeOperation) != appliedOperations.end()) {
217 continue;
218 }
219
220 bool valid = ChangeOperationExecute(changeOperation);
221 if (!valid) {
222 MEDIA_ERR_LOG("Failed to apply asset change request, operation: %{public}d", changeOperation);
223 return MEDIA_LIBRARY_OPERATION_NOT_SUPPORTED;
224 }
225 appliedOperations.insert(changeOperation);
226 }
227 assetChangeOperations_.clear();
228 addResourceTypes_.clear();
229 movingPhotoVideoResourceMode_ = AddResourceMode::DEFAULT;
230 addResourceMode_ = AddResourceMode::DEFAULT;
231 return MEDIA_LIBRARY_OK;
232 }
233
IsMovingPhoto()234 bool MediaAssetChangeRequestImpl::IsMovingPhoto()
235 {
236 auto fileAsset = mediaAsset_->GetFileAssetInstance();
237 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
238
239 return fileAsset->GetPhotoSubType() == static_cast<int32_t>(PhotoSubType::MOVING_PHOTO);
240 }
241
CheckWriteOperation(MediaLibrary_ResourceType resourceType)242 bool MediaAssetChangeRequestImpl::CheckWriteOperation(MediaLibrary_ResourceType resourceType)
243 {
244 if (IsMovingPhoto()) {
245 CHECK_AND_RETURN_RET_LOG(CheckMovingPhotoResource(resourceType), false,
246 "Failed to check resource to add for moving photo");
247 return true;
248 }
249
250 if (Contains(AssetChangeOperation::CREATE_FROM_URI) ||
251 Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER) ||
252 Contains(AssetChangeOperation::ADD_RESOURCE)) {
253 MEDIA_ERR_LOG("The previous asset creation/modification request has not been applied");
254 return false;
255 }
256 return true;
257 }
258
CheckMovingPhotoResource(MediaLibrary_ResourceType resourceType)259 bool MediaAssetChangeRequestImpl::CheckMovingPhotoResource(MediaLibrary_ResourceType resourceType)
260 {
261 bool isResourceTypeVaild = !ContainsResource(resourceType);
262 int addResourceTimes =
263 count(assetChangeOperations_.begin(), assetChangeOperations_.end(), AssetChangeOperation::ADD_RESOURCE);
264 return isResourceTypeVaild && addResourceTimes <= 1;
265 }
266
ContainsResource(MediaLibrary_ResourceType resourceType)267 bool MediaAssetChangeRequestImpl::ContainsResource(MediaLibrary_ResourceType resourceType)
268 {
269 return find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) != addResourceTypes_.end();
270 }
271
Contains(AssetChangeOperation changeOperation)272 bool MediaAssetChangeRequestImpl::Contains(AssetChangeOperation changeOperation)
273 {
274 return find(assetChangeOperations_.begin(), assetChangeOperations_.end(), changeOperation) !=
275 assetChangeOperations_.end();
276 }
277
OpenWriteCacheHandler(bool isMovingPhotoVideo)278 int32_t MediaAssetChangeRequestImpl::OpenWriteCacheHandler(bool isMovingPhotoVideo)
279 {
280 auto fileAsset = mediaAsset_->GetFileAssetInstance();
281 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
282
283 // specify mp4 extension for cache file of moving photo video
284 string extension = isMovingPhotoVideo ? MOVING_PHOTO_VIDEO_EXTENSION
285 : MediaFileUtils::GetExtensionFromPath(fileAsset->GetDisplayName());
286 int64_t currentTimestamp = MediaFileUtils::UTCTimeNanoSeconds();
287 uint32_t cacheFileId = FetchAddCacheFileId();
288 string cacheFileName = to_string(currentTimestamp) + "_" + to_string(cacheFileId) + "." + extension;
289 string uri = PhotoColumn::PHOTO_CACHE_URI_PREFIX + cacheFileName;
290 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
291 Uri openCacheUri(uri);
292 int32_t ret = UserFileClient::OpenFile(openCacheUri, MEDIA_FILEMODE_WRITEONLY);
293 CHECK_AND_RETURN_RET_LOG(ret != E_PERMISSION_DENIED, ret, "Open cache file failed, permission denied");
294
295 if (ret < 0) {
296 MEDIA_ERR_LOG("Open cache file failed, ret: %{public}d", ret);
297 }
298
299 if (isMovingPhotoVideo) {
300 cacheMovingPhotoVideoName_ = cacheFileName;
301 } else {
302 cacheFileName_ = cacheFileName;
303 }
304 return ret;
305 }
306
FetchAddCacheFileId()307 uint32_t MediaAssetChangeRequestImpl::FetchAddCacheFileId()
308 {
309 return cacheFileId_.fetch_add(1);
310 }
311
RecordChangeOperation(AssetChangeOperation changeOperation)312 void MediaAssetChangeRequestImpl::RecordChangeOperation(AssetChangeOperation changeOperation)
313 {
314 if ((changeOperation == AssetChangeOperation::GET_WRITE_CACHE_HANDLER ||
315 changeOperation == AssetChangeOperation::ADD_RESOURCE ||
316 changeOperation == AssetChangeOperation::ADD_FILTERS) &&
317 Contains(AssetChangeOperation::CREATE_FROM_SCRATCH)) {
318 assetChangeOperations_.insert(assetChangeOperations_.begin() + 1, changeOperation);
319 return;
320 }
321 assetChangeOperations_.push_back(changeOperation);
322 }
323
CheckChangeOperations()324 bool MediaAssetChangeRequestImpl::CheckChangeOperations()
325 {
326 CHECK_AND_RETURN_RET_LOG(assetChangeOperations_.size() != 0, false, "None request to apply");
327
328 bool isCreateFromScratch = Contains(AssetChangeOperation::CREATE_FROM_SCRATCH);
329 bool isCreateFromUri = Contains(AssetChangeOperation::CREATE_FROM_URI);
330 bool containsEdit = Contains(AssetChangeOperation::SET_EDIT_DATA);
331 bool containsGetHandler = Contains(AssetChangeOperation::GET_WRITE_CACHE_HANDLER);
332 bool containsAddResource = Contains(AssetChangeOperation::ADD_RESOURCE);
333 bool isSaveCameraPhoto = Contains(AssetChangeOperation::SAVE_CAMERA_PHOTO);
334 if ((isCreateFromScratch || containsEdit) && !containsGetHandler && !containsAddResource && !isSaveCameraPhoto) {
335 MEDIA_ERR_LOG("Cannot create or edit asset without data to write");
336 return false;
337 }
338
339 if (containsEdit && (isCreateFromScratch || isCreateFromUri)) {
340 MEDIA_ERR_LOG("Cannot create together with edit");
341 return false;
342 }
343
344 auto fileAsset = mediaAsset_->GetFileAssetInstance();
345 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is null");
346
347 AssetChangeOperation firstOperation = assetChangeOperations_.front();
348 if (fileAsset->GetId() <= 0 && firstOperation != AssetChangeOperation::CREATE_FROM_SCRATCH &&
349 firstOperation != AssetChangeOperation::CREATE_FROM_URI) {
350 MEDIA_ERR_LOG("Invalid asset change request");
351 return false;
352 }
353
354 bool isMovingPhoto = IsMovingPhoto();
355 if (isMovingPhoto && !CheckMovingPhotoWriteOperation()) {
356 MEDIA_ERR_LOG("Invalid write operation for moving photo");
357 return false;
358 }
359 return true;
360 }
361
CheckMovingPhotoWriteOperation()362 bool MediaAssetChangeRequestImpl::CheckMovingPhotoWriteOperation()
363 {
364 if (!Contains(AssetChangeOperation::ADD_RESOURCE)) {
365 return true;
366 }
367
368 if (!Contains(AssetChangeOperation::CREATE_FROM_SCRATCH)) {
369 MEDIA_ERR_LOG("Moving photo is not supported to edit now");
370 return false;
371 }
372
373 int addResourceTimes =
374 count(assetChangeOperations_.begin(), assetChangeOperations_.end(), AssetChangeOperation::ADD_RESOURCE);
375 bool isImageExist = ContainsResource(MediaLibrary_ResourceType::MEDIA_LIBRARY_IMAGE_RESOURCE);
376 bool isVideoExist = ContainsResource(MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE);
377 return addResourceTimes == 2 && isImageExist && isVideoExist; // must add resource 2 times with image and video
378 }
379
ChangeOperationExecute(AssetChangeOperation option)380 bool MediaAssetChangeRequestImpl::ChangeOperationExecute(AssetChangeOperation option)
381 {
382 bool ret = false;
383 switch (option) {
384 case AssetChangeOperation::GET_WRITE_CACHE_HANDLER:
385 ret = SubmitCacheExecute();
386 break;
387 case AssetChangeOperation::ADD_RESOURCE:
388 ret = AddResourceExecute();
389 break;
390 case AssetChangeOperation::SAVE_CAMERA_PHOTO:
391 ret = SaveCameraPhotoExecute();
392 break;
393 case AssetChangeOperation::DISCARD_CAMERA_PHOTO:
394 ret = DiscardCameraPhotoExecute();
395 break;
396 default:
397 break;
398 }
399 return ret;
400 }
401
SubmitCacheExecute()402 bool MediaAssetChangeRequestImpl::SubmitCacheExecute()
403 {
404 bool isCreation = IsCreation();
405 bool isSetEffectMode = IsSetEffectMode();
406 int32_t ret = SubmitCache(isCreation, isSetEffectMode);
407 if (ret < 0) {
408 MEDIA_ERR_LOG("Failed to write cache, ret: %{public}d", ret);
409 return false;
410 }
411 return true;
412 }
413
AddResourceExecute()414 bool MediaAssetChangeRequestImpl::AddResourceExecute()
415 {
416 if (IsMovingPhoto() && movingPhotoVideoResourceMode_ != AddResourceMode::FILE_URI) {
417 MEDIA_ERR_LOG("not support edit moving photo with buffer");
418 return false;
419 }
420 if (!HasWritePermission()) {
421 return WriteBySecurityComponent();
422 }
423
424 if (IsMovingPhoto() && HasAddResource(MediaLibrary_ResourceType::MEDIA_LIBRARY_VIDEO_RESOURCE) &&
425 !AddMovingPhotoVideoExecute()) {
426 MEDIA_ERR_LOG("Faild to write cache file for video of moving photo");
427 return false;
428 }
429
430 if (IsMovingPhoto() && !HasAddResource(MediaLibrary_ResourceType::MEDIA_LIBRARY_IMAGE_RESOURCE)) {
431 return SubmitCacheExecute();
432 }
433 int32_t cacheFd = OpenWriteCacheHandler();
434 if (cacheFd < 0) {
435 MEDIA_ERR_LOG("Failed to open write cache handler, err: %{public}d", cacheFd);
436 return false;
437 }
438 OHOS::UniqueFd uniqueFd(cacheFd);
439 AddResourceMode mode = addResourceMode_;
440 if (!AddResourceByMode(uniqueFd, mode)) {
441 MEDIA_ERR_LOG("Faild to write cache file");
442 return false;
443 }
444 return SubmitCacheExecute();
445 }
446
SaveCameraPhotoExecute()447 bool MediaAssetChangeRequestImpl::SaveCameraPhotoExecute()
448 {
449 bool containsAddResource = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
450 AssetChangeOperation::ADD_RESOURCE) != assetChangeOperations_.end();
451 if (containsAddResource && !PermissionUtils::IsSystemApp()) {
452 // remove high quality photo
453 MEDIA_INFO_LOG("discard high quality photo because add resource by third app");
454 DiscardHighQualityPhoto();
455 }
456
457 // The watermark will trigger the scan. If the watermark is turned on, there is no need to trigger the scan again.
458 bool needScan = std::find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
459 AssetChangeOperation::ADD_FILTERS) == assetChangeOperations_.end();
460
461 auto fileAsset = mediaAsset_->GetFileAssetInstance();
462 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
463
464 std::string uriStr = PAH_SAVE_CAMERA_PHOTO;
465 MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
466 MediaFileUtils::UriAppendKeyValue(uriStr, MEDIA_OPERN_KEYWORD, to_string(needScan));
467 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_FILE_PATH, fileAsset->GetUri());
468 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
469 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_SUBTYPE,
470 to_string(fileAsset->GetPhotoSubType()));
471 Uri uri(uriStr);
472 OHOS::DataShare::DataShareValuesBucket valuesBucket;
473 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
474 OHOS::DataShare::DataSharePredicates predicates;
475 bool ret = UserFileClient::Update(uri, predicates, valuesBucket);
476 CHECK_AND_RETURN_RET_LOG(ret, false, "save camera photo fail");
477
478 return true;
479 }
480
DiscardCameraPhotoExecute()481 bool MediaAssetChangeRequestImpl::DiscardCameraPhotoExecute()
482 {
483 OHOS::DataShare::DataSharePredicates predicates;
484 OHOS::DataShare::DataShareValuesBucket valuesBucket;
485 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, true);
486
487 auto fileAsset = mediaAsset_->GetFileAssetInstance();
488 predicates.EqualTo(PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
489
490 string uri = PAH_DISCARD_CAMERA_PHOTO;
491 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
492 Uri updateAssetUri(uri);
493 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
494 if (changedRows < 0) {
495 MEDIA_ERR_LOG("Failed to update property of asset, err: %{public}d", changedRows);
496 return false;
497 }
498 return true;
499 }
500
HasWritePermission()501 bool MediaAssetChangeRequestImpl::HasWritePermission()
502 {
503 AccessTokenID tokenCaller = OHOS::IPCSkeleton::GetSelfTokenID();
504 int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_WRITE_IMAGEVIDEO);
505 return result == PermissionState::PERMISSION_GRANTED;
506 }
507
WriteBySecurityComponent()508 bool MediaAssetChangeRequestImpl::WriteBySecurityComponent()
509 {
510 bool isCreation = IsCreation();
511 int32_t ret = E_FAIL;
512 bool isCreateFromUri = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
513 AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations_.end();
514 if (isCreateFromUri) {
515 ret = CopyToMediaLibrary(isCreation, AddResourceMode::FILE_URI);
516 } else {
517 ret = CopyToMediaLibrary(isCreation, addResourceMode_);
518 }
519 if (ret < 0) {
520 MEDIA_ERR_LOG("Failed to write by security component, ret: %{public}d", ret);
521 return false;
522 }
523 return true;
524 }
525
IsCreation()526 bool MediaAssetChangeRequestImpl::IsCreation()
527 {
528 bool isCreateFromScratch = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
529 AssetChangeOperation::CREATE_FROM_SCRATCH) != assetChangeOperations_.end();
530 bool isCreateFromUri = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
531 AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations_.end();
532 return isCreateFromScratch || isCreateFromUri;
533 }
534
CopyToMediaLibrary(bool isCreation,AddResourceMode mode)535 int32_t MediaAssetChangeRequestImpl::CopyToMediaLibrary(bool isCreation, AddResourceMode mode)
536 {
537 auto fileAsset = mediaAsset_->GetFileAssetInstance();
538 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
539
540 int32_t ret = E_ERR;
541 int32_t id = 0;
542 string assetUri;
543 if (isCreation) {
544 ret = CreateAssetBySecurityComponent(assetUri);
545 CHECK_AND_RETURN_RET_LOG(ret > 0, (ret == 0 ? E_ERR : ret), "Failed to create asset by security component");
546 id = ret;
547 } else {
548 assetUri = fileAsset->GetUri();
549 }
550 CHECK_AND_RETURN_RET_LOG(!assetUri.empty(), E_ERR, "Failed to check empty asset uri");
551
552 if (IsMovingPhoto()) {
553 ret = CopyMovingPhotoVideo(assetUri);
554 if (ret != E_OK) {
555 MEDIA_ERR_LOG("Failed to copy data to moving photo video with error: %{public}d", ret);
556 return ret;
557 }
558 }
559
560 Uri uri(assetUri);
561 OHOS::UniqueFd destFd(UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY));
562 if (destFd.Get() < 0) {
563 MEDIA_ERR_LOG("Failed to open %{public}s with error: %{public}d", assetUri.c_str(), destFd.Get());
564 return destFd.Get();
565 }
566
567 if (mode == AddResourceMode::FILE_URI) {
568 ret = CopyFileToMediaLibrary(destFd);
569 } else if (mode == AddResourceMode::DATA_BUFFER) {
570 ret = CopyDataBufferToMediaLibrary(destFd);
571 } else {
572 MEDIA_ERR_LOG("Invalid mode: %{public}d", mode);
573 return E_INVALID_VALUES;
574 }
575
576 if (ret == E_OK && isCreation) {
577 SetNewFileAsset(id, assetUri);
578 }
579 return ret;
580 }
581
CreateAssetBySecurityComponent(string & assetUri)582 int32_t MediaAssetChangeRequestImpl::CreateAssetBySecurityComponent(string& assetUri)
583 {
584 bool isValid = false;
585 string title = creationValuesBucket_.Get(PhotoColumn::MEDIA_TITLE, isValid);
586 CHECK_AND_RETURN_RET_LOG(isValid, E_FAIL, "Failed to get title");
587
588 string extension = creationValuesBucket_.Get(ASSET_EXTENTION, isValid);
589 CHECK_AND_RETURN_RET_LOG(isValid && MediaFileUtils::CheckDisplayName(title + "." + extension) == E_OK, E_FAIL,
590 "Failed to check displayName");
591
592 creationValuesBucket_.valuesMap.erase(MEDIA_DATA_DB_NAME);
593 string uri = PAH_CREATE_PHOTO_COMPONENT;
594 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
595 Uri createAssetUri(uri);
596 return UserFileClient::InsertExt(createAssetUri, creationValuesBucket_, assetUri);
597 }
598
CopyMovingPhotoVideo(const string & assetUri)599 int32_t MediaAssetChangeRequestImpl::CopyMovingPhotoVideo(const string& assetUri)
600 {
601 CHECK_AND_RETURN_RET_LOG(!assetUri.empty(), E_INVALID_URI, "Failed to check empty asset uri");
602
603 string videoUri = assetUri;
604 MediaFileUtils::UriAppendKeyValue(videoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD, OPEN_MOVING_PHOTO_VIDEO);
605 Uri uri(videoUri);
606 int videoFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY);
607 CHECK_AND_RETURN_RET_LOG(videoFd >= 0, videoFd, "Failed to open video of moving photo with write-only mode");
608
609 int32_t ret = E_ERR;
610 OHOS::UniqueFd uniqueFd(videoFd);
611 if (movingPhotoVideoResourceMode_ == AddResourceMode::FILE_URI) {
612 ret = CopyFileToMediaLibrary(uniqueFd, true);
613 } else if (movingPhotoVideoResourceMode_ == AddResourceMode::DATA_BUFFER) {
614 ret = CopyDataBufferToMediaLibrary(uniqueFd, true);
615 } else {
616 MEDIA_ERR_LOG("Invalid mode: %{public}d", movingPhotoVideoResourceMode_);
617 return E_INVALID_VALUES;
618 }
619 return ret;
620 }
621
CopyFileToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)622 int32_t MediaAssetChangeRequestImpl::CopyFileToMediaLibrary(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
623 {
624 string srcRealPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
625 CHECK_AND_RETURN_RET_LOG(!srcRealPath.empty(), E_FAIL, "Failed to check real path of source");
626
627 string absFilePath;
628 CHECK_AND_RETURN_RET_LOG(OHOS::PathToRealPath(srcRealPath, absFilePath), E_FAIL, "Not real path %{public}s",
629 srcRealPath.c_str());
630
631 OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
632 if (srcFd.Get() < 0) {
633 MEDIA_ERR_LOG("Failed to open %{public}s, errno=%{public}d", absFilePath.c_str(), errno);
634 return srcFd.Get();
635 }
636
637 int32_t err = SendFile(srcFd, destFd);
638 if (err != E_OK) {
639 MEDIA_ERR_LOG("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
640 }
641 return err;
642 }
643
CopyDataBufferToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)644 int32_t MediaAssetChangeRequestImpl::CopyDataBufferToMediaLibrary(const OHOS::UniqueFd& destFd,
645 bool isMovingPhotoVideo)
646 {
647 size_t offset = 0;
648 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
649 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
650 while (offset < length) {
651 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
652 if (written < 0) {
653 MEDIA_ERR_LOG("Failed to copy data buffer, return %{public}d", static_cast<int>(written));
654 return written;
655 }
656 offset += static_cast<size_t>(written);
657 }
658 return E_OK;
659 }
660
SetNewFileAsset(int32_t id,const string & uri)661 void MediaAssetChangeRequestImpl::SetNewFileAsset(int32_t id, const string& uri)
662 {
663 auto fileAsset = mediaAsset_->GetFileAssetInstance();
664 if (fileAsset == nullptr) {
665 MEDIA_ERR_LOG("fileAsset is nullptr");
666 return;
667 }
668
669 if (id <= 0 || uri.empty()) {
670 MEDIA_ERR_LOG("Failed to check file_id: %{public}d and uri: %{public}s", id, uri.c_str());
671 return;
672 }
673 fileAsset->SetId(id);
674 fileAsset->SetUri(uri);
675 fileAsset->SetTimePending(0);
676 }
677
SendToCacheFile(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)678 bool MediaAssetChangeRequestImpl::SendToCacheFile(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
679 {
680 string realPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
681 string absFilePath;
682 if (!OHOS::PathToRealPath(realPath, absFilePath)) {
683 MEDIA_ERR_LOG("Not real path %{public}s, errno=%{public}d", realPath.c_str(), errno);
684 return false;
685 }
686
687 OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
688 if (srcFd.Get() < 0) {
689 MEDIA_ERR_LOG("Failed to open file, errno=%{public}d", errno);
690 return false;
691 }
692
693 int32_t err = SendFile(srcFd, destFd);
694 if (err != E_OK) {
695 MEDIA_ERR_LOG("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
696 return false;
697 }
698 return true;
699 }
700
IsSetEffectMode()701 bool MediaAssetChangeRequestImpl::IsSetEffectMode()
702 {
703 return find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
704 AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE) != assetChangeOperations_.end();
705 }
706
SubmitCache(bool isCreation,bool isSetEffectMode)707 int32_t MediaAssetChangeRequestImpl::SubmitCache(bool isCreation, bool isSetEffectMode)
708 {
709 auto fileAsset = mediaAsset_->GetFileAssetInstance();
710 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
711 CHECK_AND_RETURN_RET_LOG(!cacheFileName_.empty() || !cacheMovingPhotoVideoName_.empty(), E_FAIL,
712 "Failed to check cache file");
713
714 string uri = PAH_SUBMIT_CACHE;
715 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
716 Uri submitCacheUri(uri);
717 string assetUri;
718 int32_t ret;
719 if (isCreation) {
720 bool isValid = false;
721 string displayName = creationValuesBucket_.Get(MEDIA_DATA_DB_NAME, isValid);
722 CHECK_AND_RETURN_RET_LOG(
723 isValid && MediaFileUtils::CheckDisplayName(displayName) == E_OK, E_FAIL, "Failed to check displayName");
724
725 creationValuesBucket_.Put(CACHE_FILE_NAME, cacheFileName_);
726 if (IsMovingPhoto()) {
727 creationValuesBucket_.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
728 }
729 ret = UserFileClient::InsertExt(submitCacheUri, creationValuesBucket_, assetUri);
730 } else {
731 OHOS::DataShare::DataShareValuesBucket valuesBucket;
732 valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset->GetId());
733 valuesBucket.Put(CACHE_FILE_NAME, cacheFileName_);
734 ret = PutMediaAssetEditData(valuesBucket);
735 CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to put editData");
736
737 if (isSetEffectMode) {
738 valuesBucket.Put(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, fileAsset->GetMovingPhotoEffectMode());
739 valuesBucket.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
740 }
741 ret = UserFileClient::Insert(submitCacheUri, valuesBucket);
742 }
743
744 if (ret > 0 && isCreation) {
745 SetNewFileAsset(ret, assetUri);
746 }
747 cacheFileName_.clear();
748 cacheMovingPhotoVideoName_.clear();
749 return ret;
750 }
751
SendFile(const OHOS::UniqueFd & srcFd,const OHOS::UniqueFd & destFd)752 int32_t MediaAssetChangeRequestImpl::SendFile(const OHOS::UniqueFd& srcFd, const OHOS::UniqueFd& destFd)
753 {
754 if (srcFd.Get() < 0 || destFd.Get() < 0) {
755 MEDIA_ERR_LOG("Failed to check srcFd: %{public}d and destFd: %{public}d", srcFd.Get(), destFd.Get());
756 return E_ERR;
757 }
758
759 struct stat statSrc {};
760 int32_t status = fstat(srcFd.Get(), &statSrc);
761 if (status != 0) {
762 MEDIA_ERR_LOG("Failed to get file stat, errno=%{public}d", errno);
763 return status;
764 }
765
766 off_t offset = 0;
767 off_t fileSize = statSrc.st_size;
768 while (offset < fileSize) {
769 ssize_t sent = sendfile(destFd.Get(), srcFd.Get(), &offset, fileSize - offset);
770 if (sent < 0) {
771 MEDIA_ERR_LOG("Failed to sendfile with errno=%{public}d, srcFd=%{public}d, destFd=%{public}d", errno,
772 srcFd.Get(), destFd.Get());
773 return sent;
774 }
775 }
776
777 return E_OK;
778 }
779
PutMediaAssetEditData(OHOS::DataShare::DataShareValuesBucket & valuesBucket)780 int32_t MediaAssetChangeRequestImpl::PutMediaAssetEditData(OHOS::DataShare::DataShareValuesBucket& valuesBucket)
781 {
782 if (editData_ == nullptr) {
783 return E_OK;
784 }
785
786 string compatibleFormat = editData_->GetCompatibleFormat();
787 CHECK_AND_RETURN_RET_LOG(!compatibleFormat.empty(), E_FAIL, "Failed to check compatibleFormat");
788
789 string formatVersion = editData_->GetFormatVersion();
790 CHECK_AND_RETURN_RET_LOG(!formatVersion.empty(), E_FAIL, "Failed to check formatVersion");
791
792 string data = editData_->GetData();
793 CHECK_AND_RETURN_RET_LOG(!data.empty(), E_FAIL, "Failed to check data");
794
795 valuesBucket.Put(COMPATIBLE_FORMAT, compatibleFormat);
796 valuesBucket.Put(FORMAT_VERSION, formatVersion);
797 valuesBucket.Put(EDIT_DATA, data);
798 return E_OK;
799 }
800
HasAddResource(MediaLibrary_ResourceType resourceType)801 bool MediaAssetChangeRequestImpl::HasAddResource(MediaLibrary_ResourceType resourceType)
802 {
803 return find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) !=
804 addResourceTypes_.end();
805 }
806
AddMovingPhotoVideoExecute()807 bool MediaAssetChangeRequestImpl::AddMovingPhotoVideoExecute()
808 {
809 CHECK_AND_RETURN_RET_LOG(movingPhotoVideoResourceMode_ == AddResourceMode::FILE_URI, false,
810 "not support edit moving photo with buffer");
811 int32_t cacheVideoFd = OpenWriteCacheHandler(true);
812 if (cacheVideoFd < 0) {
813 MEDIA_ERR_LOG("Failed to open cache moving photo video, err: %{public}d", cacheVideoFd);
814 return false;
815 }
816 OHOS::UniqueFd uniqueFd(cacheVideoFd);
817 AddResourceMode mode = movingPhotoVideoResourceMode_;
818 if (!AddResourceByMode(uniqueFd, mode, true)) {
819 MEDIA_ERR_LOG("Faild to write cache file");
820 return false;
821 }
822 return true;
823 }
824
AddResourceByMode(const OHOS::UniqueFd & uniqueFd,AddResourceMode mode,bool isMovingPhotoVideo)825 bool MediaAssetChangeRequestImpl::AddResourceByMode(const OHOS::UniqueFd& uniqueFd,
826 AddResourceMode mode, bool isMovingPhotoVideo)
827 {
828 bool isWriteSuccess = false;
829 if (mode == AddResourceMode::DATA_BUFFER) {
830 isWriteSuccess = WriteCacheByArrayBuffer(uniqueFd, isMovingPhotoVideo);
831 } else if (mode == AddResourceMode::FILE_URI) {
832 isWriteSuccess = SendToCacheFile(uniqueFd, isMovingPhotoVideo);
833 } else {
834 MEDIA_ERR_LOG("Unsupported addResource mode");
835 }
836 return isWriteSuccess;
837 }
838
WriteCacheByArrayBuffer(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)839 bool MediaAssetChangeRequestImpl::WriteCacheByArrayBuffer(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
840 {
841 size_t offset = 0;
842 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
843 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
844 while (offset < length) {
845 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
846 if (written < 0) {
847 MEDIA_ERR_LOG("Failed to write data buffer to cache file, return %{public}d", static_cast<int>(written));
848 return false;
849 }
850 offset += static_cast<size_t>(written);
851 }
852 return true;
853 }
854
DiscardHighQualityPhoto()855 void MediaAssetChangeRequestImpl::DiscardHighQualityPhoto()
856 {
857 string uriStr = PAH_REMOVE_MSC_TASK;
858 MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
859 Uri uri(uriStr);
860 OHOS::DataShare::DataSharePredicates predicates;
861 int errCode = 0;
862
863 auto fileAsset = mediaAsset_->GetFileAssetInstance();
864 vector<string> columns { to_string(fileAsset->GetId()) };
865 UserFileClient::Query(uri, predicates, columns, errCode);
866 }
867