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