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