• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #define MLOG_TAG "EnhancementServiceCallback"
17 
18 #include "enhancement_service_callback.h"
19 
20 #include "enhancement_database_operations.h"
21 #include "enhancement_manager.h"
22 #include "enhancement_task_manager.h"
23 #include "enhancement_service_adapter.h"
24 #include "media_log.h"
25 #include "medialibrary_errno.h"
26 #include "result_set_utils.h"
27 #include "file_utils.h"
28 #include "medialibrary_object_utils.h"
29 #include "media_file_utils.h"
30 #include "medialibrary_rdb_transaction.h"
31 #include "medialibrary_unistore_manager.h"
32 #include "medialibrary_asset_operations.h"
33 #include "medialibrary_rdb_utils.h"
34 #include "medialibrary_notify.h"
35 #include "photo_file_utils.h"
36 #include "medialibrary_photo_operations.h"
37 #include "mimetype_utils.h"
38 #include "securec.h"
39 #include "moving_photo_file_utils.h"
40 #include "asset_accurate_refresh.h"
41 #include "refresh_business_name.h"
42 
43 using namespace std;
44 #ifdef ABILITY_CLOUD_ENHANCEMENT_SUPPORT
45 using namespace OHOS::MediaEnhance;
46 #endif
47 namespace OHOS {
48 namespace Media {
49 static vector<string> needUpdateUris;
50 
EnhancementServiceCallback()51 EnhancementServiceCallback::EnhancementServiceCallback()
52 {}
53 
~EnhancementServiceCallback()54 EnhancementServiceCallback::~EnhancementServiceCallback()
55 {}
56 
57 #ifdef ABILITY_CLOUD_ENHANCEMENT_SUPPORT
checkStatusCode(int32_t statusCode)58 bool checkStatusCode(int32_t statusCode)
59 {
60     return (statusCode >= static_cast<int32_t>(MediaEnhance_Status_Code::LIMIT_USAGE)
61         && statusCode <= static_cast<int32_t>(MediaEnhance_Status_Code::TASK_CANNOT_EXECUTE))
62         || statusCode == static_cast<int32_t>(MediaEnhance_Status_Code::NON_RECOVERABLE);
63 }
64 
CheckDisplayNameWithType(const string & displayName,int32_t mediaType)65 static int32_t CheckDisplayNameWithType(const string &displayName, int32_t mediaType)
66 {
67     int32_t ret = MediaFileUtils::CheckDisplayName(displayName);
68     CHECK_AND_RETURN_RET_LOG(ret == E_OK, E_INVALID_DISPLAY_NAME, "Check DisplayName failed, "
69         "displayName=%{private}s", displayName.c_str());
70 
71     string ext = MediaFileUtils::GetExtensionFromPath(displayName);
72     CHECK_AND_RETURN_RET_LOG(!ext.empty(), E_INVALID_DISPLAY_NAME, "invalid extension, displayName=%{private}s",
73         displayName.c_str());
74 
75     auto typeFromExt = MediaFileUtils::GetMediaType(displayName);
76     CHECK_AND_RETURN_RET_LOG(typeFromExt == mediaType, E_CHECK_MEDIATYPE_MATCH_EXTENSION_FAIL,
77         "cannot match, mediaType=%{public}d, ext=%{private}s, type from ext=%{public}d",
78         mediaType, ext.c_str(), typeFromExt);
79     return E_OK;
80 }
81 
SetAssetPathInCreate(FileAsset & fileAsset,std::shared_ptr<TransactionOperations> trans)82 static int32_t SetAssetPathInCreate(FileAsset &fileAsset, std::shared_ptr<TransactionOperations> trans)
83 {
84     if (!fileAsset.GetPath().empty()) {
85         return E_OK;
86     }
87     string extension = MediaFileUtils::GetExtensionFromPath(fileAsset.GetDisplayName());
88     string filePath;
89     int32_t uniqueId = MediaLibraryAssetOperations::CreateAssetUniqueId(fileAsset.GetMediaType(), trans);
90     int32_t errCode = MediaLibraryAssetOperations::CreateAssetPathById(uniqueId, fileAsset.GetMediaType(),
91         extension, filePath);
92     if (errCode != E_OK) {
93         MEDIA_ERR_LOG("Create Asset Path failed, errCode=%{public}d", errCode);
94         return errCode;
95     }
96 
97     // filePath can not be empty
98     fileAsset.SetPath(filePath);
99     return E_OK;
100 }
101 
CheckAddrAndBytes(CloudEnhancementThreadTask & task)102 static int32_t CheckAddrAndBytes(CloudEnhancementThreadTask& task)
103 {
104     if (task.addr == nullptr || task.bytes == 0) {
105         MEDIA_ERR_LOG("task.addr is nullptr or task.bytes(%{public}u) is 0", task.bytes);
106         delete[] task.addr;
107         task.addr = nullptr;
108         return E_ERR;
109     }
110     return E_OK;
111 }
112 
SaveCloudEnhancementPhoto(shared_ptr<CloudEnhancementFileInfo> info,CloudEnhancementThreadTask & task,shared_ptr<NativeRdb::ResultSet> resultSet)113 int32_t EnhancementServiceCallback::SaveCloudEnhancementPhoto(shared_ptr<CloudEnhancementFileInfo> info,
114     CloudEnhancementThreadTask& task, shared_ptr<NativeRdb::ResultSet> resultSet)
115 {
116     CHECK_AND_RETURN_RET(CheckAddrAndBytes(task) == E_OK, E_ERR);
117     CHECK_AND_RETURN_RET_LOG(MediaFileUtils::CheckDisplayName(info->displayName) == E_OK,
118         E_ERR, "display name not valid");
119     auto pos = info->displayName.rfind('.');
120     string prefix = info->displayName.substr(0, pos);
121     string suffix = info->displayName.substr(pos);
122     string newDisplayName = prefix + "_enhanced" + suffix;
123     string newFilePath;
124     int32_t newFileId = -1;
125     shared_ptr<CloudEnhancementFileInfo> newFileInfo = make_shared<CloudEnhancementFileInfo>(0, newFilePath,
126         newDisplayName, info->subtype, info->hidden);
127     newFileId = CreateCloudEnhancementPhoto(info->fileId, newFileInfo, resultSet);
128     CHECK_AND_RETURN_RET_LOG(newFileId > 0, newFileId, "insert file in db failed, error = %{public}d", newFileId);
129     int32_t ret = FileUtils::SaveImage(newFileInfo->filePath, (void*)(task.addr), static_cast<size_t>(task.bytes));
130     delete[] task.addr;
131     task.addr = nullptr;
132     CHECK_AND_RETURN_RET_LOG(ret == E_OK, ret, "save cloud enhancement image failed. ret=%{public}d, errno=%{public}d",
133         ret, errno);
134     int32_t effectMode = GetInt32Val(PhotoColumn::MOVING_PHOTO_EFFECT_MODE, resultSet);
135     int32_t originalSubtype = GetInt32Val(PhotoColumn::PHOTO_ORIGINAL_SUBTYPE, resultSet);
136     if (MovingPhotoFileUtils::IsMovingPhoto(info->subtype, effectMode, originalSubtype)) {
137         string sourceVideoPath = MediaFileUtils::GetMovingPhotoVideoPath(info->filePath);
138         string newVideoPath = MediaFileUtils::GetMovingPhotoVideoPath(newFileInfo->filePath);
139         bool copyResult = MediaFileUtils::CopyFileUtil(sourceVideoPath, newVideoPath);
140         if (!copyResult) {
141             MEDIA_ERR_LOG(
142                 "save moving photo video failed. file_id: %{public}d, errno=%{public}d", newFileId, errno);
143         }
144     }
145     string editDataCameraSourcePath = PhotoFileUtils::GetEditDataCameraPath(info->filePath);
146     if (MediaFileUtils::IsFileExists(editDataCameraSourcePath)) {
147         string extension = MediaFileUtils::GetExtensionFromPath(info->filePath);
148         string mimeType = MimeTypeUtils::GetMimeTypeFromExtension(extension);
149         MediaLibraryPhotoOperations::AddFiltersForCloudEnhancementPhoto(newFileId,
150             newFileInfo->filePath, editDataCameraSourcePath, mimeType);
151     }
152     int64_t permId = EnhancementDatabaseOperations::InsertCloudEnhancementPerm(info->fileId, newFileId);
153     MEDIA_INFO_LOG("Add Permission for cloud enhancement photo, perm row: %{public}ld", permId);
154     MediaLibraryObjectUtils::ScanFileSyncWithoutAlbumUpdate(newFileInfo->filePath,
155         to_string(newFileId), MediaLibraryApi::API_10);
156     string newFileUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(newFileId),
157         MediaFileUtils::GetExtraUri(newFileInfo->displayName, newFileInfo->filePath));
158     needUpdateUris.emplace_back(newFileUri);
159     return newFileId;
160 }
161 
CreateCloudEnhancementPhoto(int32_t sourceFileId,shared_ptr<CloudEnhancementFileInfo> info,shared_ptr<NativeRdb::ResultSet> resultSet)162 int32_t EnhancementServiceCallback::CreateCloudEnhancementPhoto(int32_t sourceFileId,
163     shared_ptr<CloudEnhancementFileInfo> info, shared_ptr<NativeRdb::ResultSet> resultSet)
164 {
165     MediaLibraryCommand cmd(OperationObject::FILESYSTEM_PHOTO, OperationType::CREATE);
166     FileAsset fileAsset;
167     fileAsset.SetDisplayName(info->displayName);
168     fileAsset.SetTimePending(UNCREATE_FILE_TIMEPENDING);
169     fileAsset.SetMediaType(MediaType::MEDIA_TYPE_IMAGE);
170     // Check rootdir
171     int32_t errCode = CheckDisplayNameWithType(info->displayName, static_cast<int32_t>(MediaType::MEDIA_TYPE_IMAGE));
172     CHECK_AND_RETURN_RET(errCode == E_OK, errCode);
173     std::shared_ptr<TransactionOperations> trans = make_shared<TransactionOperations>(__func__);
174     int32_t outRow = -1;
175     std::function<int(void)> func = [&]()->int {
176         errCode = SetAssetPathInCreate(fileAsset, trans);
177         CHECK_AND_RETURN_RET_LOG(errCode == E_OK, errCode,
178             "Failed to Solve FileAsset Path and Name, displayName=%{private}s", info->displayName.c_str());
179         outRow = EnhancementDatabaseOperations::InsertCloudEnhancementImageInDb(cmd, fileAsset,
180             sourceFileId, info, resultSet, trans);
181         CHECK_AND_RETURN_RET_LOG(outRow > 0, E_HAS_DB_ERROR, "insert file in db failed, error = %{public}d", outRow);
182         fileAsset.SetId(outRow);
183         return errCode;
184     };
185     errCode = trans->RetryTrans(func);
186     if (errCode != E_OK) {
187         MEDIA_ERR_LOG("CreateCloudEnhancementPhoto: tans finish fail!, ret:%{public}d", errCode);
188         return errCode;
189     }
190     info->filePath = fileAsset.GetPath();
191     return outRow;
192 }
193 
OnSuccess(const char * photoId,MediaEnhanceBundleHandle * bundle)194 void EnhancementServiceCallback::OnSuccess(const char* photoId, MediaEnhanceBundleHandle* bundle)
195 {
196     string taskId = string(photoId);
197     MEDIA_INFO_LOG("callback OnSuccess start, photo_id: %{public}s", taskId.c_str());
198     CHECK_AND_RETURN_LOG(!taskId.empty(), "enhancement callback error: taskId is empty");
199     CHECK_AND_RETURN_LOG(bundle != nullptr, "enhancement callback error: bundle is nullptr");
200     EnhancementTaskManager::SetTaskRequestCount(taskId, 1);
201     CloudEnhancementThreadTask task(taskId, 0, nullptr, 0, true);
202     int32_t ret = EnhancementManager::GetInstance().enhancementService_->FillTaskWithResultBuffer(bundle, task);
203     CHECK_AND_RETURN_LOG(ret == E_OK, "enhancement callback error: FillTaskWithResultBuffer failed");
204     EnhancementManager::GetInstance().threadManager_->OnProducerCallback(task);
205     MEDIA_INFO_LOG("callback OnSuccess: add %{public}s to queue", photoId);
206 }
207 
OnFailed(const char * photoId,MediaEnhanceBundleHandle * bundle)208 void EnhancementServiceCallback::OnFailed(const char* photoId, MediaEnhanceBundleHandle* bundle)
209 {
210     string taskId = string(photoId);
211     CHECK_AND_RETURN_LOG(!taskId.empty(), "enhancement callback error: taskId is empty");
212     CHECK_AND_RETURN_LOG(bundle != nullptr, "enhancement callback error: bundle is nullptr");
213     int32_t statusCode = EnhancementManager::GetInstance().enhancementService_->GetInt(bundle,
214         MediaEnhance_Bundle_Key::ERROR_CODE);
215     MEDIA_INFO_LOG("callback start, photo_id: %{public}s enter, status code: %{public}d", taskId.c_str(), statusCode);
216     CHECK_AND_RETURN_LOG(checkStatusCode(statusCode),
217         "status code is invalid, task id:%{public}s, statusCode: %{public}d", taskId.c_str(), statusCode);
218     CloudEnhancementThreadTask task(taskId, statusCode, nullptr, 0, false);
219     EnhancementManager::GetInstance().threadManager_->OnProducerCallback(task);
220     MEDIA_INFO_LOG("callback OnFailed: add %{public}s to queue", photoId);
221 }
222 
OnServiceReconnected()223 void EnhancementServiceCallback::OnServiceReconnected()
224 {
225     MEDIA_INFO_LOG("Cloud enhancement service is reconnected, try to submit processing tasks");
226     EnhancementManager::GetInstance().Init();
227 }
228 
DealWithSuccessedTask(CloudEnhancementThreadTask & task)229 void EnhancementServiceCallback::DealWithSuccessedTask(CloudEnhancementThreadTask& task)
230 {
231     string taskId = task.taskId;
232     MEDIA_INFO_LOG("DealWithSuccessedTask start, photo_id: %{public}s", taskId.c_str());
233     // query 100 per
234     string where = PhotoColumn::PHOTO_ID + " = ? ";
235     vector<string> whereArgs { taskId };
236     NativeRdb::RdbPredicates servicePredicates(PhotoColumn::PHOTOS_TABLE);
237     servicePredicates.SetWhereClause(where);
238     servicePredicates.SetWhereArgs(whereArgs);
239     vector<string> columns;
240     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
241     CHECK_AND_RETURN_LOG(resultSet != nullptr && resultSet->GoToFirstRow() == E_OK,
242         "enhancement callback error: query result set is empty");
243     int32_t sourceFileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
244     string sourceFilePath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
245     string sourceDisplayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
246     int32_t hidden = GetInt32Val(MediaColumn::MEDIA_HIDDEN, resultSet);
247     int32_t sourceSubtype = GetInt32Val(PhotoColumn::PHOTO_SUBTYPE, resultSet);
248     int32_t sourceCEAvailable = GetInt32Val(PhotoColumn::PHOTO_CE_AVAILABLE, resultSet);
249     CHECK_AND_PRINT_LOG((sourceCEAvailable == static_cast<int32_t>(CloudEnhancementAvailableType::PROCESSING_MANUAL) ||
250         sourceCEAvailable == static_cast<int32_t>(CloudEnhancementAvailableType::PROCESSING_AUTO)),
251         "enhancement callback error: db CE_AVAILABLE status not processing, file_id: %{public}d", sourceFileId);
252     // save 120 per
253     shared_ptr<CloudEnhancementFileInfo> info = make_shared<CloudEnhancementFileInfo>(sourceFileId,
254         sourceFilePath, sourceDisplayName, sourceSubtype, hidden);
255     int32_t newFileId = SaveCloudEnhancementPhoto(info, task, resultSet);
256     CHECK_AND_RETURN_LOG(newFileId > 0, "invalid file id");
257     resultSet->Close();
258     NativeRdb::ValuesBucket rdbValues;
259     rdbValues.PutInt(PhotoColumn::PHOTO_CE_AVAILABLE, static_cast<int32_t>(CloudEnhancementAvailableType::SUCCESS));
260     rdbValues.PutInt(PhotoColumn::PHOTO_STRONG_ASSOCIATION,
261         static_cast<int32_t>(StrongAssociationType::NORMAL));
262     rdbValues.PutInt(PhotoColumn::PHOTO_ASSOCIATE_FILE_ID, newFileId);
263     auto assetRefresh = make_shared<AccurateRefresh::AssetAccurateRefresh>(
264         AccurateRefresh::DEAL_WITH_SUCCESSED_BUSSINESS_NAME);
265     int32_t ret = EnhancementDatabaseOperations::Update(rdbValues, servicePredicates, assetRefresh);
266     CHECK_AND_PRINT_LOG(ret == E_OK, "update source photo failed. ret: %{public}d, photoId: %{public}s",
267         ret, taskId.c_str());
268     int32_t taskType = EnhancementTaskManager::QueryTaskTypeByPhotoId(taskId);
269     EnhancementTaskManager::RemoveEnhancementTask(taskId);
270     CloudEnhancementGetCount::GetInstance().Report("SuccessType", taskId, taskType);
271     string fileUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(sourceFileId),
272         MediaFileUtils::GetExtraUri(sourceDisplayName, sourceFilePath));
273     auto watch = MediaLibraryNotify::GetInstance();
274     if (watch != nullptr) {
275         watch->Notify(fileUri, NotifyType::NOTIFY_UPDATE);
276     }
277     assetRefresh->Notify();
278     MEDIA_INFO_LOG("DealWithSuccessedTask success, photo_id: %{public}s", taskId.c_str());
279 }
280 
DealWithFailedTask(CloudEnhancementThreadTask & task)281 void EnhancementServiceCallback::DealWithFailedTask(CloudEnhancementThreadTask& task)
282 {
283     string taskId = task.taskId;
284     MEDIA_INFO_LOG("DealWithFailedTask start, photo_id: %{public}s", taskId.c_str());
285     int32_t statusCode = task.statusCode;
286     NativeRdb::RdbPredicates servicePredicates(PhotoColumn::PHOTOS_TABLE);
287     servicePredicates.EqualTo(PhotoColumn::PHOTO_ID, taskId);
288     vector<string> columns { MediaColumn::MEDIA_ID, MediaColumn::MEDIA_FILE_PATH,
289         MediaColumn::MEDIA_NAME, PhotoColumn::PHOTO_CE_AVAILABLE};
290     auto resultSet = MediaLibraryRdbStore::QueryWithFilter(servicePredicates, columns);
291     if (resultSet == nullptr || resultSet->GoToFirstRow() != E_OK) {
292         MEDIA_ERR_LOG("enhancement callback error: query result set is empty");
293         return;
294     }
295     int32_t fileId = GetInt32Val(MediaColumn::MEDIA_ID, resultSet);
296     string filePath = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSet);
297     string displayName = GetStringVal(MediaColumn::MEDIA_NAME, resultSet);
298     int32_t ceAvailable = GetInt32Val(PhotoColumn::PHOTO_CE_AVAILABLE, resultSet);
299     resultSet->Close();
300     CHECK_AND_PRINT_LOG((ceAvailable == static_cast<int32_t>(CloudEnhancementAvailableType::PROCESSING_MANUAL) ||
301         ceAvailable == static_cast<int32_t>(CloudEnhancementAvailableType::PROCESSING_AUTO)),
302         "enhancement callback error: db CE_AVAILABLE status not processing, file_id: %{public}d", fileId);
303     NativeRdb::ValuesBucket valueBucket;
304     if (statusCode == static_cast<int32_t>(CEErrorCodeType::EXECUTE_FAILED) ||
305         statusCode == static_cast<int32_t>(CEErrorCodeType::NON_RECOVERABLE)) {
306         valueBucket.Put(PhotoColumn::PHOTO_CE_AVAILABLE,
307             static_cast<int32_t>(CloudEnhancementAvailableType::FAILED));
308     } else {
309         valueBucket.Put(PhotoColumn::PHOTO_CE_AVAILABLE,
310             static_cast<int32_t>(CloudEnhancementAvailableType::FAILED_RETRY));
311     }
312     valueBucket.Put(PhotoColumn::PHOTO_CE_STATUS_CODE, statusCode);
313     servicePredicates.NotEqualTo(PhotoColumn::PHOTO_CE_AVAILABLE,
314         static_cast<int32_t>(CloudEnhancementAvailableType::SUCCESS));
315     auto assetRefresh = make_shared<AccurateRefresh::AssetAccurateRefresh>(
316         AccurateRefresh::DEAL_WITH_FAILED_BUSSINESS_NAME);
317     int32_t ret = EnhancementDatabaseOperations::Update(valueBucket, servicePredicates, assetRefresh);
318     CHECK_AND_RETURN_LOG(ret == E_OK, "enhancement callback error: db CE_AVAILABLE status update failed");
319     int32_t taskType = EnhancementTaskManager::QueryTaskTypeByPhotoId(taskId);
320     EnhancementTaskManager::RemoveEnhancementTask(taskId);
321     CloudEnhancementGetCount::GetInstance().Report("FailedType", taskId, taskType);
322     string fileUri = MediaFileUtils::GetUriByExtrConditions(PhotoColumn::PHOTO_URI_PREFIX, to_string(fileId),
323         MediaFileUtils::GetExtraUri(displayName, filePath));
324     auto watch = MediaLibraryNotify::GetInstance();
325     if (watch != nullptr) {
326         watch->Notify(fileUri, NotifyType::NOTIFY_UPDATE);
327     }
328     assetRefresh->Notify();
329     MEDIA_INFO_LOG("DealWithFailedTask success, photo_id: %{public}s", taskId.c_str());
330 }
331 
UpdateAlbumsForCloudEnhancement()332 void EnhancementServiceCallback::UpdateAlbumsForCloudEnhancement()
333 {
334     MEDIA_INFO_LOG("UpdateAlbumsForCloudEnhancement start");
335     bool sourceAlbumNotify = true;
336     if (!needUpdateUris.empty()) {
337         auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
338         CHECK_AND_RETURN_LOG(rdbStore != nullptr, "Failed to get rdbStore.");
339         MediaLibraryRdbUtils::UpdateSystemAlbumsByUris(rdbStore, AlbumOperationType::DEFAULT,
340             needUpdateUris, NotifyAlbumType::SYS_ALBUM);
341         MediaLibraryRdbUtils::UpdateCommonAlbumByUri(rdbStore, needUpdateUris, true);
342         needUpdateUris.clear();
343     } else {
344         MEDIA_INFO_LOG("no uris need to update albums");
345     }
346     MEDIA_INFO_LOG("UpdateAlbumsForCloudEnhancement end");
347 }
348 #endif
349 } // namespace Media
350 } // namespace OHOS