1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <thread>
17
18 #include "utils_log.h"
19 #include "ipc/cloud_download_callback_manager.h"
20 #include "data_sync/task_state_manager.h"
21
22 namespace OHOS::FileManagement::CloudSync {
23 using namespace std;
24 using namespace DriveKit;
25
CloudDownloadCallbackManager()26 CloudDownloadCallbackManager::CloudDownloadCallbackManager()
27 {
28 callback_ = nullptr;
29 }
30
FindDownload(const std::string path)31 bool CloudDownloadCallbackManager::FindDownload(const std::string path)
32 {
33 bool ret = false;
34 lock_guard<mutex> lock(downloadsMtx_);
35 if (downloads_.find(path) != downloads_.end() &&
36 downloads_[path].state == DownloadProgressObj::Status::RUNNING) {
37 ret = true;
38 }
39 return ret;
40 }
41
StartDonwload(const std::string path,const int32_t userId,const int64_t downloadId)42 void CloudDownloadCallbackManager::StartDonwload(const std::string path,
43 const int32_t userId,
44 const int64_t downloadId)
45 {
46 lock_guard<mutex> lock(downloadsMtx_);
47 TaskStateManager::GetInstance().StartTask(bundleName_, TaskType::DOWNLOAD_TASK);
48 if (downloads_.find(path) == downloads_.end()) {
49 downloads_[path].refCount = 1;
50 } else {
51 downloads_[path].refCount++;
52 }
53 downloads_[path].state = DownloadProgressObj::Status::RUNNING;
54 downloads_[path].path = path;
55 downloads_[path].downloadId = downloadId;
56 LOGI("download_file : %{public}d start download %{public}s callback success.", userId, path.c_str());
57 }
58
StopDonwload(const std::string path,const int32_t userId,DownloadProgressObj & download)59 bool CloudDownloadCallbackManager::StopDonwload(const std::string path, const int32_t userId,
60 DownloadProgressObj &download)
61 {
62 bool ret = false;
63 lock_guard<mutex> lock(downloadsMtx_);
64
65 auto res = downloads_.find(path);
66 bool isDownloading = (res != downloads_.end());
67 if (isDownloading) {
68 download = res->second;
69 LOGI("download_file : %{public}d stop download %{public}s callback success.", userId, path.c_str());
70 downloads_.erase(res);
71 ret = true;
72 } else {
73 LOGI("download_file : %{public}d stop download %{public}s callback fail, task not exist.",
74 userId, path.c_str());
75 ret = false;
76 }
77 CheckTaskState();
78 return ret;
79 }
80
StopAllDownloads(const int32_t userId)81 std::vector<int64_t> CloudDownloadCallbackManager::StopAllDownloads(const int32_t userId)
82 {
83 std::vector<int64_t> ret;
84 lock_guard<mutex> lock(downloadsMtx_);
85 for (auto &pair : downloads_) {
86 pair.second.state = DownloadProgressObj::Status::FAILED;
87 ret.push_back(pair.second.downloadId);
88 if (callback_ != nullptr) {
89 callback_->OnDownloadProcess(pair.second);
90 LOGI("download_file : %{public}d stop download %{public}s callback success.", userId, pair.first.c_str());
91 }
92 }
93 downloads_.clear();
94 CheckTaskState();
95 return ret;
96 }
97
RegisterCallback(const int32_t userId,const sptr<ICloudDownloadCallback> downloadCallback)98 void CloudDownloadCallbackManager::RegisterCallback(const int32_t userId,
99 const sptr<ICloudDownloadCallback> downloadCallback)
100 {
101 LOGI("download_file : %{public}d register download callback : %{public}d", userId,
102 downloadCallback != nullptr);
103 unique_lock<mutex> lock(callbackMutex_);
104 callback_ = downloadCallback;
105 }
106
UnregisterCallback(const int32_t userId)107 void CloudDownloadCallbackManager::UnregisterCallback(const int32_t userId)
108 {
109 LOGI("download_file : %{public}d unregister download callback", userId);
110 unique_lock<mutex> lock(callbackMutex_);
111 callback_ = nullptr;
112 }
113
OnDownloadFailed(int32_t & downloadErrorType,const DKError & dkError)114 static void OnDownloadFailed(int32_t &downloadErrorType, const DKError &dkError)
115 {
116 downloadErrorType = DownloadProgressObj::UNKNOWN_ERROR;
117 if (static_cast<DKServerErrorCode>(dkError.serverErrorCode) == DKServerErrorCode::NETWORK_ERROR) {
118 downloadErrorType = DownloadProgressObj::NETWORK_UNAVAILABLE;
119 }
120 if (dkError.errorDetails.size() != 0) {
121 auto errorDetailCode = static_cast<DKDetailErrorCode>(dkError.errorDetails[0].detailCode);
122 if (errorDetailCode == DKDetailErrorCode::SPACE_FULL) {
123 downloadErrorType = DownloadProgressObj::LOCAL_STORAGE_FULL;
124 } else if (errorDetailCode == DKDetailErrorCode::THUMBNAIL_NOT_FOUND ||
125 errorDetailCode == DKDetailErrorCode::ORIGINAL_NOT_EXSIT) {
126 downloadErrorType = DownloadProgressObj::CONTENT_NOT_FOUND;
127 } else if (errorDetailCode == DKDetailErrorCode::USER_REQUEST_TOO_MANY ||
128 errorDetailCode == DKDetailErrorCode::APP_REQUEST_TOO_MANY ||
129 errorDetailCode == DKDetailErrorCode::FLOW_CONTROL) {
130 downloadErrorType = DownloadProgressObj::FREQUENT_USER_REQUESTS;
131 }
132 }
133 LOGE("download fail, downloadErrorType %{public}d", downloadErrorType);
134 }
135
OnDownloadedResult(const std::string path,std::vector<DriveKit::DKDownloadAsset> assetsToDownload,std::shared_ptr<DataHandler> handler,std::shared_ptr<DriveKit::DKContext> context,std::shared_ptr<const DriveKit::DKDatabase> database,const std::map<DriveKit::DKDownloadAsset,DriveKit::DKDownloadResult> & results,const DriveKit::DKError & err)136 void CloudDownloadCallbackManager::OnDownloadedResult(
137 const std::string path,
138 std::vector<DriveKit::DKDownloadAsset> assetsToDownload,
139 std::shared_ptr<DataHandler> handler,
140 std::shared_ptr<DriveKit::DKContext> context,
141 std::shared_ptr<const DriveKit::DKDatabase> database,
142 const std::map<DriveKit::DKDownloadAsset, DriveKit::DKDownloadResult> &results,
143 const DriveKit::DKError &err)
144 {
145 unique_lock<mutex> lock(downloadsMtx_);
146 auto res = downloads_.find(path);
147 bool isDownloading = (res != downloads_.end());
148
149 LOGI("download_file : [callback downloaded] %{public}s is downloading : %{public}d .",
150 path.c_str(), isDownloading);
151 if (!isDownloading) {
152 lock.unlock();
153 return;
154 }
155
156 auto download = res->second;
157 download.refCount--;
158 if (download.refCount == 0) {
159 downloads_.erase(res);
160 CheckTaskState();
161 } else {
162 lock.unlock();
163 return;
164 }
165 lock.unlock();
166
167 LOGI("download_file : [callback downloaded] %{public}s state is %{public}s, localErr is %{public}d.",
168 path.c_str(), download.to_string().c_str(), static_cast<int>(err.dkErrorCode));
169
170 if (callback_ != nullptr && download.state == DownloadProgressObj::STOPPED) {
171 LOGI("stop state");
172 callback_->OnDownloadProcess(download);
173 return;
174 }
175
176 auto downloadedState = err.HasError() ? DownloadProgressObj::FAILED : DownloadProgressObj::COMPLETED;
177 /**
178 * Avoiding the issue of cloud service not returning a total error code.
179 * Currently, only single asset download is supported.
180 */
181 for (const auto &it : results) {
182 if (!it.second.IsSuccess()) {
183 LOGE("download file failed, localErr: %{public}d", it.second.GetDKError().dkErrorCode);
184 downloadedState = DownloadProgressObj::FAILED;
185 OnDownloadFailed(download.downloadErrorType, it.second.GetDKError());
186 break;
187 }
188 }
189
190 if (download.state == DownloadProgressObj::RUNNING) {
191 download.state = downloadedState;
192 if ((assetsToDownload.size() == 1) && (download.state == DownloadProgressObj::COMPLETED)) {
193 (void)handler->OnDownloadSuccess(assetsToDownload[0]);
194 }
195 std::thread([=]() {
196 this_thread::sleep_for(chrono::seconds(1));
197 if (callback_ != nullptr) {
198 callback_->OnDownloadProcess(download);
199 } else { LOGE("async download callback is nullptr"); }
200 }).detach();
201 }
202 }
203
OnDownloadProcess(const std::string path,std::shared_ptr<DriveKit::DKContext> context,DriveKit::DKDownloadAsset asset,DriveKit::TotalSize totalSize,DriveKit::DownloadSize downloadSize)204 void CloudDownloadCallbackManager::OnDownloadProcess(const std::string path,
205 std::shared_ptr<DriveKit::DKContext> context,
206 DriveKit::DKDownloadAsset asset,
207 DriveKit::TotalSize totalSize,
208 DriveKit::DownloadSize downloadSize)
209 {
210 unique_lock<mutex> lock(downloadsMtx_);
211 auto res = downloads_.find(path);
212 bool isDownloading = (res != downloads_.end());
213
214 LOGI("download_file : [callback downloading] %{public}s is downloading : %{public}d .",
215 path.c_str(), isDownloading);
216 if (!isDownloading) {
217 lock.unlock();
218 return;
219 }
220
221 auto download = res->second;
222 lock.unlock();
223
224 download.downloadedSize = downloadSize;
225 download.totalSize = totalSize;
226 LOGI("download_file : [callback downloading] %{public}s state is %{public}s.", path.c_str(),
227 download.to_string().c_str());
228 if (callback_ != nullptr && download.state == DownloadProgressObj::RUNNING) {
229 callback_->OnDownloadProcess(download);
230 }
231 }
232
SetBundleName(const std::string & bundleName)233 void CloudDownloadCallbackManager::SetBundleName(const std::string &bundleName)
234 {
235 bundleName_ = bundleName;
236 }
237
CheckTaskState()238 void CloudDownloadCallbackManager::CheckTaskState()
239 {
240 if (downloads_.empty()) {
241 TaskStateManager::GetInstance().CompleteTask(bundleName_, TaskType::DOWNLOAD_TASK);
242 }
243 }
244
NotifyProcessStop(DownloadProgressObj & download)245 void CloudDownloadCallbackManager::NotifyProcessStop(DownloadProgressObj &download)
246 {
247 download.state = DownloadProgressObj::Status::STOPPED;
248 if (callback_ != nullptr) {
249 callback_->OnDownloadProcess(download);
250 }
251 }
252 } // namespace OHOS::FileManagement::CloudSync
253