1 /*
2 * Copyright (c) 2022 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 "download_service_manager.h"
17 #include <cstddef>
18 #include <algorithm>
19 #include <cstdint>
20 #include <functional>
21 #include <map>
22 #include <memory>
23 #include <new>
24 #include <queue>
25 #include <mutex>
26 #include <thread>
27 #include <utility>
28 #include "network_adapter.h"
29 #include "net_conn_constants.h"
30 #include "application_state_observer.h"
31 #include "net_all_capabilities.h"
32 #include "unistd.h"
33 #include "log.h"
34
35 static constexpr uint32_t THREAD_POOL_NUM = 4;
36 static constexpr uint32_t TASK_SLEEP_INTERVAL = 1;
37 static constexpr uint32_t MAX_RETRY_TIMES = 3;
38
39 using namespace OHOS::NetManagerStandard;
40 namespace OHOS::Request::Download {
41 std::mutex DownloadServiceManager::instanceLock_;
42 DownloadServiceManager *DownloadServiceManager::instance_ = nullptr;
43 namespace {
44 enum class ApplicationState {
45 APP_STATE_BEGIN = 0,
46 APP_STATE_CREATE = APP_STATE_BEGIN,
47 APP_STATE_READY,
48 APP_STATE_FOREGROUND,
49 APP_STATE_FOCUS,
50 APP_STATE_BACKGROUND,
51 APP_STATE_TERMINATED,
52 APP_STATE_END,
53 };
54 }
55
DownloadServiceManager()56 DownloadServiceManager::DownloadServiceManager()
57 : initialized_(false), interval_(TASK_SLEEP_INTERVAL), threadNum_(THREAD_POOL_NUM), timeoutRetry_(MAX_RETRY_TIMES),
58 taskId_(0)
59 {
60 }
61
~DownloadServiceManager()62 DownloadServiceManager::~DownloadServiceManager()
63 {
64 Destroy();
65 }
66
GetInstance()67 DownloadServiceManager *DownloadServiceManager::GetInstance()
68 {
69 if (instance_ == nullptr) {
70 std::lock_guard<std::mutex> lock(instanceLock_);
71 if (instance_ == nullptr) {
72 instance_ = new (std::nothrow) DownloadServiceManager;
73 }
74 }
75 return instance_;
76 }
77
Create(uint32_t threadNum)78 bool DownloadServiceManager::Create(uint32_t threadNum)
79 {
80 std::lock_guard<std::recursive_mutex> lock(mutex_);
81 if (initialized_) {
82 return true;
83 }
84
85 threadNum_ = threadNum;
86 for (uint32_t i = 0; i < threadNum; i++) {
87 threadList_.push_back(std::make_shared<DownloadThread>([this]() {
88 return ProcessTask();
89 }, interval_));
90 threadList_[i]->Start();
91 }
92
93 std::thread th = std::thread([this]() {
94 pthread_setname_np(pthread_self(), "download_network");
95 if (!MonitorNetwork()) {
96 DOWNLOAD_HILOGE("network management SA does not exist");
97 }
98 MonitorAppState();
99 });
100 th.detach();
101 initialized_ = true;
102 return initialized_;
103 }
104
Destroy()105 void DownloadServiceManager::Destroy()
106 {
107 std::for_each(threadList_.begin(), threadList_.end(), [](auto t) { t->Stop(); });
108 threadList_.clear();
109 initialized_ = false;
110 }
111
AddTask(const DownloadConfig & config)112 uint32_t DownloadServiceManager::AddTask(const DownloadConfig& config)
113 {
114 if (!initialized_) {
115 return -1;
116 }
117 uint32_t taskId = GetCurrentTaskId();
118 if (taskMap_.find(taskId) != taskMap_.end()) {
119 DOWNLOAD_HILOGD("Invalid case: duplicate taskId");
120 return -1;
121 }
122 auto task = std::make_shared<DownloadServiceTask>(taskId, config);
123 if (task == nullptr) {
124 DOWNLOAD_HILOGD("No mem to add task");
125 return -1;
126 }
127 // move new task into pending queue
128 task->SetRetryTime(timeoutRetry_);
129 taskMap_[taskId] = task;
130 MoveTaskToQueue(taskId, task);
131 return taskId;
132 }
133
InstallCallback(uint32_t taskId,DownloadTaskCallback eventCb)134 void DownloadServiceManager::InstallCallback(uint32_t taskId, DownloadTaskCallback eventCb)
135 {
136 if (!initialized_) {
137 return;
138 }
139 std::map<uint32_t, std::shared_ptr<DownloadServiceTask>>::iterator it = taskMap_.find(taskId);
140 if (it != taskMap_.end()) {
141 it->second->InstallCallback(eventCb);
142 }
143 }
144
ProcessTask()145 bool DownloadServiceManager::ProcessTask()
146 {
147 if (!initialized_) {
148 return false;
149 }
150 uint32_t taskId;
151 auto pickupTask = [this, &taskId]() -> std::shared_ptr<DownloadServiceTask> {
152 // pick up one task from pending queue
153 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
154 if (pendingQueue_.size() > 0) {
155 taskId = pendingQueue_.front();
156 pendingQueue_.pop();
157 if (taskMap_.find(taskId) != taskMap_.end()) {
158 return taskMap_[taskId];
159 }
160 }
161 return nullptr;
162 };
163
164 auto execTask = [this, &taskId](std::shared_ptr<DownloadServiceTask> task) -> bool {
165 if (task == nullptr) {
166 return false;
167 }
168 bool result = task->Run();
169 this->MoveTaskToQueue(taskId, task);
170 return result;
171 };
172 return execTask(pickupTask());
173 }
174
Pause(uint32_t taskId,uint32_t uid)175 bool DownloadServiceManager::Pause(uint32_t taskId, uint32_t uid)
176 {
177 if (!initialized_) {
178 return false;
179 }
180 DOWNLOAD_HILOGD("Pause Task[%{public}d]", taskId);
181 auto it = taskMap_.find(taskId);
182 if (it == taskMap_.end()) {
183 return false;
184 }
185 if (!IsSameUid(static_cast<int32_t>(uid), it->second->GetTaskApplicationInfoUid())) {
186 return false;
187 }
188 if (it->second->Pause()) {
189 MoveTaskToQueue(taskId, it->second);
190 return true;
191 }
192 return false;
193 }
194
Resume(uint32_t taskId,uint32_t uid)195 bool DownloadServiceManager::Resume(uint32_t taskId, uint32_t uid)
196 {
197 if (!initialized_) {
198 return false;
199 }
200 DOWNLOAD_HILOGD("Resume Task[%{public}d]", taskId);
201 auto it = taskMap_.find(taskId);
202 if (it == taskMap_.end()) {
203 return false;
204 }
205 if (!IsSameUid(static_cast<int32_t>(uid), it->second->GetTaskApplicationInfoUid())) {
206 return false;
207 }
208 if (it->second->Resume()) {
209 MoveTaskToQueue(taskId, it->second);
210 return true;
211 }
212 return false;
213 }
214
Remove(uint32_t taskId,uint32_t uid)215 bool DownloadServiceManager::Remove(uint32_t taskId, uint32_t uid)
216 {
217 if (!initialized_) {
218 return false;
219 }
220 DOWNLOAD_HILOGD("Remove Task[%{public}d]", taskId);
221 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
222 auto it = taskMap_.find(taskId);
223 if (it == taskMap_.end()) {
224 return false;
225 }
226 if (!IsSameUid(static_cast<int32_t>(uid), it->second->GetTaskApplicationInfoUid())) {
227 return false;
228 }
229 bool result = it->second->Remove();
230 if (result) {
231 taskMap_.erase(it);
232 RemoveFromQueue(pendingQueue_, taskId);
233 RemoveFromQueue(pausedQueue_, taskId);
234 }
235 return result;
236 }
237
Query(uint32_t taskId,DownloadInfo & info)238 bool DownloadServiceManager::Query(uint32_t taskId, DownloadInfo &info)
239 {
240 if (!initialized_) {
241 return false;
242 }
243 auto it = taskMap_.find(taskId);
244 if (it == taskMap_.end()) {
245 return false;
246 }
247 return it->second->Query(info);
248 }
249
Query(uint32_t taskId,uint32_t uid,DownloadInfo & info)250 bool DownloadServiceManager::Query(uint32_t taskId, uint32_t uid, DownloadInfo &info)
251 {
252 if (!initialized_) {
253 return false;
254 }
255 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
256 auto it = taskMap_.find(taskId);
257 if (it == taskMap_.end()) {
258 return false;
259 }
260 if (!IsSameUid(static_cast<int32_t>(uid), it->second->GetTaskApplicationInfoUid())) {
261 return false;
262 }
263 return it->second->Query(info);
264 }
265
QueryMimeType(uint32_t taskId,uint32_t uid,std::string & mimeType)266 bool DownloadServiceManager::QueryMimeType(uint32_t taskId, uint32_t uid, std::string &mimeType)
267 {
268 if (!initialized_) {
269 return false;
270 }
271 auto it = taskMap_.find(taskId);
272 if (it == taskMap_.end()) {
273 return false;
274 }
275 if (!IsSameUid(static_cast<int32_t>(uid), it->second->GetTaskApplicationInfoUid())) {
276 return false;
277 }
278 return it->second->QueryMimeType(mimeType);
279 }
280
GetStartId() const281 uint32_t DownloadServiceManager::GetStartId() const
282 {
283 return taskId_;
284 }
285
GetCurrentTaskId()286 uint32_t DownloadServiceManager::GetCurrentTaskId()
287 {
288 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
289 return taskId_++;
290 }
291
DecideQueueType(DownloadStatus status)292 DownloadServiceManager::QueueType DownloadServiceManager::DecideQueueType(DownloadStatus status)
293 {
294 switch (status) {
295 case SESSION_PAUSED:
296 return QueueType::PAUSED_QUEUE;
297
298 case SESSION_UNKNOWN:
299 return QueueType::PENDING_QUEUE;
300
301 case SESSION_PENDING:
302 case SESSION_RUNNING:
303 case SESSION_SUCCESS:
304 case SESSION_FAILED:
305 default:
306 return QueueType::NONE_QUEUE;
307 }
308 return QueueType::NONE_QUEUE;
309 }
310
MoveTaskToQueue(uint32_t taskId,std::shared_ptr<DownloadServiceTask> task)311 void DownloadServiceManager::MoveTaskToQueue(uint32_t taskId, std::shared_ptr<DownloadServiceTask> task)
312 {
313 DownloadStatus status;
314 ErrorCode code;
315 PausedReason reason;
316 task->GetRunResult(status, code, reason);
317 DOWNLOAD_HILOGD("Status [%{public}d], Code [%{public}d], Reason [%{public}d]", status, code, reason);
318 switch (DecideQueueType(status)) {
319 case QueueType::PENDING_QUEUE: {
320 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
321 RemoveFromQueue(pausedQueue_, taskId);
322 PushQueue(pendingQueue_, taskId);
323 break;
324 }
325 case QueueType::PAUSED_QUEUE: {
326 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
327 RemoveFromQueue(pendingQueue_, taskId);
328 PushQueue(pausedQueue_, taskId);
329 break;
330 }
331 case QueueType::NONE_QUEUE:
332 default:
333 break;
334 }
335 }
336
PushQueue(std::queue<uint32_t> & queue,uint32_t taskId)337 void DownloadServiceManager::PushQueue(std::queue<uint32_t> &queue, uint32_t taskId)
338 {
339 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
340 if (taskMap_.find(taskId) == taskMap_.end()) {
341 DOWNLOAD_HILOGD("invalid task id [%{public}d]", taskId);
342 return;
343 }
344
345 if (queue.empty()) {
346 queue.push(taskId);
347 return;
348 }
349
350 auto headElement = queue.front();
351 if (headElement == taskId) {
352 return;
353 }
354
355 bool foundIt = false;
356 uint32_t indicatorId = headElement;
357 do {
358 if (queue.front() == taskId) {
359 foundIt = true;
360 }
361 queue.push(headElement);
362 queue.pop();
363 headElement = queue.front();
364 } while (headElement != indicatorId);
365
366 if (!foundIt) {
367 queue.push(taskId);
368 }
369 }
370
RemoveFromQueue(std::queue<uint32_t> & queue,uint32_t taskId)371 void DownloadServiceManager::RemoveFromQueue(std::queue<uint32_t> &queue, uint32_t taskId)
372 {
373 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
374 if (queue.empty()) {
375 return;
376 }
377
378 auto headElement = queue.front();
379 if (headElement == taskId) {
380 queue.pop();
381 return;
382 }
383
384 auto indicatorId = headElement;
385 do {
386 if (headElement != taskId) {
387 queue.push(queue.front());
388 }
389 queue.pop();
390 headElement = queue.front();
391 } while (headElement != indicatorId);
392 }
393
SetInterval(uint32_t interval)394 void DownloadServiceManager::SetInterval(uint32_t interval)
395 {
396 interval_ = interval;
397 }
GetInterval() const398 uint32_t DownloadServiceManager::GetInterval() const
399 {
400 return interval_;
401 }
402
ResumeTaskByNetwork()403 void DownloadServiceManager::ResumeTaskByNetwork()
404 {
405 int taskCount = 0;
406 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
407 size_t size = pausedQueue_.size();
408 while (size-- > 0) {
409 uint32_t taskId = pausedQueue_.front();
410 if (taskMap_.find(taskId) != taskMap_.end()) {
411 pausedQueue_.pop();
412 auto task = taskMap_[taskId];
413 DownloadStatus status;
414 ErrorCode code;
415 PausedReason reason;
416 task->GetRunResult(status, code, reason);
417 if (reason != PAUSED_BY_USER) {
418 task->Resume();
419 PushQueue(pendingQueue_, taskId);
420 taskCount++;
421 } else {
422 pausedQueue_.push(taskId);
423 }
424 }
425 }
426 DOWNLOAD_HILOGD("[%{public}d] task has been resumed by network status changed", taskCount);
427 }
428
MonitorNetwork()429 bool DownloadServiceManager::MonitorNetwork()
430 {
431 return NetworkAdapter::GetInstance().RegOnNetworkChange([this]() {
432 this->ResumeTaskByNetwork();
433 this->UpdateNetworkType();
434 });
435 }
436
UpdateNetworkType()437 void DownloadServiceManager::UpdateNetworkType()
438 {
439 DOWNLOAD_HILOGD("UpdateNetworkType start\n");
440 std::lock_guard<std::recursive_mutex> autoLock(mutex_);
441 DownloadStatus status;
442 ErrorCode code;
443 PausedReason reason;
444 for (const auto &it : taskMap_) {
445 it.second->GetRunResult(status, code, reason);
446 bool bRet = status == SESSION_RUNNING || status == SESSION_PENDING
447 || status == SESSION_PAUSED;
448 if (bRet) {
449 if (!it.second->IsSatisfiedConfiguration()) {
450 RemoveFromQueue(pendingQueue_, it.first);
451 PushQueue(pausedQueue_, it.first);
452 }
453 }
454 }
455 }
MonitorAppState()456 void DownloadServiceManager::MonitorAppState()
457 {
458 bool ret = ApplicationStateObserver::GetInstance().RegisterAppStateChanged(
459 [this](const std::string bundleName, int32_t uid, int32_t state) {
460 this->UpdateAppState(bundleName, uid, state);
461 });
462 DOWNLOAD_HILOGD("RegisterAppStateChanged retcode= %{public}d", ret);
463 }
464
UpdateAppState(const std::string bundleName,int32_t uid,int32_t state)465 void DownloadServiceManager::UpdateAppState(const std::string bundleName, int32_t uid, int32_t state)
466 {
467 DOWNLOAD_HILOGI("UpdateAppState uid=%{public}d, bundleName=%{public}s, state=%{public}d",
468 uid, bundleName.c_str(), state);
469 std::lock_guard<std::mutex> lck(appStateMutex_);
470 for (const auto &iter : taskMap_) {
471 if (IsSameApplication(bundleName, uid,
472 iter.second->GetTaskBundleName(), iter.second->GetTaskApplicationInfoUid())) {
473 if (IsBackgroundOrTerminated(state)) {
474 iter.second->SetNotifyApp(false);
475 } else if (IsForeground(state)) {
476 iter.second->SetNotifyApp(true);
477 }
478 }
479 }
480 }
481
IsSameApplication(const std::string sName,int32_t sUid,const std::string dName,int32_t dUid)482 bool DownloadServiceManager::IsSameApplication(const std::string sName, int32_t sUid,
483 const std::string dName, int32_t dUid)
484 {
485 return (IsSameBundleName(sName, dName)) && (IsSameUid(sUid, dUid));
486 }
487
IsBackgroundOrTerminated(int32_t state)488 bool DownloadServiceManager::IsBackgroundOrTerminated(int32_t state)
489 {
490 return state == static_cast<int32_t>(ApplicationState::APP_STATE_BACKGROUND) ||
491 state == static_cast<int32_t>(ApplicationState::APP_STATE_TERMINATED);
492 }
493
IsForeground(int32_t state)494 bool DownloadServiceManager::IsForeground(int32_t state)
495 {
496 return state == static_cast<int32_t>(ApplicationState::APP_STATE_FOREGROUND);
497 }
498
QueryAllTask(std::vector<DownloadInfo> & taskVector) const499 bool DownloadServiceManager::QueryAllTask(std::vector<DownloadInfo> &taskVector) const
500 {
501 for (const auto &it : taskMap_) {
502 DownloadInfo downloadInfo;
503 it.second->Query(downloadInfo);
504 taskVector.push_back(downloadInfo);
505 }
506 return true;
507 }
508
IsSameBundleName(const std::string & sName,const std::string & dName)509 bool DownloadServiceManager::IsSameBundleName(const std::string &sName, const std::string &dName)
510 {
511 return sName == dName;
512 }
513
IsSameUid(int32_t sUid,int32_t dUid)514 bool DownloadServiceManager::IsSameUid(int32_t sUid, int32_t dUid)
515 {
516 return sUid = dUid;
517 }
518 } // namespace OHOS::Request::Download