• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #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