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 std::string uriStr = PAH_SAVE_CAMERA_PHOTO;
452 if (containsAddResource && !PermissionUtils::IsSystemApp()) {
453 // remove high quality photo
454 MEDIA_INFO_LOG("discard high quality photo because add resource by third app");
455 DiscardHighQualityPhoto();
456
457 // set dirty flag when third-party hap calling addResource to save camera photo
458 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_DIRTY,
459 to_string(static_cast<int32_t>(DirtyType::TYPE_NEW)));
460 }
461
462 // The watermark will trigger the scan. If the watermark is turned on, there is no need to trigger the scan again.
463 bool needScan = std::find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
464 AssetChangeOperation::ADD_FILTERS) == assetChangeOperations_.end();
465
466 auto fileAsset = mediaAsset_->GetFileAssetInstance();
467 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, false, "fileAsset is nullptr");
468
469 MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
470 MediaFileUtils::UriAppendKeyValue(uriStr, MEDIA_OPERN_KEYWORD, to_string(needScan));
471 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_FILE_PATH, fileAsset->GetUri());
472 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
473 MediaFileUtils::UriAppendKeyValue(uriStr, PhotoColumn::PHOTO_SUBTYPE,
474 to_string(fileAsset->GetPhotoSubType()));
475 Uri uri(uriStr);
476 OHOS::DataShare::DataShareValuesBucket valuesBucket;
477 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, false);
478 OHOS::DataShare::DataSharePredicates predicates;
479 bool ret = UserFileClient::Update(uri, predicates, valuesBucket);
480 CHECK_AND_RETURN_RET_LOG(ret, false, "save camera photo fail");
481
482 return true;
483 }
484
DiscardCameraPhotoExecute()485 bool MediaAssetChangeRequestImpl::DiscardCameraPhotoExecute()
486 {
487 OHOS::DataShare::DataSharePredicates predicates;
488 OHOS::DataShare::DataShareValuesBucket valuesBucket;
489 valuesBucket.Put(PhotoColumn::PHOTO_IS_TEMP, true);
490
491 auto fileAsset = mediaAsset_->GetFileAssetInstance();
492 predicates.EqualTo(PhotoColumn::MEDIA_ID, to_string(fileAsset->GetId()));
493
494 string uri = PAH_DISCARD_CAMERA_PHOTO;
495 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
496 Uri updateAssetUri(uri);
497 int32_t changedRows = UserFileClient::Update(updateAssetUri, predicates, valuesBucket);
498 if (changedRows < 0) {
499 MEDIA_ERR_LOG("Failed to update property of asset, err: %{public}d", changedRows);
500 return false;
501 }
502 return true;
503 }
504
HasWritePermission()505 bool MediaAssetChangeRequestImpl::HasWritePermission()
506 {
507 AccessTokenID tokenCaller = OHOS::IPCSkeleton::GetSelfTokenID();
508 int result = AccessTokenKit::VerifyAccessToken(tokenCaller, PERM_WRITE_IMAGEVIDEO);
509 return result == PermissionState::PERMISSION_GRANTED;
510 }
511
WriteBySecurityComponent()512 bool MediaAssetChangeRequestImpl::WriteBySecurityComponent()
513 {
514 bool isCreation = IsCreation();
515 int32_t ret = E_FAIL;
516 bool isCreateFromUri = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
517 AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations_.end();
518 if (isCreateFromUri) {
519 ret = CopyToMediaLibrary(isCreation, AddResourceMode::FILE_URI);
520 } else {
521 ret = CopyToMediaLibrary(isCreation, addResourceMode_);
522 }
523 if (ret < 0) {
524 MEDIA_ERR_LOG("Failed to write by security component, ret: %{public}d", ret);
525 return false;
526 }
527 return true;
528 }
529
IsCreation()530 bool MediaAssetChangeRequestImpl::IsCreation()
531 {
532 bool isCreateFromScratch = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
533 AssetChangeOperation::CREATE_FROM_SCRATCH) != assetChangeOperations_.end();
534 bool isCreateFromUri = find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
535 AssetChangeOperation::CREATE_FROM_URI) != assetChangeOperations_.end();
536 return isCreateFromScratch || isCreateFromUri;
537 }
538
CopyToMediaLibrary(bool isCreation,AddResourceMode mode)539 int32_t MediaAssetChangeRequestImpl::CopyToMediaLibrary(bool isCreation, AddResourceMode mode)
540 {
541 auto fileAsset = mediaAsset_->GetFileAssetInstance();
542 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
543
544 int32_t ret = E_ERR;
545 int32_t id = 0;
546 string assetUri;
547 if (isCreation) {
548 ret = CreateAssetBySecurityComponent(assetUri);
549 CHECK_AND_RETURN_RET_LOG(ret > 0, (ret == 0 ? E_ERR : ret), "Failed to create asset by security component");
550 id = ret;
551 } else {
552 assetUri = fileAsset->GetUri();
553 }
554 CHECK_AND_RETURN_RET_LOG(!assetUri.empty(), E_ERR, "Failed to check empty asset uri");
555
556 if (IsMovingPhoto()) {
557 ret = CopyMovingPhotoVideo(assetUri);
558 if (ret != E_OK) {
559 MEDIA_ERR_LOG("Failed to copy data to moving photo video with error: %{public}d", ret);
560 return ret;
561 }
562 }
563
564 Uri uri(assetUri);
565 OHOS::UniqueFd destFd(UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY));
566 if (destFd.Get() < 0) {
567 MEDIA_ERR_LOG("Failed to open %{public}s with error: %{public}d", assetUri.c_str(), destFd.Get());
568 return destFd.Get();
569 }
570
571 if (mode == AddResourceMode::FILE_URI) {
572 ret = CopyFileToMediaLibrary(destFd);
573 } else if (mode == AddResourceMode::DATA_BUFFER) {
574 ret = CopyDataBufferToMediaLibrary(destFd);
575 } else {
576 MEDIA_ERR_LOG("Invalid mode: %{public}d", mode);
577 return E_INVALID_VALUES;
578 }
579
580 if (ret == E_OK && isCreation) {
581 SetNewFileAsset(id, assetUri);
582 }
583 return ret;
584 }
585
CreateAssetBySecurityComponent(string & assetUri)586 int32_t MediaAssetChangeRequestImpl::CreateAssetBySecurityComponent(string& assetUri)
587 {
588 bool isValid = false;
589 string title = creationValuesBucket_.Get(PhotoColumn::MEDIA_TITLE, isValid);
590 CHECK_AND_RETURN_RET_LOG(isValid, E_FAIL, "Failed to get title");
591
592 string extension = creationValuesBucket_.Get(ASSET_EXTENTION, isValid);
593 CHECK_AND_RETURN_RET_LOG(isValid && MediaFileUtils::CheckDisplayName(title + "." + extension) == E_OK, E_FAIL,
594 "Failed to check displayName");
595
596 creationValuesBucket_.valuesMap.erase(MEDIA_DATA_DB_NAME);
597 string uri = PAH_CREATE_PHOTO_COMPONENT;
598 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
599 Uri createAssetUri(uri);
600 return UserFileClient::InsertExt(createAssetUri, creationValuesBucket_, assetUri);
601 }
602
CopyMovingPhotoVideo(const string & assetUri)603 int32_t MediaAssetChangeRequestImpl::CopyMovingPhotoVideo(const string& assetUri)
604 {
605 CHECK_AND_RETURN_RET_LOG(!assetUri.empty(), E_INVALID_URI, "Failed to check empty asset uri");
606
607 string videoUri = assetUri;
608 MediaFileUtils::UriAppendKeyValue(videoUri, MEDIA_MOVING_PHOTO_OPRN_KEYWORD, OPEN_MOVING_PHOTO_VIDEO);
609 Uri uri(videoUri);
610 int videoFd = UserFileClient::OpenFile(uri, MEDIA_FILEMODE_WRITEONLY);
611 CHECK_AND_RETURN_RET_LOG(videoFd >= 0, videoFd, "Failed to open video of moving photo with write-only mode");
612
613 int32_t ret = E_ERR;
614 OHOS::UniqueFd uniqueFd(videoFd);
615 if (movingPhotoVideoResourceMode_ == AddResourceMode::FILE_URI) {
616 ret = CopyFileToMediaLibrary(uniqueFd, true);
617 } else if (movingPhotoVideoResourceMode_ == AddResourceMode::DATA_BUFFER) {
618 ret = CopyDataBufferToMediaLibrary(uniqueFd, true);
619 } else {
620 MEDIA_ERR_LOG("Invalid mode: %{public}d", movingPhotoVideoResourceMode_);
621 return E_INVALID_VALUES;
622 }
623 return ret;
624 }
625
CopyFileToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)626 int32_t MediaAssetChangeRequestImpl::CopyFileToMediaLibrary(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
627 {
628 string srcRealPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
629 CHECK_AND_RETURN_RET_LOG(!srcRealPath.empty(), E_FAIL, "Failed to check real path of source");
630
631 string absFilePath;
632 CHECK_AND_RETURN_RET_LOG(OHOS::PathToRealPath(srcRealPath, absFilePath), E_FAIL, "Not real path %{public}s",
633 srcRealPath.c_str());
634
635 OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
636 if (srcFd.Get() < 0) {
637 MEDIA_ERR_LOG("Failed to open %{public}s, errno=%{public}d", absFilePath.c_str(), errno);
638 return srcFd.Get();
639 }
640
641 int32_t err = SendFile(srcFd, destFd);
642 if (err != E_OK) {
643 MEDIA_ERR_LOG("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
644 }
645 return err;
646 }
647
CopyDataBufferToMediaLibrary(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)648 int32_t MediaAssetChangeRequestImpl::CopyDataBufferToMediaLibrary(const OHOS::UniqueFd& destFd,
649 bool isMovingPhotoVideo)
650 {
651 size_t offset = 0;
652 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
653 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
654 while (offset < length) {
655 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
656 if (written < 0) {
657 MEDIA_ERR_LOG("Failed to copy data buffer, return %{public}d", static_cast<int>(written));
658 return written;
659 }
660 offset += static_cast<size_t>(written);
661 }
662 return E_OK;
663 }
664
SetNewFileAsset(int32_t id,const string & uri)665 void MediaAssetChangeRequestImpl::SetNewFileAsset(int32_t id, const string& uri)
666 {
667 auto fileAsset = mediaAsset_->GetFileAssetInstance();
668 if (fileAsset == nullptr) {
669 MEDIA_ERR_LOG("fileAsset is nullptr");
670 return;
671 }
672
673 if (id <= 0 || uri.empty()) {
674 MEDIA_ERR_LOG("Failed to check file_id: %{public}d and uri: %{public}s", id, uri.c_str());
675 return;
676 }
677 fileAsset->SetId(id);
678 fileAsset->SetUri(uri);
679 fileAsset->SetTimePending(0);
680 }
681
SendToCacheFile(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)682 bool MediaAssetChangeRequestImpl::SendToCacheFile(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
683 {
684 string realPath = isMovingPhotoVideo ? movingPhotoVideoRealPath_ : realPath_;
685 string absFilePath;
686 if (!OHOS::PathToRealPath(realPath, absFilePath)) {
687 MEDIA_ERR_LOG("Not real path %{public}s, errno=%{public}d", realPath.c_str(), errno);
688 return false;
689 }
690
691 OHOS::UniqueFd srcFd(open(absFilePath.c_str(), O_RDONLY));
692 if (srcFd.Get() < 0) {
693 MEDIA_ERR_LOG("Failed to open file, errno=%{public}d", errno);
694 return false;
695 }
696
697 int32_t err = SendFile(srcFd, destFd);
698 if (err != E_OK) {
699 MEDIA_ERR_LOG("Failed to send file from %{public}d to %{public}d", srcFd.Get(), destFd.Get());
700 return false;
701 }
702 return true;
703 }
704
IsSetEffectMode()705 bool MediaAssetChangeRequestImpl::IsSetEffectMode()
706 {
707 return find(assetChangeOperations_.begin(), assetChangeOperations_.end(),
708 AssetChangeOperation::SET_MOVING_PHOTO_EFFECT_MODE) != assetChangeOperations_.end();
709 }
710
SubmitCache(bool isCreation,bool isSetEffectMode)711 int32_t MediaAssetChangeRequestImpl::SubmitCache(bool isCreation, bool isSetEffectMode)
712 {
713 auto fileAsset = mediaAsset_->GetFileAssetInstance();
714 CHECK_AND_RETURN_RET_LOG(fileAsset != nullptr, E_FAIL, "fileAsset is null");
715 CHECK_AND_RETURN_RET_LOG(!cacheFileName_.empty() || !cacheMovingPhotoVideoName_.empty(), E_FAIL,
716 "Failed to check cache file");
717
718 string uri = PAH_SUBMIT_CACHE;
719 MediaFileUtils::UriAppendKeyValue(uri, API_VERSION, to_string(MEDIA_API_VERSION_V10));
720 Uri submitCacheUri(uri);
721 string assetUri;
722 int32_t ret;
723 if (isCreation) {
724 bool isValid = false;
725 string displayName = creationValuesBucket_.Get(MEDIA_DATA_DB_NAME, isValid);
726 CHECK_AND_RETURN_RET_LOG(
727 isValid && MediaFileUtils::CheckDisplayName(displayName) == E_OK, E_FAIL, "Failed to check displayName");
728
729 creationValuesBucket_.Put(CACHE_FILE_NAME, cacheFileName_);
730 if (IsMovingPhoto()) {
731 creationValuesBucket_.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
732 }
733 ret = UserFileClient::InsertExt(submitCacheUri, creationValuesBucket_, assetUri);
734 } else {
735 OHOS::DataShare::DataShareValuesBucket valuesBucket;
736 valuesBucket.Put(PhotoColumn::MEDIA_ID, fileAsset->GetId());
737 valuesBucket.Put(CACHE_FILE_NAME, cacheFileName_);
738 ret = PutMediaAssetEditData(valuesBucket);
739 CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "Failed to put editData");
740
741 if (isSetEffectMode) {
742 valuesBucket.Put(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, fileAsset->GetMovingPhotoEffectMode());
743 valuesBucket.Put(CACHE_MOVING_PHOTO_VIDEO_NAME, cacheMovingPhotoVideoName_);
744 }
745 ret = UserFileClient::Insert(submitCacheUri, valuesBucket);
746 }
747
748 if (ret > 0 && isCreation) {
749 SetNewFileAsset(ret, assetUri);
750 }
751 cacheFileName_.clear();
752 cacheMovingPhotoVideoName_.clear();
753 return ret;
754 }
755
SendFile(const OHOS::UniqueFd & srcFd,const OHOS::UniqueFd & destFd)756 int32_t MediaAssetChangeRequestImpl::SendFile(const OHOS::UniqueFd& srcFd, const OHOS::UniqueFd& destFd)
757 {
758 if (srcFd.Get() < 0 || destFd.Get() < 0) {
759 MEDIA_ERR_LOG("Failed to check srcFd: %{public}d and destFd: %{public}d", srcFd.Get(), destFd.Get());
760 return E_ERR;
761 }
762
763 struct stat statSrc {};
764 int32_t status = fstat(srcFd.Get(), &statSrc);
765 if (status != 0) {
766 MEDIA_ERR_LOG("Failed to get file stat, errno=%{public}d", errno);
767 return status;
768 }
769
770 off_t offset = 0;
771 off_t fileSize = statSrc.st_size;
772 while (offset < fileSize) {
773 ssize_t sent = sendfile(destFd.Get(), srcFd.Get(), &offset, fileSize - offset);
774 if (sent < 0) {
775 MEDIA_ERR_LOG("Failed to sendfile with errno=%{public}d, srcFd=%{public}d, destFd=%{public}d", errno,
776 srcFd.Get(), destFd.Get());
777 return sent;
778 }
779 }
780
781 return E_OK;
782 }
783
PutMediaAssetEditData(OHOS::DataShare::DataShareValuesBucket & valuesBucket)784 int32_t MediaAssetChangeRequestImpl::PutMediaAssetEditData(OHOS::DataShare::DataShareValuesBucket& valuesBucket)
785 {
786 if (editData_ == nullptr) {
787 return E_OK;
788 }
789
790 string compatibleFormat = editData_->GetCompatibleFormat();
791 CHECK_AND_RETURN_RET_LOG(!compatibleFormat.empty(), E_FAIL, "Failed to check compatibleFormat");
792
793 string formatVersion = editData_->GetFormatVersion();
794 CHECK_AND_RETURN_RET_LOG(!formatVersion.empty(), E_FAIL, "Failed to check formatVersion");
795
796 string data = editData_->GetData();
797 CHECK_AND_RETURN_RET_LOG(!data.empty(), E_FAIL, "Failed to check data");
798
799 valuesBucket.Put(COMPATIBLE_FORMAT, compatibleFormat);
800 valuesBucket.Put(FORMAT_VERSION, formatVersion);
801 valuesBucket.Put(EDIT_DATA, data);
802 return E_OK;
803 }
804
HasAddResource(MediaLibrary_ResourceType resourceType)805 bool MediaAssetChangeRequestImpl::HasAddResource(MediaLibrary_ResourceType resourceType)
806 {
807 return find(addResourceTypes_.begin(), addResourceTypes_.end(), resourceType) !=
808 addResourceTypes_.end();
809 }
810
AddMovingPhotoVideoExecute()811 bool MediaAssetChangeRequestImpl::AddMovingPhotoVideoExecute()
812 {
813 CHECK_AND_RETURN_RET_LOG(movingPhotoVideoResourceMode_ == AddResourceMode::FILE_URI, false,
814 "not support edit moving photo with buffer");
815 int32_t cacheVideoFd = OpenWriteCacheHandler(true);
816 if (cacheVideoFd < 0) {
817 MEDIA_ERR_LOG("Failed to open cache moving photo video, err: %{public}d", cacheVideoFd);
818 return false;
819 }
820 OHOS::UniqueFd uniqueFd(cacheVideoFd);
821 AddResourceMode mode = movingPhotoVideoResourceMode_;
822 if (!AddResourceByMode(uniqueFd, mode, true)) {
823 MEDIA_ERR_LOG("Faild to write cache file");
824 return false;
825 }
826 return true;
827 }
828
AddResourceByMode(const OHOS::UniqueFd & uniqueFd,AddResourceMode mode,bool isMovingPhotoVideo)829 bool MediaAssetChangeRequestImpl::AddResourceByMode(const OHOS::UniqueFd& uniqueFd,
830 AddResourceMode mode, bool isMovingPhotoVideo)
831 {
832 bool isWriteSuccess = false;
833 if (mode == AddResourceMode::DATA_BUFFER) {
834 isWriteSuccess = WriteCacheByArrayBuffer(uniqueFd, isMovingPhotoVideo);
835 } else if (mode == AddResourceMode::FILE_URI) {
836 isWriteSuccess = SendToCacheFile(uniqueFd, isMovingPhotoVideo);
837 } else {
838 MEDIA_ERR_LOG("Unsupported addResource mode");
839 }
840 return isWriteSuccess;
841 }
842
WriteCacheByArrayBuffer(const OHOS::UniqueFd & destFd,bool isMovingPhotoVideo)843 bool MediaAssetChangeRequestImpl::WriteCacheByArrayBuffer(const OHOS::UniqueFd& destFd, bool isMovingPhotoVideo)
844 {
845 size_t offset = 0;
846 size_t length = isMovingPhotoVideo ? movingPhotoVideoBufferSize_ : dataBufferSize_;
847 void* dataBuffer = isMovingPhotoVideo ? movingPhotoVideoDataBuffer_ : dataBuffer_;
848 while (offset < length) {
849 ssize_t written = write(destFd.Get(), (char*)dataBuffer + offset, length - offset);
850 if (written < 0) {
851 MEDIA_ERR_LOG("Failed to write data buffer to cache file, return %{public}d", static_cast<int>(written));
852 return false;
853 }
854 offset += static_cast<size_t>(written);
855 }
856 return true;
857 }
858
DiscardHighQualityPhoto()859 void MediaAssetChangeRequestImpl::DiscardHighQualityPhoto()
860 {
861 string uriStr = PAH_REMOVE_MSC_TASK;
862 MediaFileUtils::UriAppendKeyValue(uriStr, API_VERSION, to_string(MEDIA_API_VERSION_V10));
863 Uri uri(uriStr);
864 OHOS::DataShare::DataSharePredicates predicates;
865 int errCode = 0;
866
867 auto fileAsset = mediaAsset_->GetFileAssetInstance();
868 vector<string> columns { to_string(fileAsset->GetId()) };
869 UserFileClient::Query(uri, predicates, columns, errCode);
870 }
871