1. fix file access permission, 2. add network monitor

Signed-off-by: liulinna <liulinna4@huawei.com>
This commit is contained in:
liulinna
2022-03-27 05:30:14 +08:00
parent 77b17942b9
commit bcf3050390
11 changed files with 408 additions and 106 deletions
@@ -40,6 +40,10 @@ public:
void SetTitle(const std::string &title);
void SetFD(int32_t fd);
void SetFDError(int32_t fdError);
[[nodiscard]] const std::string &GetUrl() const;
[[nodiscard]] const std::map<std::string, std::string> &GetHeader() const;
@@ -56,6 +60,10 @@ public:
[[nodiscard]] const std::string &GetTitle() const;
int32_t GetFD() const;
int32_t GetFDError() const;
void Dump(bool isFull = true) const;
private:
@@ -74,6 +82,10 @@ private:
std::string filePath_;
std::string title_;
int32_t fd_;
int32_t fdError_;
};
} // namespace OHOS::Request::Download
@@ -20,7 +20,7 @@
namespace OHOS::Request::Download {
DownloadConfig::DownloadConfig()
: url_(""), enableMetered_(false), enableRoaming_(false), description_(""), networkType_(0),
filePath_(""), title_("") {
filePath_(""), title_(""), fd_(-1), fdError_(0) {
}
void DownloadConfig::SetUrl(const std::string &url)
@@ -63,6 +63,16 @@ void DownloadConfig::SetTitle(const std::string &title)
title_ = title;
}
void DownloadConfig::SetFD(int32_t fd)
{
fd_ = fd;
}
void DownloadConfig::SetFDError(int32_t fdError)
{
fdError_ = fdError;
}
const std::string &DownloadConfig::GetUrl() const
{
return url_;
@@ -103,8 +113,20 @@ const std::string &DownloadConfig::GetTitle() const
return title_;
}
int32_t DownloadConfig::GetFD() const
{
return fd_;
}
int32_t DownloadConfig::GetFDError() const
{
return fdError_;
}
void DownloadConfig::Dump(bool isFull) const
{
DOWNLOAD_HILOGD("fd: %{public}d", fd_);
DOWNLOAD_HILOGD("fd errno: %{public}s", strerror(fdError_));
DOWNLOAD_HILOGD("URL: %{public}s", url_.c_str());
DOWNLOAD_HILOGD("enableMetered: %{public}s", enableMetered_ ? "true" : "false");
DOWNLOAD_HILOGD("enableRoaming: %{public}s", enableRoaming_ ? "true" : "false");
@@ -13,9 +13,12 @@
* limitations under the License.
*/
#include "download_service_proxy.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "iremote_broker.h"
#include "log.h"
#include "download_common.h"
@@ -32,6 +35,26 @@ uint32_t DownloadServiceProxy::Request(const DownloadConfig &config)
MessageParcel data, reply;
MessageOption option;
data.WriteInterfaceToken(GetDescriptor());
int32_t fd = -1;
int32_t err = 0;
fd = open(config.GetFilePath().c_str(), O_RDWR);
if (fd > 0) {
DOWNLOAD_HILOGD("File [%{public}s] already exists", config.GetFilePath().c_str());
fd = -1;
} else {
fd = open(config.GetFilePath().c_str(), O_CREAT | O_RDWR, 0644);
if (fd < 0) {
DOWNLOAD_HILOGD("Failed to open file [%{public}s], errno [%{public}s]",
config.GetFilePath().c_str(), strerror(errno));
err = errno;
}
}
DOWNLOAD_HILOGI("Succeed to open file [%{public}s, fd [%{public}d]]", config.GetFilePath().c_str(), fd);
data.WriteFileDescriptor(fd);
data.WriteInt32(err);
close(fd);
data.WriteString(config.GetUrl());
data.WriteBool(config.GetMetered());
data.WriteBool(config.GetRoaming());
@@ -156,7 +156,8 @@ bool DownloadTaskNapi::ParseConfig(napi_env env, napi_value configValue, Downloa
bool DownloadTaskNapi::ParseHeader(napi_env env, napi_value configValue, DownloadConfig &config)
{
if (!NapiUtils::HasNamedProperty(env, configValue, PARAM_KEY_HEADER)) {
return false;
DOWNLOAD_HILOGD("No header present, ignore it");
return true;
}
napi_value header = NapiUtils::GetNamedProperty(env, configValue, PARAM_KEY_HEADER);
if (NapiUtils::GetValueType(env, header) != napi_object) {
@@ -164,6 +165,7 @@ bool DownloadTaskNapi::ParseHeader(napi_env env, napi_value configValue, Downloa
}
auto names = NapiUtils::GetPropertyNames(env, header);
std::vector<std::string>::iterator iter;
DOWNLOAD_HILOGD("current name list size = %{public}d", names.size());
for (iter = names.begin(); iter != names.end(); ++iter)
{
auto value = NapiUtils::GetStringPropertyUtf8(env, header, *iter);
@@ -56,7 +56,6 @@ private:
NONE_QUEUE,
PENDING_QUEUE,
PAUSED_QUEUE,
COMPLETED_QUEUE,
};
uint32_t GetCurrentTaskId();
@@ -65,12 +64,15 @@ private:
void PushQueue(std::queue<uint32_t> &queue, uint32_t taskId);
void RemoveFromQueue(std::queue<uint32_t> &queue, uint32_t taskId);
bool GetNetworkStatus();
void ResumeTaskByNetwork();
static void MonitorNetwork(DownloadServiceManager *thisVal);
private:
bool initialized_;
std::recursive_mutex mutex_;
std::map<uint32_t, std::shared_ptr<DownloadServiceTask>> taskMap_;
std::queue<uint32_t> pendingQueue_;
std::queue<uint32_t> completedQueue_;
std::queue<uint32_t> pausedQueue_;
std::vector<std::shared_ptr<DownloadThread>> threadList_;
@@ -79,6 +81,8 @@ private:
uint32_t threadNum_;
uint32_t timeoutRetry_;
std::shared_ptr<std::thread> networkThread_;
static uint32_t taskId;
static std::recursive_mutex instanceLock_;
static std::shared_ptr<DownloadServiceManager> instance_;
@@ -26,9 +26,9 @@ public:
int32_t OnRemoteRequest(uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option) override;
private:
bool OnRequest(Parcel &data, Parcel &reply);
bool OnPause(Parcel &data, Parcel &reply);
bool OnQuery(Parcel &data, Parcel &reply);
bool OnRequest(MessageParcel &data, MessageParcel &reply);
bool OnPause(MessageParcel &data, MessageParcel &reply);
bool OnQuery(MessageParcel &data, MessageParcel &reply);
bool OnQueryMimeType(MessageParcel &data, MessageParcel &reply);
bool OnRemove(MessageParcel &data, MessageParcel &reply);
bool OnResume(MessageParcel &data, MessageParcel &reply);
@@ -45,6 +45,7 @@ public:
void GetRunResult(DownloadStatus &status, ErrorCode &code, PausedReason &reason);
void SetRetryTime(uint32_t retryTime);
void SetNetworkStatus(bool isOnline);
private:
void SetStatus(DownloadStatus status, ErrorCode code, PausedReason reason);
@@ -57,6 +58,7 @@ private:
void DumpPausedReason();
bool ExecHttp();
bool SetFileSizeOption(CURL *curl, struct curl_slist *requestHeader);
bool SetOption(CURL *curl, struct curl_slist *requestHeader);
struct curl_slist *MakeHeaders(const std::vector<std::string> &vec);
@@ -73,6 +75,7 @@ private:
bool CheckResumeCondition();
void ForceStopRunning();
bool HandleFileError();
private:
uint32_t taskId_;
@@ -93,6 +96,9 @@ private:
DownloadTaskCallback eventCb_;
std::recursive_mutex mutex_;
bool hasFileSize_;
bool isOnline_;
uint32_t prevSize_;
};
} // namespace OHOS::Request::Download
#endif // DOWNLOAD_TASK_H
@@ -20,7 +20,7 @@
static constexpr uint32_t THREAD_POOL_NUM = 4;
static constexpr uint32_t TASK_SLEEP_INTERVAL = 1;
static constexpr uint32_t MAX_RETRY_TIMES = 10;
static constexpr uint32_t MAX_RETRY_TIMES = 3;
namespace OHOS::Request::Download {
uint32_t DownloadServiceManager::taskId = 1000;
@@ -28,7 +28,8 @@ std::recursive_mutex DownloadServiceManager::instanceLock_;
std::shared_ptr<DownloadServiceManager> DownloadServiceManager::instance_ = nullptr;
DownloadServiceManager::DownloadServiceManager()
: initialized_(false), interval_(TASK_SLEEP_INTERVAL), threadNum_(THREAD_POOL_NUM), timeoutRetry_(MAX_RETRY_TIMES)
: initialized_(false), interval_(TASK_SLEEP_INTERVAL), threadNum_(THREAD_POOL_NUM), timeoutRetry_(MAX_RETRY_TIMES),
networkThread_(nullptr)
{
}
@@ -66,14 +67,18 @@ bool DownloadServiceManager::Create(uint32_t threadNum)
DOWNLOAD_HILOGD("Failed to initialize 'curl'");
return false;
}
networkThread_ = std::make_shared<std::thread>(MonitorNetwork, this);
initialized_ = true;
return initialized_;
return initialized_;
}
void DownloadServiceManager::Destroy()
{
std::for_each(threadList_.begin(), threadList_.end(), [](std::shared_ptr<DownloadThread> t) { t->Stop(); });
std::for_each(threadList_.begin(), threadList_.end(), [](auto t) { t->Stop(); });
threadList_.clear();
initialized_ = false;
networkThread_->join();
}
uint32_t DownloadServiceManager::AddTask(const DownloadConfig& config)
@@ -121,7 +126,9 @@ bool DownloadServiceManager::ProcessTask()
if (pendingQueue_.size() > 0) {
taskId = pendingQueue_.front();
pendingQueue_.pop();
return taskMap_[taskId];
if (taskMap_.find(taskId) != taskMap_.end()) {
return taskMap_[taskId];
}
}
return nullptr;
};
@@ -142,10 +149,12 @@ bool DownloadServiceManager::Pause(uint32_t taskId)
if (!initialized_) {
return false;
}
DOWNLOAD_HILOGD("Pause Task[%{public}d]", taskId);
auto it = taskMap_.find(taskId);
if (it == taskMap_.end()) {
return false;
}
if (it->second->Pause()) {
MoveTaskToQueue(taskId, it->second);
return true;
@@ -158,10 +167,12 @@ bool DownloadServiceManager::Resume(uint32_t taskId)
if (!initialized_) {
return false;
}
DOWNLOAD_HILOGD("Resume Task[%{public}d]", taskId);
auto it = taskMap_.find(taskId);
if (it == taskMap_.end()) {
return false;
}
if (it->second->Resume()) {
MoveTaskToQueue(taskId, it->second);
return true;
@@ -174,17 +185,18 @@ bool DownloadServiceManager::Remove(uint32_t taskId)
if (!initialized_) {
return false;
}
DOWNLOAD_HILOGD("Remove Task[%{public}d]", taskId);
auto it = taskMap_.find(taskId);
if (it == taskMap_.end()) {
return false;
}
bool result = it->second->Remove();
if (result) {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
RemoveFromQueue(pendingQueue_, taskId);
RemoveFromQueue(pausedQueue_, taskId);
RemoveFromQueue(completedQueue_, taskId);
taskMap_.erase(it);
RemoveFromQueue(pendingQueue_, taskId);
RemoveFromQueue(pausedQueue_, taskId);
}
return result;
}
@@ -222,24 +234,20 @@ uint32_t DownloadServiceManager::GetCurrentTaskId()
DownloadServiceManager::QueueType DownloadServiceManager::DecideQueueType(DownloadStatus status)
{
switch (status) {
case SESSION_PENDING:
case SESSION_RUNNING:
return QueueType::NONE_QUEUE;
case SESSION_SUCCESS:
return QueueType::COMPLETED_QUEUE;
case SESSION_PAUSED:
return QueueType::PAUSED_QUEUE;
case SESSION_FAILED:
case SESSION_UNKNOWN:
return QueueType::PENDING_QUEUE;
case SESSION_PENDING:
case SESSION_RUNNING:
case SESSION_SUCCESS:
case SESSION_FAILED:
default:
return QueueType::PENDING_QUEUE;
return QueueType::NONE_QUEUE;
}
return QueueType::PENDING_QUEUE;
return QueueType::NONE_QUEUE;
}
void DownloadServiceManager::MoveTaskToQueue(uint32_t taskId, std::shared_ptr<DownloadServiceTask> task)
@@ -248,28 +256,20 @@ void DownloadServiceManager::MoveTaskToQueue(uint32_t taskId, std::shared_ptr<Do
ErrorCode code;
PausedReason reason;
task->GetRunResult(status, code, reason);
DOWNLOAD_HILOGD("Status [%{public}d], Code [%{public}d], Reason [%{public}d]", status, code, reason);
switch (DecideQueueType(status)) {
case QueueType::PENDING_QUEUE: {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
RemoveFromQueue(pausedQueue_, taskId);
RemoveFromQueue(completedQueue_, taskId);
PushQueue(pendingQueue_, taskId);
break;
}
case QueueType::PAUSED_QUEUE: {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
RemoveFromQueue(pendingQueue_, taskId);
RemoveFromQueue(completedQueue_, taskId);
PushQueue(pausedQueue_, taskId);
break;
}
case QueueType::COMPLETED_QUEUE: {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
RemoveFromQueue(pendingQueue_, taskId);
RemoveFromQueue(pausedQueue_, taskId);
PushQueue(completedQueue_, taskId);
break;
}
}
case QueueType::NONE_QUEUE:
default:
break;
@@ -279,6 +279,10 @@ void DownloadServiceManager::MoveTaskToQueue(uint32_t taskId, std::shared_ptr<Do
void DownloadServiceManager::PushQueue(std::queue<uint32_t> &queue, uint32_t taskId)
{
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
if (taskMap_.find(taskId) == taskMap_.end()) {
DOWNLOAD_HILOGD("invalid task id [%{public}d]", taskId);
return;
}
bool foundIt = false;
if (queue.size() > 0) {
uint32_t indicatorId = queue.front();
@@ -318,4 +322,74 @@ uint32_t DownloadServiceManager::GetInterval() const
{
return interval_;
}
bool DownloadServiceManager::GetNetworkStatus()
{
bool isOnline = false;
std::unique_ptr<CURL, decltype(&curl_easy_cleanup)> handle(curl_easy_init(), curl_easy_cleanup);
if (!handle) {
DOWNLOAD_HILOGD("Failed to create network monitor task");
return false;
}
std::string example = "www.example.com";
curl_easy_setopt(handle.get(), CURLOPT_URL, example.c_str());
CURLcode code = curl_easy_perform(handle.get());
if (code == CURLE_OK) {
DOWNLOAD_HILOGD("Network status is online");
isOnline = true;
}
return isOnline;
}
void DownloadServiceManager::ResumeTaskByNetwork()
{
int taskCount = 0;
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
if (pausedQueue_.size() > 0) {
size_t size = pausedQueue_.size();
while (size-- > 0) {
uint32_t taskId = pausedQueue_.front();
if (taskMap_.find(taskId) != taskMap_.end()) {
pausedQueue_.pop();
auto task = taskMap_[taskId];
DownloadStatus status;
ErrorCode code;
PausedReason reason;
task->GetRunResult(status, code, reason);
if (reason != PAUSED_BY_USER) {
task->Resume();
PushQueue(pendingQueue_, taskId);
taskCount++;
} else {
pausedQueue_.push(taskId);
}
}
}
}
DOWNLOAD_HILOGD("[%{public}d] task has been resumed by network status changed", taskCount);
}
void DownloadServiceManager::MonitorNetwork(DownloadServiceManager *thisVal)
{
bool isOnline = true;
bool currentStatus = true;
while (thisVal->initialized_) {
currentStatus = thisVal->GetNetworkStatus();
if (!isOnline && currentStatus) {
// offline --> online
if (thisVal) {
thisVal->ResumeTaskByNetwork();
}
}
isOnline = currentStatus;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
std::this_thread::yield();
}
}
} // namespace OHOS::Request::Download
@@ -15,7 +15,7 @@
#include "download_service_stub.h"
#include "ipc_skeleton.h"
#include "parcel.h"
#include "message_parcel.h"
#include "download_common.h"
#include "download_service_interface.h"
#include "log.h"
@@ -62,10 +62,14 @@ int32_t DownloadServiceStub::OnRemoteRequest(
return E_DOWNLOAD_OK;
}
bool DownloadServiceStub::OnRequest(Parcel &data, Parcel &reply)
bool DownloadServiceStub::OnRequest(MessageParcel &data, MessageParcel &reply)
{
DOWNLOAD_HILOGD("Receive request");
DownloadConfig config;
int32_t fd = data.ReadFileDescriptor();
DOWNLOAD_HILOGI("Get FD from client, fd [%{public}d]", fd);
config.SetFD(fd);
config.SetFDError(data.ReadInt32());
config.SetUrl(data.ReadString());
config.SetMetered(data.ReadBool());
config.SetRoaming(data.ReadBool());
@@ -88,7 +92,7 @@ bool DownloadServiceStub::OnRequest(Parcel &data, Parcel &reply)
return true;
}
bool DownloadServiceStub::OnPause(Parcel &data, Parcel &reply)
bool DownloadServiceStub::OnPause(MessageParcel &data, MessageParcel &reply)
{
bool result = Pause(data.ReadUint32());
if (!reply.WriteBool(result)) {
@@ -98,7 +102,7 @@ bool DownloadServiceStub::OnPause(Parcel &data, Parcel &reply)
return true;
}
bool DownloadServiceStub::OnQuery(Parcel &data, Parcel &reply)
bool DownloadServiceStub::OnQuery(MessageParcel &data, MessageParcel &reply)
{
DownloadInfo info;
bool result = Query(data.ReadUint32(), info);
+216 -64
View File
@@ -16,6 +16,9 @@
#include "download_service_task.h"
#include <algorithm>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include "constant.h"
#include "log.h"
@@ -23,7 +26,7 @@ namespace OHOS::Request::Download {
DownloadServiceTask::DownloadServiceTask(uint32_t taskId, const DownloadConfig &config)
: taskId_(taskId), config_(config), status_(SESSION_UNKNOWN), code_(ERROR_UNKNOWN), reason_(PAUSED_UNKNOWN),
mimeType_(""), file_(nullptr), totalSize_(0), downloadSize_(0), isPartialMode_(false), forceStop_(false),
isRemoved_(false), retryTime_(10), eventCb_(nullptr) {
isRemoved_(false), retryTime_(10), eventCb_(nullptr), hasFileSize_(false), isOnline_(true), prevSize_(0) {
}
DownloadServiceTask::~DownloadServiceTask(void)
@@ -33,6 +36,10 @@ DownloadServiceTask::~DownloadServiceTask(void)
fflush(file_);
fclose(file_);
}
if (config_.GetFD() > 0) {
close(config_.GetFD());
config_.SetFD(-1);
}
}
uint32_t DownloadServiceTask::GetId() const
@@ -43,59 +50,70 @@ uint32_t DownloadServiceTask::GetId() const
bool DownloadServiceTask::Run()
{
DOWNLOAD_HILOGD("Task[%{public}d] start.", taskId_);
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
if (!GetFileSize(totalSize_)) {
SetStatus(SESSION_PENDING, ERROR_UNKNOWN, reason_);
if (HandleFileError()) {
return false;
}
uint32_t retryTime = 0;
bool result = true;
bool enableTimeout;
bool result = false;
bool enableTimeout = false;
SetStatus(SESSION_RUNNING);
do {
enableTimeout = false;
SetStatus(SESSION_RUNNING);
result = ExecHttp();
if (status_ != SESSION_RUNNING && status_ != SESSION_PENDING) {
break;
}
if (GetFileSize(totalSize_)) {
result = ExecHttp();
}
DumpStatus();
DumpErrorCode();
DumpPausedReason();
// HTTP timeout occurs, retry
if (status_ == SESSION_PENDING) {
enableTimeout = true;
retryTime++;
}
} while (!result && enableTimeout && retryTime < retryTime_);
if (retryTime >= retryTime_) {
SetStatus(SESSION_PAUSED, ERROR_UNKNOWN, PAUSED_WAITING_TO_RETRY);
}
return result;
}
bool DownloadServiceTask::Pause()
{
DOWNLOAD_HILOGD("Pause Task[%{public}d], current status is %{public}d\n", taskId_, status_);
DOWNLOAD_HILOGD("Status [%{public}d], Code [%{public}d], Reason [%{public}d]", status_, code_, reason_);
if (status_ != SESSION_RUNNING && status_ != SESSION_PENDING) {
return false;
}
ForceStopRunning();
SetStatus(SESSION_PAUSED);
SetStatus(SESSION_PAUSED, ERROR_UNKNOWN, PAUSED_BY_USER);
return true;
}
bool DownloadServiceTask::Resume()
{
DOWNLOAD_HILOGD("Resume Task[%{public}d], current status is %{public}d\n", taskId_, status_);
if (status_ != SESSION_PAUSED) {
return false;
}
ForceStopRunning();
if (!CheckResumeCondition()) {
SetStatus(SESSION_FAILED, ERROR_CANNOT_RESUME, reason_);
DOWNLOAD_HILOGD("Status [%{public}d], Code [%{public}d], Reason [%{public}d]", status_, code_, reason_);
if (status_ == SESSION_PAUSED || (status_ == SESSION_FAILED && code_ == ERROR_CANNOT_RESUME)) {
forceStop_ = false;
if (!CheckResumeCondition()) {
SetStatus(SESSION_FAILED, ERROR_CANNOT_RESUME, PAUSED_UNKNOWN);
} else {
// reset status
SetStatus(SESSION_UNKNOWN, ERROR_UNKNOWN, PAUSED_UNKNOWN);
}
return true;
}
SetStatus(SESSION_UNKNOWN, code_, reason_);
return true;
return false;
}
bool DownloadServiceTask::Remove()
{
DOWNLOAD_HILOGD("Remove Task[%{public}d], current status is %{public}d\n", taskId_, status_);
DOWNLOAD_HILOGD("Status [%{public}d], Code [%{public}d], Reason [%{public}d]", status_, code_, reason_);
isRemoved_ = true;
ForceStopRunning();
if (eventCb_ != nullptr) {
@@ -147,11 +165,19 @@ void DownloadServiceTask::SetRetryTime(uint32_t retryTime)
retryTime_ = retryTime;
}
void DownloadServiceTask::SetNetworkStatus(bool isOnline)
{
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
isOnline_ = isOnline;
if (status_ == SESSION_PAUSED && reason_ == PAUSED_WAITING_TO_RETRY && !isOnline_) {
reason_ = PAUSED_WAITING_FOR_NETWORK;
}
}
void DownloadServiceTask::SetStatus(DownloadStatus status, ErrorCode code, PausedReason reason)
{
auto stateChange = [this](DownloadStatus status, ErrorCode code, PausedReason reason) -> bool {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
this->forceStop_ = false;
bool isChanged = false;
if (status != this->status_) {
this->status_ = status;
@@ -161,16 +187,24 @@ void DownloadServiceTask::SetStatus(DownloadStatus status, ErrorCode code, Pause
this->code_ = code;
isChanged = true;
}
if (reason != this->reason_) {
this->reason_ = reason;
isChanged = true;
if (this->reason_ != PAUSED_BY_USER) {
if (!isOnline_ && reason == PAUSED_WAITING_TO_RETRY) {
reason = PAUSED_WAITING_FOR_NETWORK;
}
if (reason != this->reason_) {
this->reason_ = reason;
isChanged = true;
}
}
return true;
};
DOWNLOAD_HILOGD("Status [%{public}d], Code [%{public}d], Reason [%{public}d]", status, code, reason);
if (!stateChange(status, code, reason)) {
return;
}
if (eventCb_ != nullptr) {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
switch (status_) {
case SESSION_SUCCESS:
eventCb_("complete", taskId_, 0, 0);
@@ -194,7 +228,6 @@ void DownloadServiceTask::SetStatus(DownloadStatus status)
{
auto stateChange = [this](DownloadStatus status) -> bool {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
this->forceStop_ = false;
if (status == this->status_) {
DOWNLOAD_HILOGD("ignore same status");
return false;
@@ -202,10 +235,12 @@ void DownloadServiceTask::SetStatus(DownloadStatus status)
this->status_ = status;
return true;
};
DOWNLOAD_HILOGD("Status [%{public}d]", status);
if (!stateChange(status)) {
return;
}
if (eventCb_ != nullptr) {
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
switch (status_) {
case SESSION_SUCCESS:
eventCb_("complete", taskId_, 0, 0);
@@ -227,8 +262,8 @@ void DownloadServiceTask::SetStatus(DownloadStatus status)
void DownloadServiceTask::SetError(ErrorCode code)
{
DOWNLOAD_HILOGD("Code [%{public}d]", code);
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
this->forceStop_ = false;
if (code == code_) {
DOWNLOAD_HILOGD("ignore same error code");
return;
@@ -238,13 +273,19 @@ void DownloadServiceTask::SetError(ErrorCode code)
void DownloadServiceTask::SetReason(PausedReason reason)
{
DOWNLOAD_HILOGD("Reason [%{public}d]", reason);
std::lock_guard<std::recursive_mutex> autoLock(mutex_);
this->forceStop_ = false;
if (reason == reason_) {
DOWNLOAD_HILOGD("ignore same paused reason");
return;
}
reason_ = reason;
if (reason_ != PAUSED_BY_USER) {
if (!isOnline_ && reason == PAUSED_WAITING_TO_RETRY) {
reason = PAUSED_WAITING_FOR_NETWORK;
}
if (reason == reason_) {
DOWNLOAD_HILOGD("ignore same paused reason");
return;
}
reason_ = reason;
}
}
void DownloadServiceTask::DumpStatus()
@@ -358,8 +399,11 @@ size_t DownloadServiceTask::WriteCallback(void *buffer, size_t size, size_t num,
{
size_t result = 0;
DownloadServiceTask *this_ = static_cast<DownloadServiceTask *>(param);
if (this_ != nullptr && this_->file_) {
result = fwrite(buffer, size, num, this_->file_);
if (this_ != nullptr && this_->config_.GetFD() > 0) {
result = write(this_->config_.GetFD(), buffer, size * num);
if (result < size * num) {
DOWNLOAD_HILOGE("origin size = %{pulic}d, write size = %{pulic}d", size * num, result);
}
this_->downloadSize_ += static_cast<uint32_t>(result);
}
return result;
@@ -384,12 +428,18 @@ int DownloadServiceTask::ProgressCallback(void *pParam, double dltotal, double d
if (this_->isRemoved_) {
DOWNLOAD_HILOGD("download task has been removed\n");
}
if (this_->eventCb_ != nullptr && !this_->isRemoved_) {
this_->eventCb_("progress", this_->taskId_, this_->downloadSize_, this_->totalSize_);
}
if (this_->forceStop_) {
DOWNLOAD_HILOGD("Pause issued by user\n");
return HTTP_FORCE_STOP;
}
if (this_->eventCb_ != nullptr && !this_->isRemoved_) {
if (this_->prevSize_ != this_->downloadSize_) {
std::lock_guard<std::recursive_mutex> autoLock(this_->mutex_);
if (this_->status_ != SESSION_PAUSED) {
this_->eventCb_("progress", this_->taskId_, this_->downloadSize_, this_->totalSize_);
this_->prevSize_ = this_->downloadSize_;
}
}
}
// calc the download speed
}
@@ -418,29 +468,29 @@ bool DownloadServiceTask::ExecHttp()
DOWNLOAD_HILOGD("set option failed");
return false;
}
std::string tmpFileName = GetTmpPath().c_str();
file_ = fopen(tmpFileName.c_str(), "ab");
if (file_ != nullptr) {
DOWNLOAD_HILOGD("Succeed to open %{public}s", tmpFileName.c_str());
fseek(file_, 0, SEEK_END);
uint32_t pos = ftell(file_);
if (config_.GetFD() > 0) {
DOWNLOAD_HILOGD("Succeed to open %{public}s", config_.GetFilePath().c_str());
uint64_t pos = lseek(config_.GetFD(), 0, SEEK_END);
downloadSize_ = 0;
if (pos > 0) {
if (pos < totalSize_) {
isPartialMode_ = true;
downloadSize_ = static_cast<uint32_t>(pos);
SetResumeFromLarge(handle.get(), pos);
} else if (pos == totalSize_) {
} else if (pos >= totalSize_) {
downloadSize_ = totalSize_;
DOWNLOAD_HILOGD("Download task has already completed");
SetStatus(SESSION_SUCCESS);
return true;
} else {
DOWNLOAD_HILOGD("Download size exceed the file size, re-download it");
fclose(file_);
file_ = fopen(tmpFileName.c_str(), "wb");
return false;
}
}
prevSize_ = downloadSize_;
} else {
DOWNLOAD_HILOGD("Failed to open %{public}s", tmpFileName.c_str());
DOWNLOAD_HILOGD("Failed to open %{public}s", config_.GetFilePath().c_str());
}
CURLcode code = curl_easy_perform(handle.get());
@@ -456,6 +506,51 @@ bool DownloadServiceTask::ExecHttp()
return code == CURLE_OK;
}
bool DownloadServiceTask::SetFileSizeOption(CURL *curl, struct curl_slist *requestHeader)
{
curl_easy_setopt(curl, CURLOPT_URL, config_.GetUrl().c_str());
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, HeaderCallback);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, this);
if (requestHeader != nullptr) {
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, requestHeader);
}
// Some servers don't like requests that are made without a user-agent field, so we provide one
curl_easy_setopt(curl, CURLOPT_USERAGENT, HTTP_DEFAULT_USER_AGENT);
#if 1
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
/* first #undef CURL_DISABLE_COOKIES in curl config */
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "");
#ifdef DOWNLOAD_USE_PROXY
curl_easy_setopt(curl, CURLOPT_PROXY, HTTP_PROXY_URL_PORT);
curl_easy_setopt(curl, CURLOPT_PROXYTYPE, HTTP_PROXY_TYPE);
curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
#ifdef DOWNLOAD_PROXY_PASS
curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, HTTP_PROXY_PASS);
#endif // DOWNLOAD_PROXY_PASS
#endif // DOWNLOAD_USE_PROXY
#ifdef DOWNLOAD_SSL_CERTIFICATION
curl_easy_setopt(curl, CURLOPT_CAINFO, HTTP_DEFAULT_CA_PATH);
#else
// NO_SSL_CERTIFICATION
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
#endif
curl_easy_setopt(curl, CURLOPT_NOSIGNAL, 1L);
#if HTTP_CURL_PRINT_VERBOSE
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L, context);
#endif
curl_easy_setopt(curl, CURLOPT_TIMEOUT, DEFAULT_READ_TIMEOUT);
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, DEFAULT_CONNECT_TIMEOUT);
#endif
return true;
}
bool DownloadServiceTask::SetOption(CURL *curl, struct curl_slist *requestHeader)
{
curl_easy_setopt(curl, CURLOPT_URL, config_.GetUrl().c_str());
@@ -525,7 +620,7 @@ void DownloadServiceTask::SetResumeFromLarge(CURL *curl, long long pos)
bool DownloadServiceTask::GetFileSize(uint32_t &result)
{
if (totalSize_) {
if (hasFileSize_) {
DOWNLOAD_HILOGD("Already get file size");
return true;
}
@@ -544,23 +639,30 @@ bool DownloadServiceTask::GetFileSize(uint32_t &result)
});
std::unique_ptr<struct curl_slist, decltype(&curl_slist_free_all)> header(MakeHeaders(vec), curl_slist_free_all);
if (!SetOption(handle.get(), header.get())) {
if (!SetFileSizeOption(handle.get(), header.get())) {
DOWNLOAD_HILOGD("set option failed");
return false;
}
curl_easy_setopt(handle.get(), CURLOPT_NOBODY, 1L);
CURLcode res;
curl_easy_perform(handle.get());
res = curl_easy_getinfo(handle.get(), CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size);
if (res == CURLE_OK) {
CURLcode code = curl_easy_perform(handle.get());
curl_easy_getinfo(handle.get(), CURLINFO_CONTENT_LENGTH_DOWNLOAD, &size);
if (code == CURLE_OK) {
result = static_cast<long long>(size);
if (result == static_cast<uint32_t>(-1)) {
result = 0;
}
hasFileSize_ = true;
DOWNLOAD_HILOGD("Has got file size");
} else {
if (status_ == SESSION_RUNNING || status_ == SESSION_PENDING) {
SetStatus(SESSION_PENDING, ERROR_UNKNOWN, PAUSED_UNKNOWN);
}
}
if (result == -1) {
result = 0;
}
DOWNLOAD_HILOGD("fetch file size %{public}d", result);
return true;
return hasFileSize_;
}
std::string DownloadServiceTask::GetTmpPath()
@@ -574,22 +676,41 @@ void DownloadServiceTask::HandleResponseCode(CURLcode code, int32_t httpCode)
DOWNLOAD_HILOGD("download task has been removed");
return;
}
DOWNLOAD_HILOGD("Current CURLcode is %{public}d, httpCode is %{public}d\n", code, httpCode);
if (status_ == SESSION_PAUSED && reason_ == PAUSED_BY_USER) {
DOWNLOAD_HILOGD("Pause By User:ignore status changed caused by libcurl");
return;
}
switch (code) {
case CURLE_OK:
if (httpCode == HTTP_OK || (isPartialMode_ && httpCode == HTTP_PARIAL_FILE)) {
SetStatus(SESSION_SUCCESS);
return;
}
break;
case CURLE_ABORTED_BY_CALLBACK:
if (httpCode == HTTP_OK || (isPartialMode_ && httpCode == HTTP_PARIAL_FILE)) {
SetStatus(SESSION_PAUSED, code_, PAUSED_BY_USER);
SetStatus(SESSION_PAUSED, ERROR_UNKNOWN, PAUSED_BY_USER);
return;
}
break;
case CURLE_WRITE_ERROR:
if (httpCode == HTTP_OK || (isPartialMode_ && httpCode == HTTP_PARIAL_FILE)) {
SetStatus(SESSION_FAILED, ERROR_HTTP_DATA_ERROR, PAUSED_UNKNOWN);
return;
}
break;
case CURLE_TOO_MANY_REDIRECTS:
SetStatus(SESSION_FAILED, ERROR_TOO_MANY_REDIRECTS, reason_);
SetStatus(SESSION_FAILED, ERROR_TOO_MANY_REDIRECTS, PAUSED_UNKNOWN);
return;
case CURLE_COULDNT_RESOLVE_PROXY:
case CURLE_COULDNT_RESOLVE_HOST:
case CURLE_COULDNT_CONNECT:
case CURLE_OPERATION_TIMEDOUT:
SetStatus(SESSION_PENDING);
return;
@@ -597,13 +718,14 @@ void DownloadServiceTask::HandleResponseCode(CURLcode code, int32_t httpCode)
default:
break;
}
DOWNLOAD_HILOGD("Current CURLcode is %{public}d, httpCode is %{public}d\n", code, httpCode);
SetStatus(SESSION_FAILED, ERROR_UNHANDLED_HTTP_CODE, reason_);
SetStatus(SESSION_FAILED, ERROR_UNHANDLED_HTTP_CODE, PAUSED_UNKNOWN);
}
bool DownloadServiceTask::CheckResumeCondition()
{
// current paused issued by user
if (!isOnline_) {
return false;
}
return true;
}
@@ -611,12 +733,16 @@ void DownloadServiceTask::ForceStopRunning()
{
forceStop_ = true;
}
void DownloadServiceTask::HandleCleanup(DownloadStatus status)
{
switch (status) {
case SESSION_SUCCESS:
// rename download to target file name
rename(GetTmpPath().c_str(), config_.GetFilePath().c_str());
if (config_.GetFD() > 0) {
close(config_.GetFD());
config_.SetFD(-1);
}
break;
case SESSION_FAILED:
@@ -626,4 +752,30 @@ void DownloadServiceTask::HandleCleanup(DownloadStatus status)
break;
}
}
bool DownloadServiceTask::HandleFileError()
{
ErrorCode code = ERROR_UNKNOWN;
if (config_.GetFD() < 0) {
switch (config_.GetFDError()) {
case 0:
DOWNLOAD_HILOGD("File [%{public}s] already exists", config_.GetFilePath().c_str());
code = ERROR_FILE_ALREADY_EXISTS;
break;
case ENODEV:
code = ERROR_DEVICE_NOT_FOUND;
break;
default:
code = ERROR_FILE_ERROR;
break;
}
SetStatus(SESSION_FAILED, code, PAUSED_UNKNOWN);
return true;
}
return false;
}
} // namespace OHOS::Request::Download
@@ -40,6 +40,7 @@ static napi_value paused_queue_wifi = nullptr;
static napi_value paused_for_network = nullptr;
static napi_value paused_to_retry = nullptr;
static napi_value paused_by_user = nullptr;
static napi_value paused_unknown = nullptr;
static napi_value session_success = nullptr;
static napi_value session_running = nullptr;
static napi_value session_pending = nullptr;
@@ -68,6 +69,7 @@ static napi_value Init(napi_env env, napi_value exports)
napi_create_int32(env, static_cast<int32_t>(PAUSED_WAITING_FOR_NETWORK), &paused_for_network);
napi_create_int32(env, static_cast<int32_t>(PAUSED_WAITING_TO_RETRY), &paused_to_retry);
napi_create_int32(env, static_cast<int32_t>(PAUSED_BY_USER), &paused_by_user);
napi_create_int32(env, static_cast<int32_t>(PAUSED_UNKNOWN), &paused_unknown);
/* Create session status Const */
napi_create_int32(env, static_cast<int32_t>(SESSION_SUCCESS), &session_success);
@@ -94,8 +96,9 @@ static napi_value Init(napi_env env, napi_value exports)
DECLARE_NAPI_STATIC_PROPERTY("PAUSED_WAITING_FOR_NETWORK", paused_for_network),
DECLARE_NAPI_STATIC_PROPERTY("PAUSED_WAITING_TO_RETRY", paused_to_retry),
DECLARE_NAPI_STATIC_PROPERTY("PAUSED_BY_USER", paused_by_user),
DECLARE_NAPI_STATIC_PROPERTY("PAUSED_UNKNOWN", paused_unknown),
DECLARE_NAPI_STATIC_PROPERTY("SESSION_SUCCESS", session_success),
DECLARE_NAPI_STATIC_PROPERTY("SESSION_SUCCESSFUL", session_success),
DECLARE_NAPI_STATIC_PROPERTY("SESSION_RUNNING", session_running),
DECLARE_NAPI_STATIC_PROPERTY("SESSION_PENDING", session_pending),
DECLARE_NAPI_STATIC_PROPERTY("SESSION_PAUSED", session_paused),