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 "CloudMediaAssetOperations"
17 
18 #include "cloud_media_asset_download_operation.h"
19 
20 #include <iostream>
21 #include <thread>
22 #include <mutex>
23 #include <condition_variable>
24 #include <vector>
25 #include <atomic>
26 #include <memory>
27 #include <chrono>
28 #include <algorithm>
29 #include <map>
30 
31 #include "common_event_utils.h"
32 #include "cloud_sync_common.h"
33 #include "cloud_sync_constants.h"
34 #include "cloud_sync_manager.h"
35 #include "cloud_sync_utils.h"
36 #include "datashare_helper.h"
37 #include "iservice_registry.h"
38 #include "media_column.h"
39 #include "media_file_utils.h"
40 #include "media_log.h"
41 #include "medialibrary_command.h"
42 #include "medialibrary_db_const.h"
43 #include "medialibrary_errno.h"
44 #include "medialibrary_operation.h"
45 #include "medialibrary_rdb_utils.h"
46 #include "medialibrary_rdbstore.h"
47 #include "medialibrary_subscriber.h"
48 #include "medialibrary_tracer.h"
49 #include "medialibrary_type_const.h"
50 #include "medialibrary_unistore_manager.h"
51 #include "rdb_store.h"
52 #include "result_set_utils.h"
53 #include "wifi_device.h"
54 #include "thermal_mgr_client.h"
55 #include "userfile_manager_types.h"
56 
57 using namespace std;
58 using namespace OHOS::DataShare;
59 using namespace OHOS::NativeRdb;
60 namespace OHOS {
61 namespace Media {
62 using namespace FileManagement::CloudSync;
63 using Status = CloudMediaAssetDownloadOperation::Status;
64 std::mutex CloudMediaAssetDownloadOperation::mutex_;
65 std::mutex CloudMediaAssetDownloadOperation::callbackMutex_;
66 std::shared_ptr<CloudMediaAssetDownloadOperation> CloudMediaAssetDownloadOperation::instance_ = nullptr;
67 static const int32_t PROPER_DEVICE_TEMPERATURE_LEVEL_HOT = 3;
68 static const int32_t BATCH_DOWNLOAD_CLOUD_FILE = 10;
69 static constexpr int STORAGE_MANAGER_MANAGER_ID = 5003;
70 static constexpr int CLOUD_MANAGER_MANAGER_ID = 5204;
71 static const std::string CLOUD_DATASHARE_URI = "datashareproxy://generic.cloudstorage/cloud_sp?Proxy=true";
72 static const std::string CLOUD_URI = CLOUD_DATASHARE_URI + "&key=useMobileNetworkData";
73 static const int64_t DOWNLOAD_ID_DEFAULT = -1;
74 static const std::string TOTAL_COUNT = "COUNT(1)";
75 static const std::string TOTAL_SIZE = "SUM(size)";
76 static const bool NEED_CLEAN = true;
77 static const int32_t EXIT_TASK = 1;
78 // CLOUD_E_PATH_NOT_FOUND and CLOUD_E_RDB corresponds to the E_PATH and E_RDB of dfs_error.h
79 static const int32_t CLOUD_E_PATH_NOT_FOUND = 28;
80 static const int32_t CLOUD_E_RDB = 22;
81 static const int32_t SLEEP_FOR_LOCK = 100;
82 static const int32_t STATUS_CHANGE_ARG_SIZE = 3;
83 static const int32_t INDEX_ZERO = 0;
84 static const int32_t INDEX_ONE = 1;
85 static const int32_t INDEX_TWO = 2;
86 
87 static const std::map<Status, std::vector<int32_t>> STATUS_MAP = {
88     { Status::FORCE_DOWNLOADING, {0, 0, 0} },
89     { Status::GENTLE_DOWNLOADING, {1, 0, 0} },
90     { Status::PAUSE_FOR_TEMPERATURE_LIMIT, {-1, 1, 1} },
91     { Status::PAUSE_FOR_ROM_LIMIT, {-1, 1, 2} },
92     { Status::PAUSE_FOR_NETWORK_FLOW_LIMIT, {-1, 1, 3} },
93     { Status::PAUSE_FOR_WIFI_UNAVAILABLE, {-1, 1, 4} },
94     { Status::PAUSE_FOR_POWER_LIMIT, {-1, 1, 5} },
95     { Status::PAUSE_FOR_BACKGROUND_TASK_UNAVAILABLE, {1, 1, 6} },
96     { Status::PAUSE_FOR_FREQUENT_USER_REQUESTS, {-1, 1, 7} },
97     { Status::PAUSE_FOR_CLOUD_ERROR, {-1, 1, 8} },
98     { Status::PAUSE_FOR_USER_PAUSE, {-1, 1, 9} },
99     { Status::RECOVER_FOR_MANAUL_ACTIVE, {0, 0, 0} },
100     { Status::RECOVER_FOR_PASSIVE_STATUS, {-1, 0, 0} },
101     { Status::IDLE, {-1, 2, 0} },
102 };
103 
104 static const std::map<CloudMediaTaskRecoverCause, CloudMediaTaskPauseCause> RECOVER_RELATIONSHIP_MAP = {
105     { CloudMediaTaskRecoverCause::FOREGROUND_TEMPERATURE_PROPER, CloudMediaTaskPauseCause::TEMPERATURE_LIMIT },
106     { CloudMediaTaskRecoverCause::NETWORK_FLOW_UNLIMIT, CloudMediaTaskPauseCause::NETWORK_FLOW_LIMIT },
107     { CloudMediaTaskRecoverCause::BACKGROUND_TASK_AVAILABLE, CloudMediaTaskPauseCause::BACKGROUND_TASK_UNAVAILABLE },
108     { CloudMediaTaskRecoverCause::RETRY_FOR_FREQUENT_REQUESTS, CloudMediaTaskPauseCause::FREQUENT_USER_REQUESTS },
109     { CloudMediaTaskRecoverCause::RETRY_FOR_CLOUD_ERROR, CloudMediaTaskPauseCause::CLOUD_ERROR },
110 };
111 
OnRemoteDied(const wptr<IRemoteObject> & object)112 void CloudDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
113 {
114     MEDIA_INFO_LOG("enter.");
115     if (!operation_ || operation_->GetTaskStatus() != CloudMediaAssetTaskStatus::DOWNLOADING) {
116         MEDIA_ERR_LOG("operation is nullptr or taskStatus is not DOWNLOADING");
117         return;
118     }
119     if (object == nullptr) {
120         MEDIA_ERR_LOG("remote object is nullptr");
121         return;
122     }
123     object->RemoveDeathRecipient(this);
124     operation_->CancelDownloadTask();
125 }
126 
GetInstance()127 std::shared_ptr<CloudMediaAssetDownloadOperation> CloudMediaAssetDownloadOperation::GetInstance()
128 {
129     if (instance_ == nullptr) {
130         instance_ = std::make_shared<CloudMediaAssetDownloadOperation>();
131         MEDIA_INFO_LOG("create cloud media asset task.");
132     }
133     return instance_;
134 }
135 
IsProperFgTemperature()136 bool CloudMediaAssetDownloadOperation::IsProperFgTemperature()
137 {
138     return CommonEventUtils::GetThermalLevel() <= PROPER_DEVICE_TEMPERATURE_LEVEL_HOT;
139 }
140 
SetTaskStatus(Status status)141 void CloudMediaAssetDownloadOperation::SetTaskStatus(Status status)
142 {
143     std::vector<int32_t> statusChangeVec = STATUS_MAP.at(status);
144     if (static_cast<int32_t>(statusChangeVec.size()) != STATUS_CHANGE_ARG_SIZE) {
145         MEDIA_ERR_LOG("change status failed.");
146         return;
147     }
148     if (statusChangeVec[INDEX_ZERO] >= 0) {
149         downloadType_ = static_cast<CloudMediaDownloadType>(statusChangeVec[INDEX_ZERO]);
150     }
151     taskStatus_ = static_cast<CloudMediaAssetTaskStatus>(statusChangeVec[INDEX_ONE]);
152     pauseCause_ = static_cast<CloudMediaTaskPauseCause>(statusChangeVec[INDEX_TWO]);
153     MEDIA_INFO_LOG("SetTaskStatus, downloadType_: %{public}d, taskStatus_: %{public}d, pauseCause_: %{public}d",
154         statusChangeVec[INDEX_ZERO], statusChangeVec[INDEX_ONE], statusChangeVec[INDEX_TWO]);
155 }
156 
ClearData(CloudMediaAssetDownloadOperation::DownloadFileData & data)157 void CloudMediaAssetDownloadOperation::ClearData(CloudMediaAssetDownloadOperation::DownloadFileData &data)
158 {
159     data.pathVec.clear();
160     data.fileDownloadMap.clear();
161     data.batchFileIdNeedDownload.clear();
162     data.batchSizeNeedDownload = 0;
163     data.batchCountNeedDownload = 0;
164 }
165 
IsDataEmpty(const CloudMediaAssetDownloadOperation::DownloadFileData & data)166 bool CloudMediaAssetDownloadOperation::IsDataEmpty(const CloudMediaAssetDownloadOperation::DownloadFileData &data)
167 {
168     return data.fileDownloadMap.empty();
169 }
170 
IsNetworkUnavailable()171 bool CloudMediaAssetDownloadOperation::IsNetworkUnavailable()
172 {
173     return (MedialibrarySubscriber::IsWifiConnected() ||
174         (MedialibrarySubscriber::IsCellularNetConnected() && isUnlimitedTrafficStatusOn_));
175 }
176 
QueryDownloadFilesNeeded(const bool & isQueryInfo)177 std::shared_ptr<NativeRdb::ResultSet> CloudMediaAssetDownloadOperation::QueryDownloadFilesNeeded(
178     const bool &isQueryInfo)
179 {
180     auto rdbStore = MediaLibraryUnistoreManager::GetInstance().GetRdbStore();
181     if (rdbStore == nullptr) {
182         MEDIA_ERR_LOG("QueryDownloadFilesNeeded failed. rdbStore is null");
183         return nullptr;
184     }
185     AbsRdbPredicates predicates(PhotoColumn::PHOTOS_TABLE);
186     predicates.EqualTo(PhotoColumn::PHOTO_SYNC_STATUS, to_string(static_cast<int32_t>(SyncStatusType::TYPE_VISIBLE)));
187     predicates.EqualTo(PhotoColumn::PHOTO_CLEAN_FLAG, to_string(static_cast<int32_t>(CleanType::TYPE_NOT_CLEAN)));
188     predicates.EqualTo(MediaColumn::MEDIA_TIME_PENDING, "0");
189     predicates.EqualTo(PhotoColumn::PHOTO_IS_TEMP, "0");
190     predicates.IsNotNull(MediaColumn::MEDIA_FILE_PATH);
191     predicates.EqualTo(PhotoColumn::PHOTO_POSITION, to_string(static_cast<int32_t>(PhotoPositionType::CLOUD)));
192     predicates.BeginWrap();
193     predicates.EqualTo(MediaColumn::MEDIA_TYPE, to_string(static_cast<int32_t>(MEDIA_TYPE_IMAGE)));
194     predicates.Or();
195     predicates.EqualTo(MediaColumn::MEDIA_TYPE, to_string(static_cast<int32_t>(MEDIA_TYPE_VIDEO)));
196     predicates.EndWrap();
197     if (isQueryInfo) {
198         predicates.EqualTo(PhotoColumn::PHOTO_BURST_COVER_LEVEL,
199             to_string(static_cast<int32_t>(BurstCoverLevelType::COVER)));
200         const std::vector<std::string> columns = {
201             TOTAL_COUNT,
202             TOTAL_SIZE
203         };
204         return rdbStore->Query(predicates, columns);
205     }
206     if (static_cast<int32_t>(dataForDownload_.batchFileIdNeedDownload.size()) > 0) {
207         predicates.NotIn(PhotoColumn::MEDIA_ID, dataForDownload_.batchFileIdNeedDownload);
208     }
209     predicates.OrderByDesc(MediaColumn::MEDIA_DATE_MODIFIED);
210     predicates.Limit(BATCH_DOWNLOAD_CLOUD_FILE);
211     const std::vector<std::string> columns = {
212         MediaColumn::MEDIA_ID,
213         MediaColumn::MEDIA_FILE_PATH,
214         MediaColumn::MEDIA_SIZE,
215         PhotoColumn::PHOTO_BURST_COVER_LEVEL
216     };
217     return rdbStore->Query(predicates, columns);
218 }
219 
InitDownloadTaskInfo()220 int32_t CloudMediaAssetDownloadOperation::InitDownloadTaskInfo()
221 {
222     if (!isThumbnailUpdate_) {
223         MEDIA_INFO_LOG("No need to update InitDownloadTaskInfo.");
224         return E_OK;
225     }
226     std::shared_ptr<NativeRdb::ResultSet> resultSetForInfo = QueryDownloadFilesNeeded(true);
227     if (resultSetForInfo == nullptr || resultSetForInfo->GoToNextRow() != NativeRdb::E_OK) {
228         MEDIA_ERR_LOG("queryResult is invalid!");
229         return E_ERR;
230     }
231     int32_t count = GetInt32Val(TOTAL_COUNT, resultSetForInfo);
232     if (count == 0) {
233         MEDIA_ERR_LOG("no cloud media asset need to download");
234         return E_ERR;
235     }
236     int64_t size = GetInt64Val(TOTAL_SIZE, resultSetForInfo);
237 
238     int64_t hasDownloadNum_ = totalCount_ - remainCount_;
239     int64_t hasDownloadSize_ = totalSize_ - remainSize_;
240     remainCount_ = count;
241     remainSize_ = size;
242     totalCount_ = remainCount_ + hasDownloadNum_;
243     totalSize_ = remainSize_ + hasDownloadSize_;
244     isThumbnailUpdate_ = false;
245     resultSetForInfo->Close();
246     MEDIA_INFO_LOG("GetTaskInfo: %{public}s", GetTaskInfo().c_str());
247     return E_OK;
248 }
249 
ReadyDataForBatchDownload()250 CloudMediaAssetDownloadOperation::DownloadFileData CloudMediaAssetDownloadOperation::ReadyDataForBatchDownload()
251 {
252     MEDIA_INFO_LOG("enter ReadyDataForBatchDownload");
253     InitDownloadTaskInfo();
254 
255     CloudMediaAssetDownloadOperation::DownloadFileData data;
256     std::shared_ptr<NativeRdb::ResultSet> resultSetForDownload = QueryDownloadFilesNeeded(false);
257     if (resultSetForDownload == nullptr) {
258         MEDIA_ERR_LOG("resultSetForDownload is nullptr.");
259         return data;
260     }
261 
262     while (resultSetForDownload->GoToNextRow() == NativeRdb::E_OK) {
263         std::string fileId = GetStringVal(MediaColumn::MEDIA_ID, resultSetForDownload);
264         std::string path = GetStringVal(MediaColumn::MEDIA_FILE_PATH, resultSetForDownload);
265         if (fileId.empty() || path.empty()) {
266             MEDIA_ERR_LOG("empty fileId or filePath, fileId: %{public}s, filePath: %{public}s.",
267                 fileId.c_str(), MediaFileUtils::DesensitizePath(path).c_str());
268             continue;
269         }
270         int64_t fileSize = GetInt64Val(PhotoColumn::MEDIA_SIZE, resultSetForDownload);
271 
272         data.pathVec.push_back(path);
273         int32_t burstCoverLevel = GetInt32Val(PhotoColumn::PHOTO_BURST_COVER_LEVEL, resultSetForDownload);
274         if (burstCoverLevel == static_cast<int32_t>(BurstCoverLevelType::COVER)) {
275             data.fileDownloadMap[path] = fileSize;
276             data.batchSizeNeedDownload += fileSize;
277             data.batchCountNeedDownload++;
278         } else {
279             data.fileDownloadMap[path] = 0;
280         }
281         data.batchFileIdNeedDownload.push_back(fileId);
282     }
283     resultSetForDownload->Close();
284     MEDIA_INFO_LOG("end ReadyDataForBatchDownload");
285     return data;
286 }
287 
StartFileCacheFailed(const int64_t batchNum,const int64_t batchSize)288 void CloudMediaAssetDownloadOperation::StartFileCacheFailed(const int64_t batchNum, const int64_t batchSize)
289 {
290     downloadId_ = DOWNLOAD_ID_DEFAULT;
291     if (isCache_) {
292         ClearData(cacheForDownload_);
293     }
294     ClearData(readyForDownload_);
295     ClearData(dataForDownload_);
296     isThumbnailUpdate_ = true;
297     // prepare for data consumption time, don't move this line
298     CloudMediaAssetDownloadOperation::DownloadFileData data = ReadyDataForBatchDownload();
299     if  (IsDataEmpty(data)) {
300         CancelDownloadTask();
301         return;
302     }
303     readyForDownload_ = data;
304     // prepare the data and then set task status
305     SetTaskStatus(Status::PAUSE_FOR_CLOUD_ERROR);
306 }
307 
StartBatchDownload(const int64_t batchNum,const int64_t batchSize)308 void CloudMediaAssetDownloadOperation::StartBatchDownload(const int64_t batchNum, const int64_t batchSize)
309 {
310     std::thread([this, batchNum, batchSize]() {
311         this_thread::sleep_for(chrono::milliseconds(SLEEP_FOR_LOCK));
312         int32_t ret = cloudSyncManager_.get().StartFileCache(dataForDownload_.pathVec, downloadId_,
313             FieldKey::FIELDKEY_CONTENT, downloadCallback_);
314         if (ret == CLOUD_E_RDB || ret == CLOUD_E_PATH_NOT_FOUND) {
315             MEDIA_INFO_LOG("failed to StartFileCache, ret: %{public}d, downloadId_: %{public}s.",
316                 ret, to_string(downloadId_).c_str());
317             StartFileCacheFailed(batchNum, batchSize);
318             return;
319         }
320         if (ret != E_OK || downloadId_ == DOWNLOAD_ID_DEFAULT) {
321             MEDIA_ERR_LOG("failed to StartFileCache, ret: %{public}d, downloadId_: %{public}s.",
322                 ret, to_string(downloadId_).c_str());
323             downloadId_ = DOWNLOAD_ID_DEFAULT;
324             cacheForDownload_ = dataForDownload_;
325             SetTaskStatus(Status::PAUSE_FOR_CLOUD_ERROR);
326             return;
327         }
328         MEDIA_INFO_LOG("Success, downloadId: %{public}d, downloadNum: %{public}d, isCache: %{public}d.",
329             static_cast<int32_t>(downloadId_), static_cast<int32_t>(dataForDownload_.fileDownloadMap.size()),
330             static_cast<int32_t>(isCache_));
331         if (isCache_) {
332             ClearData(cacheForDownload_);
333             return;
334         }
335         CloudMediaAssetDownloadOperation::DownloadFileData data = ReadyDataForBatchDownload();
336         if (taskStatus_ == CloudMediaAssetTaskStatus::IDLE) {
337             MEDIA_INFO_LOG("taskStatus_ is IDLE.");
338             return;
339         }
340         ClearData(readyForDownload_);
341         readyForDownload_ = data;
342     }).detach();
343 }
344 
SubmitBatchDownload(CloudMediaAssetDownloadOperation::DownloadFileData & data,const bool & isCache)345 int32_t CloudMediaAssetDownloadOperation::SubmitBatchDownload(
346     CloudMediaAssetDownloadOperation::DownloadFileData &data, const bool &isCache)
347 {
348     std::lock_guard<std::mutex> lock(mutex_);
349     if (taskStatus_ != CloudMediaAssetTaskStatus::DOWNLOADING || downloadId_ != DOWNLOAD_ID_DEFAULT) {
350         MEDIA_INFO_LOG("SubmitBatchDownload permission denied, taskStatus_: %{public}d.",
351             static_cast<int32_t>(taskStatus_));
352         return E_ERR;
353     }
354     isCache_ = isCache;
355     if (IsDataEmpty(data)) {
356         MEDIA_INFO_LOG("No data need to submit.");
357         if (!isCache_) {
358             CancelDownloadTask();
359             return EXIT_TASK;
360         }
361         return E_OK;
362     }
363     dataForDownload_ = data;
364 
365     StartBatchDownload(data.batchCountNeedDownload, data.batchSizeNeedDownload);
366     return E_OK;
367 }
368 
InitStartDownloadTaskStatus(const bool & isForeground)369 void CloudMediaAssetDownloadOperation::InitStartDownloadTaskStatus(const bool &isForeground)
370 {
371     isUnlimitedTrafficStatusOn_ = CloudSyncUtils::IsUnlimitedTrafficStatusOn();
372     MEDIA_INFO_LOG("isUnlimitedTrafficStatusOn_ is %{public}d", static_cast<int32_t>(isUnlimitedTrafficStatusOn_));
373     if (isForeground && !IsProperFgTemperature()) {
374         SetTaskStatus(Status::PAUSE_FOR_TEMPERATURE_LIMIT);
375         MEDIA_ERR_LOG("Temperature is not suitable for foreground downloads.");
376         return;
377     }
378     if (!CommonEventUtils::IsWifiConnected() && !isUnlimitedTrafficStatusOn_) {
379         Status status = MedialibrarySubscriber::IsCellularNetConnected() ?
380             Status::PAUSE_FOR_WIFI_UNAVAILABLE : Status::PAUSE_FOR_NETWORK_FLOW_LIMIT;
381         SetTaskStatus(status);
382         MEDIA_ERR_LOG("No wifi and no cellular data.");
383         return;
384     }
385 }
386 
SetDeathRecipient()387 int32_t CloudMediaAssetDownloadOperation::SetDeathRecipient()
388 {
389     auto saMgr = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
390     if (saMgr == nullptr) {
391         MEDIA_ERR_LOG("Failed to get SystemAbilityManagerClient");
392         return E_ERR;
393     }
394     cloudRemoteObject_ = saMgr->CheckSystemAbility(CLOUD_MANAGER_MANAGER_ID);
395     if (cloudRemoteObject_ == nullptr) {
396         MEDIA_ERR_LOG("Token is null.");
397         return E_ERR;
398     }
399     if (!cloudRemoteObject_->AddDeathRecipient(sptr(new CloudDeathRecipient(instance_)))) {
400         MEDIA_ERR_LOG("Failed to add death recipient.");
401         return E_ERR;
402     }
403     return E_OK;
404 }
405 
DoRelativedRegister()406 int32_t CloudMediaAssetDownloadOperation::DoRelativedRegister()
407 {
408     // register unlimit traffic status
409     auto saMgr = OHOS::SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
410     if (saMgr == nullptr) {
411         MEDIA_ERR_LOG("Failed to get SystemAbilityManagerClient");
412         return E_ERR;
413     }
414     OHOS::sptr<OHOS::IRemoteObject> remoteObject = saMgr->CheckSystemAbility(STORAGE_MANAGER_MANAGER_ID);
415     if (remoteObject == nullptr) {
416         MEDIA_ERR_LOG("Token is null.");
417         return E_ERR;
418     }
419     cloudHelper_ = DataShare::DataShareHelper::Creator(remoteObject, CLOUD_DATASHARE_URI);
420     cloudMediaAssetObserver_ = std::make_shared<CloudMediaAssetObserver>(instance_);
421     // observer more than 50, failed to register
422     cloudHelper_->RegisterObserverExt(Uri(CLOUD_URI), cloudMediaAssetObserver_, true);
423 
424     // observer download callback
425     downloadCallback_ = std::make_shared<MediaCloudDownloadCallback>(instance_);
426     int32_t ret = SetDeathRecipient();
427     if (ret != E_OK) {
428         MEDIA_ERR_LOG("failed to register death recipient, ret: %{public}d.", ret);
429         return ret;
430     }
431     MEDIA_INFO_LOG("success to register");
432     return ret;
433 }
434 
DoForceTaskExecute()435 int32_t CloudMediaAssetDownloadOperation::DoForceTaskExecute()
436 {
437     if (taskStatus_ == CloudMediaAssetTaskStatus::IDLE) {
438         MEDIA_ERR_LOG("DoForceTaskExecute permission denied");
439         return E_ERR;
440     }
441     if (taskStatus_ == CloudMediaAssetTaskStatus::PAUSED) {
442         MEDIA_INFO_LOG("pause cause is %{public}d", static_cast<int32_t>(pauseCause_));
443         readyForDownload_ = ReadyDataForBatchDownload();
444         if (IsDataEmpty(readyForDownload_)) {
445             CancelDownloadTask();
446         }
447         return E_OK;
448     }
449     CloudMediaAssetDownloadOperation::DownloadFileData data = ReadyDataForBatchDownload();
450     return SubmitBatchDownload(data, false);
451 }
452 
StartDownloadTask(int32_t cloudMediaDownloadType)453 int32_t CloudMediaAssetDownloadOperation::StartDownloadTask(int32_t cloudMediaDownloadType)
454 {
455     MediaLibraryTracer tracer;
456     tracer.Start("StartDownloadTask");
457     if (taskStatus_ != CloudMediaAssetTaskStatus::IDLE) {
458         MEDIA_ERR_LOG("permission denied");
459         return E_ERR;
460     }
461     MEDIA_INFO_LOG("enter, download type: %{public}d", cloudMediaDownloadType);
462     int32_t ret = DoRelativedRegister();
463     if (ret != E_OK) {
464         return ret;
465     }
466     if (cloudMediaDownloadType == static_cast<int32_t>(CloudMediaDownloadType::DOWNLOAD_FORCE)) {
467         SetTaskStatus(Status::FORCE_DOWNLOADING);
468         InitStartDownloadTaskStatus(true);
469         return DoForceTaskExecute();
470     }
471     SetTaskStatus(Status::PAUSE_FOR_BACKGROUND_TASK_UNAVAILABLE);
472     InitStartDownloadTaskStatus(false);
473     InitDownloadTaskInfo();
474     readyForDownload_ = ReadyDataForBatchDownload();
475     if (IsDataEmpty(readyForDownload_)) {
476         CancelDownloadTask();
477     }
478     return E_OK;
479 }
480 
DoRecoverExecute()481 int32_t CloudMediaAssetDownloadOperation::DoRecoverExecute()
482 {
483     if (!IsDataEmpty(dataForDownload_)) {
484         MEDIA_ERR_LOG("callback for cache is still alive.");
485         return E_ERR;
486     }
487     if (IsDataEmpty(cacheForDownload_)) {
488         return SubmitBatchDownload(readyForDownload_, false);
489     }
490     return SubmitBatchDownload(cacheForDownload_, true);
491 }
492 
ManualActiveRecoverTask(int32_t cloudMediaDownloadType)493 int32_t CloudMediaAssetDownloadOperation::ManualActiveRecoverTask(int32_t cloudMediaDownloadType)
494 {
495     MEDIA_INFO_LOG("enter ManualActiveRecoverTask.");
496     if (taskStatus_ != CloudMediaAssetTaskStatus::PAUSED) {
497         MEDIA_ERR_LOG("ManualActiveRecoverTask permission denied");
498         return E_ERR;
499     }
500 
501     if (cloudMediaDownloadType == static_cast<int32_t>(CloudMediaDownloadType::DOWNLOAD_FORCE)) {
502         SetTaskStatus(Status::RECOVER_FOR_MANAUL_ACTIVE);
503         InitStartDownloadTaskStatus(true);
504         return DoRecoverExecute();
505     }
506     SetTaskStatus(Status::PAUSE_FOR_BACKGROUND_TASK_UNAVAILABLE);
507     return E_OK;
508 }
509 
PassiveStatusRecover()510 int32_t CloudMediaAssetDownloadOperation::PassiveStatusRecover()
511 {
512     if (downloadType_ == CloudMediaDownloadType::DOWNLOAD_GENTLE && !isBgDownloadPermission_) {
513         SetTaskStatus(Status::PAUSE_FOR_BACKGROUND_TASK_UNAVAILABLE);
514         return E_OK;
515     }
516     SetTaskStatus(Status::RECOVER_FOR_PASSIVE_STATUS);
517     if (downloadType_ == CloudMediaDownloadType::DOWNLOAD_FORCE) {
518         InitStartDownloadTaskStatus(true);
519     } else {
520         InitStartDownloadTaskStatus(false);
521     }
522     return DoRecoverExecute();
523 }
524 
PassiveStatusRecoverTask(const CloudMediaTaskRecoverCause & recoverCause)525 int32_t CloudMediaAssetDownloadOperation::PassiveStatusRecoverTask(const CloudMediaTaskRecoverCause &recoverCause)
526 {
527     if (taskStatus_ != CloudMediaAssetTaskStatus::PAUSED || pauseCause_ == CloudMediaTaskPauseCause::USER_PAUSED) {
528         MEDIA_ERR_LOG("PassiveStatusRecoverTask permission denied, taskStatus: %{public}d, pauseCause: %{public}d,",
529             static_cast<int32_t>(taskStatus_), static_cast<int32_t>(pauseCause_));
530         return E_ERR;
531     }
532 
533     if (recoverCause == CloudMediaTaskRecoverCause::NETWORK_NORMAL &&
534         (pauseCause_ == CloudMediaTaskPauseCause::WIFI_UNAVAILABLE ||
535         pauseCause_ == CloudMediaTaskPauseCause::NETWORK_FLOW_LIMIT)) {
536         downloadId_ = DOWNLOAD_ID_DEFAULT; // wifi recovery, submit
537         return PassiveStatusRecover();
538     }
539 
540     if (RECOVER_RELATIONSHIP_MAP.find(recoverCause) == RECOVER_RELATIONSHIP_MAP.end() ||
541         pauseCause_ != RECOVER_RELATIONSHIP_MAP.at(recoverCause)) {
542         MEDIA_INFO_LOG("recoverCause is error, recoverCause: %{public}d", static_cast<int32_t>(recoverCause));
543         return E_ERR;
544     }
545     return PassiveStatusRecover();
546 }
547 
PauseDownloadTask(const CloudMediaTaskPauseCause & pauseCause)548 int32_t CloudMediaAssetDownloadOperation::PauseDownloadTask(const CloudMediaTaskPauseCause &pauseCause)
549 {
550     MediaLibraryTracer tracer;
551     tracer.Start("PauseDownloadTask");
552     if (taskStatus_ == CloudMediaAssetTaskStatus::IDLE || pauseCause_ == CloudMediaTaskPauseCause::USER_PAUSED) {
553         MEDIA_ERR_LOG("PauseDownloadTask permission denied");
554         return E_ERR;
555     }
556     MEDIA_INFO_LOG("enter PauseDownloadTask, taskStatus_: %{public}d, pauseCause_: %{public}d, pauseCause: %{public}d",
557         static_cast<int32_t>(taskStatus_), static_cast<int32_t>(pauseCause_), static_cast<int32_t>(pauseCause));
558 
559     pauseCause_ = pauseCause;
560     if (taskStatus_ == CloudMediaAssetTaskStatus::DOWNLOADING) {
561         taskStatus_ = CloudMediaAssetTaskStatus::PAUSED;
562         if (downloadId_ != DOWNLOAD_ID_DEFAULT) {
563             cloudSyncManager_.get().StopFileCache(downloadId_, !NEED_CLEAN);
564             MEDIA_INFO_LOG("success StopFileCache.");
565         }
566     }
567     return E_OK;
568 }
569 
ResetParameter()570 void CloudMediaAssetDownloadOperation::ResetParameter()
571 {
572     ClearData(readyForDownload_);
573     ClearData(notFoundForDownload_);
574     ClearData(cacheForDownload_);
575     downloadId_ = DOWNLOAD_ID_DEFAULT;
576     ClearData(dataForDownload_);
577 
578     isThumbnailUpdate_ = true;
579     isBgDownloadPermission_ = false;
580 
581     totalCount_ = 0;
582     totalSize_ = 0;
583     remainCount_ = 0;
584     remainSize_ = 0;
585 }
586 
CancelDownloadTask()587 int32_t CloudMediaAssetDownloadOperation::CancelDownloadTask()
588 {
589     if (taskStatus_ == CloudMediaAssetTaskStatus::IDLE) {
590         MEDIA_ERR_LOG("CancelDownloadTask permission denied");
591         return E_ERR;
592     }
593     MEDIA_INFO_LOG("the number of not found assets: %{public}d",
594         static_cast<int32_t>(notFoundForDownload_.fileDownloadMap.size()));
595     SetTaskStatus(Status::IDLE);
596     if (downloadId_ != DOWNLOAD_ID_DEFAULT) {
597         cloudSyncManager_.get().StopFileCache(downloadId_, NEED_CLEAN);
598     }
599     ResetParameter();
600     downloadCallback_ = nullptr;
601     cloudRemoteObject_ = nullptr;
602     if (cloudHelper_ == nullptr) {
603         return E_OK;
604     }
605     cloudHelper_->UnregisterObserverExt(Uri(CLOUD_URI), cloudMediaAssetObserver_);
606     cloudHelper_ = nullptr;
607     cloudMediaAssetObserver_ = nullptr;
608     return E_OK;
609 }
610 
SubmitBatchDownloadAgain()611 int32_t CloudMediaAssetDownloadOperation::SubmitBatchDownloadAgain()
612 {
613     if (!IsDataEmpty(dataForDownload_)) {
614         return E_ERR;
615     }
616     MEDIA_INFO_LOG("Submit batchDownload again.");
617     downloadId_ = DOWNLOAD_ID_DEFAULT;
618     if (IsDataEmpty(cacheForDownload_)) {
619         return SubmitBatchDownload(readyForDownload_, false);
620     }
621     return SubmitBatchDownload(cacheForDownload_, true);
622 }
623 
HandleSuccessCallback(const DownloadProgressObj & progress)624 void CloudMediaAssetDownloadOperation::HandleSuccessCallback(const DownloadProgressObj& progress)
625 {
626     std::lock_guard<std::mutex> lock(callbackMutex_);
627     MediaLibraryTracer tracer;
628     tracer.Start("HandleSuccessCallback");
629     if (progress.downloadId != downloadId_ ||
630         dataForDownload_.fileDownloadMap.find(progress.path) == dataForDownload_.fileDownloadMap.end()) {
631         MEDIA_WARN_LOG("this path is unknown, path: %{public}s, downloadId: %{public}s, downloadId_: %{public}s.",
632             MediaFileUtils::DesensitizePath(progress.path).c_str(), to_string(progress.downloadId).c_str(),
633             to_string(downloadId_).c_str());
634         return;
635     }
636 
637     int64_t size = dataForDownload_.fileDownloadMap[progress.path];
638     if (size != 0) {
639         remainCount_--;
640         remainSize_ -= size;
641     }
642     dataForDownload_.fileDownloadMap.erase(progress.path);
643 
644     MEDIA_INFO_LOG("success, path: %{public}s, size: %{public}s, batchSuccNum: %{public}s.",
645         MediaFileUtils::DesensitizePath(progress.path).c_str(), to_string(size).c_str(),
646         to_string(progress.batchSuccNum).c_str());
647 
648     SubmitBatchDownloadAgain();
649 }
650 
MoveDownloadFileToCache(const DownloadProgressObj & progress)651 void CloudMediaAssetDownloadOperation::MoveDownloadFileToCache(const DownloadProgressObj& progress)
652 {
653     std::lock_guard<std::mutex> lock(callbackMutex_);
654     if (progress.downloadId != downloadId_ ||
655         dataForDownload_.fileDownloadMap.find(progress.path) == dataForDownload_.fileDownloadMap.end()) {
656         MEDIA_WARN_LOG("This file is unknown, path: %{public}s, downloadId: %{public}s, downloadId_: %{public}s.",
657             MediaFileUtils::DesensitizePath(progress.path).c_str(), to_string(progress.downloadId).c_str(),
658             to_string(downloadId_).c_str());
659         return;
660     }
661     if (cacheForDownload_.fileDownloadMap.find(progress.path) != cacheForDownload_.fileDownloadMap.end()) {
662         MEDIA_INFO_LOG("file is in fileDownloadCacheMap_, path: %{public}s.",
663             MediaFileUtils::DesensitizePath(progress.path).c_str());
664         return;
665     }
666     cacheForDownload_.pathVec.push_back(progress.path);
667     cacheForDownload_.fileDownloadMap[progress.path] = dataForDownload_.fileDownloadMap.at(progress.path);
668     dataForDownload_.fileDownloadMap.erase(progress.path);
669     MEDIA_INFO_LOG("success, path: %{public}s.", MediaFileUtils::DesensitizePath(progress.path).c_str());
670     SubmitBatchDownloadAgain();
671 }
672 
MoveDownloadFileToNotFound(const DownloadProgressObj & progress)673 void CloudMediaAssetDownloadOperation::MoveDownloadFileToNotFound(const DownloadProgressObj& progress)
674 {
675     std::lock_guard<std::mutex> lock(callbackMutex_);
676     if (progress.downloadId != downloadId_ ||
677         dataForDownload_.fileDownloadMap.find(progress.path) == dataForDownload_.fileDownloadMap.end()) {
678         MEDIA_ERR_LOG("This file is unknown, path: %{public}s, downloadId: %{public}s, downloadId_: %{public}s.",
679             MediaFileUtils::DesensitizePath(progress.path).c_str(), to_string(progress.downloadId).c_str(),
680             to_string(downloadId_).c_str());
681         return;
682     }
683     if (notFoundForDownload_.fileDownloadMap.find(progress.path) != notFoundForDownload_.fileDownloadMap.end()) {
684         MEDIA_INFO_LOG("file is in notFoundForDownload_, path: %{public}s.",
685             MediaFileUtils::DesensitizePath(progress.path).c_str());
686         return;
687     }
688     notFoundForDownload_.fileDownloadMap[progress.path] = dataForDownload_.fileDownloadMap.at(progress.path);
689     dataForDownload_.fileDownloadMap.erase(progress.path);
690     MEDIA_INFO_LOG("success, path: %{public}s.", MediaFileUtils::DesensitizePath(progress.path).c_str());
691     SubmitBatchDownloadAgain();
692 }
693 
HandleFailedCallback(const DownloadProgressObj & progress)694 void CloudMediaAssetDownloadOperation::HandleFailedCallback(const DownloadProgressObj& progress)
695 {
696     MediaLibraryTracer tracer;
697     tracer.Start("HandleFailedCallback");
698     if (taskStatus_ == CloudMediaAssetTaskStatus::PAUSED && pauseCause_ == CloudMediaTaskPauseCause::USER_PAUSED) {
699         MEDIA_INFO_LOG("pauseCause_ is USER_PAUSED");
700         return;
701     }
702     MEDIA_INFO_LOG("Download error type: %{public}d, path: %{public}s.", progress.downloadErrorType,
703         MediaFileUtils::DesensitizePath(progress.path).c_str());
704     switch (progress.downloadErrorType) {
705         case static_cast<int32_t>(DownloadProgressObj::DownloadErrorType::UNKNOWN_ERROR): {
706             PauseDownloadTask(CloudMediaTaskPauseCause::CLOUD_ERROR);
707             MoveDownloadFileToCache(progress);
708             break;
709         }
710         case static_cast<int32_t>(DownloadProgressObj::DownloadErrorType::NETWORK_UNAVAILABLE): {
711             if (!IsNetworkUnavailable()) {
712                 PauseDownloadTask(CloudMediaTaskPauseCause::NETWORK_FLOW_LIMIT);
713             }
714             MoveDownloadFileToCache(progress);
715             break;
716         }
717         case static_cast<int32_t>(DownloadProgressObj::DownloadErrorType::LOCAL_STORAGE_FULL): {
718             PauseDownloadTask(CloudMediaTaskPauseCause::ROM_LIMIT);
719             MoveDownloadFileToCache(progress);
720             break;
721         }
722         case static_cast<int32_t>(DownloadProgressObj::DownloadErrorType::CONTENT_NOT_FOUND): {
723             MoveDownloadFileToNotFound(progress);
724             break;
725         }
726         case static_cast<int32_t>(DownloadProgressObj::DownloadErrorType::FREQUENT_USER_REQUESTS): {
727             PauseDownloadTask(CloudMediaTaskPauseCause::FREQUENT_USER_REQUESTS);
728             MoveDownloadFileToCache(progress);
729             break;
730         }
731         default: {
732             MEDIA_WARN_LOG("download error type not exit.");
733             break;
734         }
735     }
736 }
737 
HandleStoppedCallback(const DownloadProgressObj & progress)738 void CloudMediaAssetDownloadOperation::HandleStoppedCallback(const DownloadProgressObj& progress)
739 {
740     MediaLibraryTracer tracer;
741     tracer.Start("HandleStoppedCallback");
742     MEDIA_INFO_LOG("enter DownloadStopped, path: %{public}s.", MediaFileUtils::DesensitizePath(progress.path).c_str());
743     MoveDownloadFileToCache(progress);
744 }
745 
GetDownloadType()746 CloudMediaDownloadType CloudMediaAssetDownloadOperation::GetDownloadType()
747 {
748     return downloadType_;
749 }
750 
GetTaskStatus()751 CloudMediaAssetTaskStatus CloudMediaAssetDownloadOperation::GetTaskStatus()
752 {
753     return taskStatus_;
754 }
755 
GetTaskPauseCause()756 CloudMediaTaskPauseCause CloudMediaAssetDownloadOperation::GetTaskPauseCause()
757 {
758     return pauseCause_;
759 }
760 
GetTaskInfo()761 std::string CloudMediaAssetDownloadOperation::GetTaskInfo()
762 {
763     return to_string(totalCount_) + "," + to_string(totalSize_) + "," +
764         to_string(remainCount_) + "," + to_string(remainSize_);
765 }
766 } // namespace Media
767 } // namespace OHOS