• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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